mcpField
E
elixir-idioms

elixir-idioms

github.com/oliver-kriska开发57148 次安装1 周前更新
代码仓库

关于 elixir-idioms

elixir-idioms 是编写符合 Elixir 惯用法代码的参考技能,强调适用于 BEAM 的模式。它通过规则、决策指南和示例讲解控制流、错误处理、进程与 OTP。

主要功能

  1. 01运用模式匹配与管道操作符
  2. 02选择错误处理约定
  3. 03挑选进程和 OTP 组件
  4. 04规避常见 Elixir 陷阱
  5. 05查阅主题明确的参考指南

适用场景

  1. 01检查 Elixir 代码是否符合惯用模式
  2. 02在函数、Agent、GenServer 和 Task 间选择
  3. 03处理预期与意外错误
  4. 04设计受监督的长生命周期进程

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/oliver-kriska/claude-elixir-phoenix --skill elixir-idioms

安装后在 Claude Code 中输入/elixir-idioms确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
anti-patterns.md
elixir-118-features.md
elixir-120-type-system.md
error-handling.md
mix-tasks.md
otp-patterns.md
pattern-matching.md
troubleshooting.md
with-and-pipes.md

详细介绍

Elixir 惯用法

编写符合 Elixir 惯用风格代码的参考指南,采用适配 BEAM 的模式。

铁律——绝不违反

  1. 没有运行时理由就不要创建进程——进程用于建模并发、状态和隔离,而不是代码结构
  2. 消息会被复制(64 字节以上的二进制数据除外)——保持消息精简
  3. 守卫中使用 and/or/not——守卫中绝不使用短路运算符(守卫要求操作数为布尔值)
  4. 外部数据使用变更集——用户输入使用 cast/4,内部数据使用 change/2
  5. 仅对外部代码使用 rescue——绝不使用 rescue 控制流程
  6. 不要动态创建原子——String.to_atom(user_input) 会导致内存泄漏(原子不会被垃圾回收)
  7. 编译时读取的文件使用 @external_resource——在编译时读取文件的模块必须声明 @external_resource
  8. 监督所有长生命周期进程——生产环境中绝不直接调用 GenServer.start_link/Agent.start_link。使用监督树
  9. 封装第三方库 API——始终通过项目自有模块门面封装外部依赖。这样无需修改调用方即可替换依赖
  10. Mix 任务只启动所需内容——使用 Mix.Task.run("app.config") + Application.ensure_all_started/1,绝不使用 Mix.Task.run("app.start")(它会启动完整的树:端点端口、Oban 消费任务)
  11. 启动进程前捕获区域设置——Gettext/CLDR 的区域设置是进程本地的。在调用方读取并显式传递;新启动的 Task/GenServer 会使用默认区域设置

BEAM 架构(Elixir 采用此设计的原因)

  • 进程开销低(2.6KB)——可大量创建进程以实现并发/隔离
  • 完全的内存隔离——没有共享状态,无需锁
  • 消息会被复制(64 字节以上的二进制数据除外)——保持消息精简
  • 每进程垃圾回收——不会发生全局垃圾回收暂停
  • “让它崩溃”——监督者会将其重启到已知的良好状态

核心原则

  1. 优先使用模式匹配,而非条件判断——先用函数头,再用 case,最后用 cond
  2. 预期失败使用带标签的元组——预期错误使用 {:ok, _}/{:error, _},程序错误则抛出异常
  3. 使用管道运算符转换数据——从数据开始,绝不对单次调用使用管道
  4. 让它崩溃——处理预期错误,遇到意外错误则崩溃
  5. 明确胜于隐式——清楚表达意图

快速决策树

控制流程
Need patterns? → case (or function heads)
Multiple operations? → with
Boolean conditions? → cond (multiple) or if (single)
错误处理
Expected failure? → {:ok, _}/{:error, _} tuples
Unexpected/bug? → raise exception (let supervisor handle)
External library? → rescue (only here!)
OTP
Need state?
├─ No → Plain functions
├─ Simple get/update → Agent or ETS
├─ Complex messages/timeouts → GenServer
└─ One-off async → Task

快速模式

# Pattern match in function head
def process(%{status: :active} = user), do: activate(user)
def process(%{status: :inactive} = user), do: deactivate(user)

# with for happy path
with {:ok, user} <- get_user(id),
     {:ok, order} <- create_order(user) do
  {:ok, order}
end

# Task for async
Task.Supervisor.async_nolink(TaskSup, fn -> work() end)
|> Task.yield(5000) || Task.shutdown(task)

常见陷阱

错误正确
length(list) == 0list == [] 或 Enum.empty?(list)
list ++ [item][item | list] |> Enum.reverse()
String.to_atom(input)String.to_existing_atom(input)
spawn(fn -> log(conn) end)ip = conn.ip; spawn(fn -> log(ip) end)
unless conditionif !condition(除非使用 1.18 中已弃用的 unless)

参考资料

如需了解详细模式,请参阅:

  • ${CLAUDE_SKILL_DIR}/references/pattern-matching.md - 模式匹配、守卫、二进制匹配
  • ${CLAUDE_SKILL_DIR}/references/otp-patterns.md - GenServer、Supervisor、Task、Registry
  • ${CLAUDE_SKILL_DIR}/references/error-handling.md - 带标签的元组、rescue、with
  • ${CLAUDE_SKILL_DIR}/references/with-and-pipes.md - 何时使用 with 和 |>(惯用模式)
  • ${CLAUDE_SKILL_DIR}/references/troubleshooting.md - 生产环境 BEAM 调试(内存、性能、崩溃)
  • ${CLAUDE_SKILL_DIR}/references/anti-patterns.md - 常见错误及修正方法
  • ${CLAUDE_SKILL_DIR}/references/mix-tasks.md - Mix 任务命名、选项解析、Shell 输出
  • ${CLAUDE_SKILL_DIR}/references/elixir-118-features.md - Duration 模块、dbg 改进(1.18+)
  • ${CLAUDE_SKILL_DIR}/references/elixir-120-type-system.md - 渐进式类型检查器、dynamic()、将已验证的错误作为编译警告(1.20+、OTP 27+)

评论

支持 Markdown