Loading...
Loading...
Compare original and translation side by side
NO PROCESS WITHOUT A RUNTIME REASONNO PROCESS WITHOUT A RUNTIME REASON| OOP Dimension | Elixir Equivalent |
|---|---|
| Behavior | Modules (functions) |
| State | Data (structs, maps) |
| Mutability | Processes (GenServer) |
| OOP维度 | Elixir对应项 |
|---|---|
| 行为 | 模块(函数) |
| 状态 | 数据(结构体、映射) |
| 可变性 | 进程(GenServer) |
{:ok, _}{:error, _}{:ok, _}{:error, _}if/elsecase%{}map_size(map) == 0casecasewith{:ok, result}{:error, reason}with{:ok, _}{:error, _}_ -> nilvalue && value.field{:ok, nil} -> nil{:ok, value} -> value.fieldwithundefinedif/elsecase%{}map_size(map) == 0casecasewith{:ok, result}{:error, reason}with{:ok, _}{:error, _}_ -> nilvalue && value.field{:ok, nil} -> nil{:ok, value} -> value.fieldwithundefinedundefinedundefined| For Polymorphism Over... | Use | Contract |
|---|---|---|
| Modules | Behaviors | Upfront callbacks |
| Data | Protocols | Upfront implementations |
| Processes | Message passing | Implicit (send/receive) |
| 针对...的多态性 | 使用方式 | 约定 |
|---|---|---|
| 模块 | Behaviors | 预先定义回调 |
| 数据 | Protocols | 预先实现 |
| 进程 | 消息传递 | 隐式(send/receive) |
{:sequence, {:literal, "rain"}, {:repeat, {:alternation, "dogs", "cats"}}}
def interpret({:literal, text}, input), do: ...
def interpret({:sequence, left, right}, input), do: ...
def interpret({:repeat, pattern}, input), do: ...{:sequence, {:literal, "rain"}, {:repeat, {:alternation, "dogs", "cats"}}}
def interpret({:literal, text}, input), do: ...
def interpret({:sequence, left, right}, input), do: ...
def interpret({:repeat, pattern}, input), do: .../3Keyword.get/3Map.get/3nilundefined/3Keyword.get/3Map.get/3nilundefined
Don't create helper functions to merge config defaults. Inline the fallback:
```elixir
不要创建辅助函数来合并配置默认值。直接内联回退逻辑:
```elixirundefinedundefinedis_thingdefstruct [:name, :age][new | list]list ++ [new]dbg/1JSONis_thingdefstruct [:name, :age][new | list]list ++ [new]dbg/1JSONasync: false| Problem | Solution |
|---|---|
| Pass config as function argument |
| Feature flags | Inject via process dictionary or context |
| ETS tables | Create per-test tables with unique names |
| External APIs | Use Mox with explicit allowances |
| File system operations | Use |
tmp_dir@tag :tmp_dir
test "writes file", %{tmp_dir: tmp_dir} do
path = Path.join(tmp_dir, "test.txt")
File.write!(path, "content")
assert File.read!(path) == "content"
end@moduletag :tmp_dirasync: false| 问题 | 解决方案 |
|---|---|
| 将配置作为函数参数传递 |
| 功能开关 | 通过进程字典或上下文注入 |
| ETS表 | 创建每个测试独有的表,使用唯一名称 |
| 外部API | 使用Mox并显式设置允许列表 |
| 文件系统操作 | 使用 |
tmp_dir@tag :tmp_dir
test "writes file", %{tmp_dir: tmp_dir} do
path = Path.join(tmp_dir, "test.txt")
File.write!(path, "content")
assert File.read!(path) == "content"
end@moduletag :tmp_dir| Excuse | Reality |
|---|---|
| "I need a process to organize this code" | Modules organize code. Processes are for runtime. |
| "GenServer is the Elixir way" | Plain functions are also the Elixir way. |
| "I'll need state eventually" | YAGNI. Add process when you need it. |
| "It's just a simple wrapper process" | Simple wrappers become bottlenecks. |
| "This is how I'd structure it in OOP" | Rethink from data flow. |
| 借口 | 真相 |
|---|---|
| “我需要一个进程来组织这段代码” | 模块用于组织代码。进程是为运行时服务的。 |
| “GenServer是Elixir的标准写法” | 纯函数同样是Elixir的标准写法。 |
| “我最终会需要状态的” | YAGNI(你不会用到它)。需要时再添加进程。 |
| “这只是一个简单的进程包装器” | 简单的包装器也可能成为性能瓶颈。 |
| “我在OOP里就是这么组织的” | 从数据流的角度重新思考。 |