Extensions
· · ·
题目进度 0 / 0 ✓ 0
Elixir 扩展地图 / Extension Radar
目标:覆盖”如果你要真正精通 Elixir / 读懂 Phoenix/LiveView/Nerves 这类重 Elixir 项目”需要知道的所有点。
这不是速通。每个点只点一下”是什么 / 为什么重要 / 学到什么程度 / 影响哪些代码”。有兴趣的深挖。
阅读方式
- 🟢 = 速通课已覆盖(不需要再学)
- 🟡 = 推荐花 1-3 天弄懂(有时间就做)
- 🔴 = 进阶 / 1-2 周 / 用到再学(记下入口)
配套扩展文档
读这份”扩展地图”前先知道另几份配套文档:
- extensions-serverless-architecture.md — Elixir + Cloudflare + Vultr “按需起 VM”架构详解(4 个场景 + 成本对比 + 实施步骤 + §9 业务选择框架)
- concepts-vultr-glossary.md — Vultr 专有名词速查(Plan/Region/Snapshot/cloud-init/Firewall/Reserved IP 等)
- extensions-cf-ai-rag.md — Cloudflare Workers AI + Vectorize 零后端 RAG 实战(30 分钟搭起来,$0.50/月)
一、基础语法 & 核心数据结构 🟡
| 主题 | 状态 | 一句话 | 影响代码 |
|---|---|---|---|
| 字面量(数字/atom/string/charlist/tuple/list/map/binary/struct) | 🟢 | 详见 0001 | 全部 |
模式匹配(Pattern matching)+ pin operator ^ | 🟢 | 详见 0001 | 全部 |
函数子句(multi-clause + guard when) | 🟢 | 详见 0001 | 全部 |
管道 |> + 柯里化场景 | 🟢 | 详见 0001 | Enum.reduce / Repo.all 链 |
| 模块(defmodule)+ import/alias/require/use | 🟢 | 详见 0001 | 全部 |
Struct(defstruct + %MyStruct{}) | 🟢 | 详见 0001 | Pipeline.NewsDigest |
| 列表 vs 元组 vs Map vs Keyword List 选型 | 🟡 | List=链表, Tuple=定长 N<10, Map=hashmap, Keyword List=配置参数 | Keyword.get(opts, :dag_name) |
| Binary / Bitstring(位级) | 🟡 | 视频/协议解析必学;UTF-8 默认 | <<a, b, c::16>> 模式匹配 |
with 表达式(monadic 链) | 🟡 | with {:ok, x} <- ..., {:ok, y} <- ... do ... else ... end | 错误处理链 |
捕获运算符 & / 匿名函数 fn ... -> ... end | 🟢 | &String.upcase/1 | 全部 |
列表推导(comprehension)for x <- xs, ... do | 🟡 | 像 SQL WHERE,生成 List / Map | 批量转换 |
| String / String.split / String.replace | 🟡 | Grapheme 概念、Charcodepoint vs Grapheme | String.split("\n", trim: true) |
一·五、构建工具 & 部署 🟡
| 主题 | 状态 | 一句话 | 详见 |
|---|---|---|---|
mix.exs 三段式(project/application/deps) | 🟢 | 详见 lesson 0006 | ex/elixir/mix.exs |
mix new 4 种类型(普通/sup/umbrella/—module) | 🟡 | OTP 项目用 --sup | lesson 0006 |
MIX_ENV 切换(dev/test/prod) | 🟢 | 详见 lesson 0006 | CI 流水线必用 |
mix release 自包含目录 | 🟢 | 详见 lesson 0006 | 按需起 VM 架构的关键 |
runtime.exs vs config.exs(编译时 vs 运行时) | 🟢 | 详见 lesson 0006 | secrets 必须放 runtime.exs |
compile_env vs get_env | 🟡 | compile_env 烧死,get_env 可改 | ex/elixir/feishu_message.ex:5 |
mix format / .formatter.exs | 🟡 | 项目统一代码风格 | CI 必跑 --check-formatted |
mix credo(lint) | 🟡 | 类似 Checkstyle | 推荐装 |
mix dialyzer(静态类型) | 🟡 | 需要 @spec + PLT(首次慢) | 强类型项目装 |
mix.exs aliases(自定义命令组合) | 🟡 | aliases: [test: ["ecto.create --quiet", "test"] | CI 集成用 |
MIX_ENV=prod mix release 配置项(runtime.exs) | 🟢 | 详见 lesson 0006 | 生产部署必配 |
| Hex.pm 私有仓库(公司内部 hex 源) | 🟡 | 自托管 hexpm/hex Docker | 企业级才用 |
二、并发 & OTP 🟡
| 主题 | 状态 | 一句话 | 影响代码 |
|---|---|---|---|
spawn / send / receive | 🟢 | 详见 0002 | 全部并发 |
Process 模块 + link + spawn_link | 🟡 | 单向 vs 双向 link | 异常传播 |
GenServer 完整生命周期 | 🟢 | 详见 0002 | Oban.Worker 内部就是 GenServer |
Agent(状态 + 简单 API) | 🟡 | 缓存场景;Agent.update/2 | 轻量 KV |
Task(一次性 async) | 🟡 | Task.async / Task.await | 并行 IO |
Supervisor + 重启策略(one_for_one 等) | 🟢 | 详见 0002 | Pipeline.Application 监督树 |
Application 回调 / mix.exs 的 mod: | 🟢 | 详见 0002 | Pipeline.Application |
注册进程(:via / :global) | 🔴 | 命名服务发现 | 集群时必须 |
:rpc 跨节点调用 | 🔴 | 多节点 BEAM 集群 | Node.spawn / :rpc.call |
| 节点(Node) | 🔴 | 集群、:net_kernel.start、epmd | 分布式系统 |
| Distributed Erlang 协议 | 🔴 | 跟 Java RMI / gRPC 对位 | 大规模集群 |
进程字典(:erlang.put) | 🔴 | 反模式;只是因为存在 | 几乎不该用 |
进程监控 Process.monitor | 🟡 | 收到 :DOWN 消息 | 临时任务 |
| ETS(Erlang Term Storage) | 🟡 | BEAM 内存表,O(1) 读写,万级并发 | 缓存 / 计数器 |
| DETS(磁盘 ETS) | 🟡 | ETS 持久化版 | 轻量本地存储 |
| :mnesia(分布式 DB) | 🔴 | Erlang 自带分布式 DB | 极少用 |
:persistent_term | 🟡 | 存配置、路由表,读极快但 GC 暂停 | 静态配置 |
Process.flag(:trap_exit, true) | 🟡 | 把 EXIT 转成 message | 自定义清理逻辑 |
三、错误处理 🟡
| 主题 | 状态 | 一句话 | 影响代码 |
|---|---|---|---|
Tagged tuple {:ok, x} / {:error, e} | 🟢 | “Sum type” 的 Elixir 风格 | 全部 API |
with 表达式 | 🟡 | 同上 | 全部 IO 调用 |
try/rescue/catch/after | 🟡 | 异常处理;rescue 捕 RuntimeError 等 | Oban 失败重试 |
throw + catch(非局部跳转) | 🔴 | 极少用;库内部偶见 | 控制流 |
| Erlang/Elixir 哲学:“let it crash” | 🟢 | 不防御性 if,交给 supervisor 重启 | 监督树 |
| Error 模式 vs 抛出异常 | 🟡 | error tuple=预期失败,throw=异常 | 设计 API |
| Logger 配置 / 元数据 / Sentry | 🟡 | Logger.error/1 / Logger.metadata | 生产日志 |
四、Elixir 独有机制 🟡
| 主题 | 状态 | 一句话 | 影响代码 |
|---|---|---|---|
| 协议(Protocol)= 多态 | 🟡 | 详见 0003;为已有类型扩展 dispatch | Phoenix 渲染 / String.Chars |
行为(@behaviour)= 接口 | 🟢 | 详见 0003 | Pipeline.Llm 抽象 Real/Dummy |
宏(defmacro)= 编译期代码生成 | 🟡 | 详见 0003 | use GenServer / use Oban.Worker |
quote / unquote = AST 操作 | 🟡 | 写宏必学 | quote do: 1 + 2 |
Module.create / Module.eval_quoted | 🔴 | 运行时定义模块 | 元编程高级 |
use vs import vs require vs alias | 🟡 | use=宏包,import=导入,require=宏可见,alias=重命名 | 全部 |
@ 编译时属性(@moduledoc / @doc) | 🟡 | 文档、spec、行为声明 | 全部 |
类型规范(@spec + dialyzer) | 🟡 | 静态类型检查(可选) | mix dialyzer |
@callback 行为声明 | 🟢 | 详见 0003 | Pipeline.Llm.@callback |
| 热代码升级(hot code reload) | 🟡 | 详见 0003;Application.start 模式 | 生产零停机 |
| mix releases + 配置 | 🟡 | MIX_ENV=prod mix release,自带 runtime.exs | 部署 |
| 编译时 vs 运行时的边界 | 🟡 | Module.compile_env vs Application.get_env | 配置 |
| Mix Project 完整结构(mix.exs) | 🟡 | deps / application / paths / aliases | 全部 |
Mix Tasks(自定义 mix mytask) | 🟡 | 写 CLIs | mix ecto.migrate |
五、Ecto 🟡
| 主题 | 状态 | 一句话 | 影响代码 |
|---|---|---|---|
use Ecto.Schema 声明表 | 🟢 | 详见 0001 / Pipeline.FeishuMessage | 全部 |
Ecto.Changeset + cast + validate_required | 🟢 | 详见 0001 / Pipeline.PipelineExecution.changeset | 入库前校验 |
Repo.insert! / update! / delete! | 🟢 | 增删改;带 ! 抛异常 | 全部 |
Repo.get/2 / get_by/2 | 🟢 | 主键 / 字段查询 | 全部 |
Repo.all/1 + Ecto.Query | 🟢 | from e in X, where: ..., select: ... | 全部查询 |
关联(has_many / belongs_to) | 🟡 | Ecto 关系 | 多表 |
嵌入(embeds_one / embeds_many) | 🟡 | 嵌套 JSONB | 配置存储 |
| 多 Repo / 读副本 | 🔴 | Ecto.Repo.Supervisor.child_spec 多次 | 多 DB |
事务(Repo.transaction/1) | 🟡 | Multi 模式 | 复杂写 |
| Ecto 动态查询 | 🟡 | from e in base, where: ^cond 条件拼装 | Pipeline.Execution.list |
Ecto.Adapters.SQL.query!/1 | 🟡 | 原生 SQL | Pipeline.Execution.recent_runs |
on_conflict: :nothing 幂等 upsert | 🟢 | Pipeline.NewsStore.upsert_messages | 重复拉取 |
Ecto.Query join / group_by / window | 🟡 | CTE / 窗口函数 | 复杂报表 |
迁移(mix ecto.migrate) | 🟡 | 手动写 up/down 函数 | schema 演进 |
@schema_prefix(test 隔离表空间) | 🟢 | Pipeline.PipelineExecution | 测试 |
六、Plug & Web 🟡
| 主题 | 状态 | 一句话 | 影响代码 |
|---|---|---|---|
use Plug.Router 路由 | 🟢 | 详见 0001 / Pipeline.Web | 全部 HTTP |
| Plug 概念(function plug) | 🟡 | def my_plug(conn, _), do: conn | middleware |
Plug 链(plug MyPlug) | 🟡 | 顺序敏感 | middleware |
Plug.Conn 字段(assigns / query_params) | 🟢 | conn.query_params["dag_name"] | 路由 |
Plug.Parsers(JSON decoder) | 🟢 | 详见 0001 | POST body |
send_resp / put_resp_content_type | 🟢 | 写裸响应 | 全部 |
| Phoenix Framework | 🔴 | 完整 Web 框架(独立项目) | Phoenix 项目 |
| Phoenix LiveView | 🔴 | 服务端实时 UI | 现代 Web |
| Bandit / Cowboy HTTP 服务器 | 🟡 | Pipeline.Application 用 Bandit | 部署 |
七、Oban & 异步 🟡
| 主题 | 状态 | 一句话 | 影响代码 |
|---|---|---|---|
use Oban.Worker | 🟢 | 详见 0001 / Pipeline.Jobs.NewsDigest | 全部 job |
Oban.insert/2 入队 | 🟡 | 异步触发 worker | 调度 |
Oban.retry_job/2 | 🟡 | Pipeline.Web /api/retry/:id | 失败重试 |
| 队列(queue)/ 限制(concurrency) | 🟡 | queue: :digest, max_attempts: 3 | 限流 |
| Cron 触发 | 🟡 | Oban.Cron | 定时任务 |
| Oban 失败处理 / discarded state | 🟡 | 死信队列 | 监控 |
替代品:Broadway(数据流)/ Flow | 🔴 | GenStage 之上的 ETL | 大数据量 |
替代品:Nx(数值计算) | 🔴 | GPU 加速 tensor | ML |
替代品:Nx.Image | 🔴 | 图像处理 | 视觉 |
八、测试 🟡
| 主题 | 状态 | 一句话 | 影响代码 |
|---|---|---|---|
ExUnit.Case + test "..." do | 🟢 | 标准测试 | test/pipeline/*_test.exs |
assert / refute | 🟢 | 断言 | 全部 |
setup / setup_all | 🟡 | 前置数据 | 每次/每文件 |
use Pipeline.DataCase(共享测试 DB) | 🟡 | test/support/data_case.ex | 测试隔离 |
describe 分组 | 🟡 | 组织用例 | 测试 |
Mox / 模拟 | 🟡 | behaviour mock | Pipeline.Llm.Dummy |
| Property-based testing(StreamData) | 🔴 | 边界 case 自动生成 | 高级 |
| doctest | 🟡 | @doc 块中的 iex 输出当断言 | 文档兼测试 |
九、生态系统 & 工具 🟡
| 主题 | 状态 | 一句话 | 影响代码 |
|---|---|---|---|
| IEx(REPL) | 🟡 | iex -S mix,带补全/历史 | 探索代码 |
| mix format(格式化) | 🟡 | 项目根 .formatter.exs | 一致风格 |
| mix credo(lint) | 🟡 | 代码质量检查 | |
| mix dialyzer(类型检查) | 🟡 | 需 PLT,首次慢 | |
| mix.exs 配置 | 🟡 | 依赖、paths、aliases | |
| Phoenix LiveDashboard | 🔴 | 实时 Web 监控 | 运维 |
| Tidewave / Mox / Mimic | 🔴 | 测试与调试工具 | |
| ExDoc | 🟡 | 文档生成 mix docs | |
| Telemetry + PromEx | 🟡 | 监控埋点 | |
| Nerves | 🔴 | 嵌入式 Elixir | IoT |
| Livebook | 🔴 | 类 Jupyter notebook | 数据科学 |
| Broadway + GenStage | 🔴 | 数据流处理 | ETL |
十、底层 BEAM & 性能 🟡
| 主题 | 状态 | 一句话 | 影响代码 |
|---|---|---|---|
| BEAM 调度器(scheduler) | 🔴 | 1 核 1 调度器,抢占式 | 性能调优 |
| 进程调度(reductions) | 🔴 | 默认 2000 reductions 切换 | |
| GC(每进程独立) | 🟡 | 不会因大对象全局 pause | 内存模型 |
| 进程邮箱(mailbox) | 🟡 | 消息堆积检测 Process.info(pid, :message_queue_len) | 监控 |
| 写时复制(COW)大 binary | 🟡 | 进程间发大消息不会真复制 | |
:erlang.system_info/1 | 🟡 | VM 统计 | 监控 |
Process.flag(:sensitive, true) | 🟡 | 进程死亡原因不传播 | 安全 |
| NIF(原生函数) | 🔴 | 写 C/Rust 提速 | 高性能库 |
| dirty NIF / dirty CPU scheduler | 🔴 | NIF 阻塞调度 | 性能 |
十一、与其他 FP 语言对比 🟢
| 主题 | 状态 | 详见 |
|---|---|---|
| Elixir vs Haskell(纯度、monad、类型) | 🟢 | 0004 |
| Elixir vs Clojure(不可变、JVM vs BEAM、宏) | 🟢 | 0004 |
| Elixir vs OCaml / F#(ML 家族) | 🟢 | 0004 |
| Elixir vs Scala(Actor、宏) | 🟢 | 0004 |
| Elixir vs Erlang(语法、metadata) | 🟢 | 0004 |
十二、设计哲学 / 文化 🟡
| 主题 | 状态 | 一句话 |
|---|---|---|
| ”Let it crash” 哲学 | 🟢 | 不防御性 if,supervisor 重启 |
| 进程即一切(everything is a process) | 🟢 | OS 进程 vs BEAM 进程 |
| 不可变数据 + 消息传递 | 🟢 | Actor 模型 |
| 显式 > 隐式(“Code is data”) | 🟡 | 宏存在的哲学基础 |
| 协议优于继承(“Open–Closed”) | 🟡 | Elixir 的 OCP 实现 |
| OTP 模式(GenServer / Supervisor / Application) | 🟡 | “设计模式”在 Elixir 是头等公民 |
| 测试是头等公民(ExUnit 与 mix 集成) | 🟡 | mix test 即一切 |
| BEAM 三十年验证 | 🟡 | Ericsson AXD 301 / WhatsApp / Discord |
十三、ex/elixir 项目特有 🟡
本节只列项目里用到的”学了上面就能读”的扩展点
| 主题 | 状态 | 出现位置 |
|---|---|---|
Application.compile_env vs Application.get_env | 🟡 | 编译时/运行时配置切换 |
Jason.encode! / Jason.decode! | 🟢 | JSON 序列化 |
Finch HTTP 客户端 | 🟡 | Pipeline.Llm.Real 调 LLM |
Ecto.Adapters.SQL.query! 原生 SQL | 🟡 | Pipeline.Execution.recent_runs CTE |
String.slice / String.split(..., trim:) | 🟢 | Pipeline.Llm.Dummy |
Map.get / Map.put / Map.new | 🟢 | 全部 Map 操作 |
Enum.map / Enum.reduce / Enum.zip | 🟢 | 全部数据转换 |
Enum.filter / Enum.find / Enum.member? | 🟢 | 列表操作 |
Keyword.get(opts, :key, default) | 🟢 | 命名参数 |
require Logger + Logger.warning | 🟢 | 日志 |
defp(私有函数) | 🟢 | 内部 helper |
@impl true(behaviour 实现声明) | 🟢 | 编译期检查 |
速通建议
如果你赶时间(目标:3 天能改 ex/elixir 的代码):
| Day | 学什么 | 跳过什么 |
|---|---|---|
| Day 1 | 0001-0003 + IEx 实操 | 全部 🔴 主题 |
| Day 2 | 一节 Ecto + 一节 Plug + 改一个 Oban worker | Type spec、行为宏内部 |
| Day 3 | 改 ex/elixir 的真实小 bug | 分布式、ETS 高级用法 |
如果你有 1 个月:
| 周 | 学什么 |
|---|---|
| W1 | Day 1-3 + 全部 🟡 中”并发 & OTP”段 |
| W2 | 🟡 “Ecto” + “Oban” + “Plug” |
| W3 | 🟡 “测试” + “工具” + 写一个完整功能 |
| W4 | 🔴 中感兴趣的 1-2 个(推荐 ETS + 节点 / Nerves) |
资源入口
- Elixir 官方文档 — 唯一权威
- Elixir School — 中文入门
- OTP 行为设计原则 — 原始论文
- Phoenix 实战 — 完整 Web 框架
- The Pragmatic Programmer Elixir 系列 — 实战书
- Elixir in Action 第二版 — 深入 BEAM