docs: idiomatic Elixir and Phoenix patterns with verified source citations

Extracted patterns from Elixir core and Phoenix source code with specific
file:line citations, then verified all citations against the actual source
in a second pass.

Structure:
- patterns/ — Elixir core patterns (GenServer, errors, data, types, etc.)
- phoenix/ — Phoenix-specific patterns and deviations
- comparison/ — Elixir vs Phoenix side-by-side
- smells/ — Anti-patterns and common mistakes
- changelog/ — Daily Elixir/Phoenix PR digest (auto-updated)
This commit is contained in:
Aaron Weiker
2026-04-29 22:59:17 -07:00
parent 4ea9a884aa
commit 2e7a822b6b
6 changed files with 845 additions and 406 deletions
+30 -11
View File
@@ -10,7 +10,7 @@ Where Phoenix deliberately differs from Elixir core patterns and why.
**Phoenix deviation:** The Router uses macros extensively.
**Source:** `lib/phoenix/router.ex:109-123`
**Source:** `lib/phoenix/router.ex:106-128`
> We use `get`, `post`, `put`, and `delete` to define your routes. We use macros
> for two purposes:
@@ -31,10 +31,12 @@ Where Phoenix deliberately differs from Elixir core patterns and why.
**Phoenix deviation:** The Router imports entire modules:
**Source:** `lib/phoenix/router.ex:274-276`
**Source:** `lib/phoenix/router.ex:303-306`
```elixir
import Phoenix.Router
# TODO v2: No longer automatically import dependencies
import Plug.Conn
import Phoenix.Controller
```
@@ -49,13 +51,24 @@ import Phoenix.Controller
**Phoenix deviation:** Aggressive use of module attribute accumulation.
**Source:** `lib/phoenix/router.ex:271-280`
**Source:** `lib/phoenix/router.ex:297-312`
```elixir
Module.register_attribute(__MODULE__, :phoenix_routes, accumulate: true)
@phoenix_pipeline nil
Phoenix.Router.Scope.init(__MODULE__)
@before_compile unquote(__MODULE__)
defp prelude(opts) do
quote do
Module.register_attribute(__MODULE__, :phoenix_routes, accumulate: true)
@phoenix_helpers Keyword.get(unquote(opts), :helpers, true)
import Phoenix.Router
import Plug.Conn
import Phoenix.Controller
# Set up initial scope
@phoenix_pipeline nil
Phoenix.Router.Scope.init(__MODULE__)
@before_compile unquote(__MODULE__)
end
end
```
**Why the deviation:** The Router needs to collect ALL routes, then compile them into a single dispatch function. This requires building up state during module compilation, then consuming it all at `@before_compile`.
@@ -68,7 +81,7 @@ Phoenix.Router.Scope.init(__MODULE__)
**Phoenix Channel default:** `:temporary` (never restart).
**Source:** `lib/phoenix/channel.ex:470-475`
**Source:** `lib/phoenix/channel.ex:464-472`
```elixir
def child_spec(init_arg) do
@@ -91,7 +104,7 @@ end
**Phoenix Channel:** Defaults to hibernate after 15 seconds of inactivity.
**Source:** `lib/phoenix/channel.ex:460`
**Source:** `lib/phoenix/channel.ex:459`
```elixir
@phoenix_hibernate_after Keyword.get(opts, :hibernate_after, 15_000)
@@ -115,7 +128,7 @@ end
**Phoenix Endpoint:** Uses `Plug.Builder` — a macro that generates the `call/2` pipeline by chaining plugs at compile time.
**Source:** `lib/phoenix/endpoint.ex:481-483`
**Source:** `lib/phoenix/endpoint.ex:478-480`
```elixir
defp plug() do
@@ -136,14 +149,20 @@ end
**Phoenix exceptions:** Include `plug_status` for HTTP response mapping.
**Source:** `lib/phoenix/router.ex:7-8`
**Source:** `lib/phoenix/router.ex:2-26`
```elixir
defmodule NoRouteError do
@moduledoc """
Exception raised when no route is found.
"""
defexception plug_status: 404, message: "no route found", conn: nil, router: nil
end
defmodule MalformedURIError do
@moduledoc """
Exception raised when the URI is malformed on matching.
"""
defexception [:message, plug_status: 400]
end
```