Curated library of 38 atomic skills, 7 personas, and 1 orchestrator for Elixir and Phoenix development. Organized by category: fundamentals, phoenix, database, testing, auth, infrastructure, quality, security, integrations, tooling, frameworks, personas, and orchestration. Covers core Elixir patterns, Phoenix LiveView, Ecto, OTP, Oban, testing, security, deployment, real-time, and modern tooling (Req, Swoosh, Cachex, Broadway, Ash).
73
91%
Does it follow best practices?
Impact
—
No eval scenarios have been run
Advisory
Suggest reviewing before use
MIX_ENV=prod for realistic resultsbench/baseline.json with a >10% threshold:fprof or :eprof to identify the actual bottleneck before writing benchmarkstime: 10 (10 seconds) for reliable measurements and run 3-5 times to rule out variance:fprof or :eprof — identify which function is the actual bottleneck; verify the output explicitly names the expected slow call site before proceedinginputs:; if results are within noise (< 5% difference), run 3 additional times to rule out variancebench/baseline.json and check for regressions (>10% threshold); if a regression is detected, compare against the previous 3 baseline runs before raising an error to rule out noise# mix.exs
defp deps do
[
{:benchee, "~> 1.3", only: :dev}
]
end# bench/list_benchmark.exs
list = Enum.to_list(1..10_000)
Benchee.run(%{
"Enum.map" => fn -> Enum.map(list, &(&1 * 2)) end,
"for comprehension" => fn -> for i <- list, do: i * 2 end,
":lists.map (Erlang)" => fn -> :lists.map(fn x -> x * 2 end, list) end
})# Run benchmark
MIX_ENV=prod mix run bench/list_benchmark.exslist = Enum.to_list(1..10_000)
Benchee.run(
%{
"Enum.sort" => fn -> Enum.sort(list) end,
"Enum.sort_by" => fn -> Enum.sort_by(list, & &1) end
},
time: 10, # Run each scenario for 10 seconds
warmup: 2, # Warm up for 2 seconds
memory_time: 2, # Measure memory usage
reduction_time: 2, # Measure reductions
inputs: %{
"small list" => Enum.to_list(1..100),
"medium list" => Enum.to_list(1..10_000),
"large list" => Enum.to_list(1..100_000)
},
formatters: [
{Benchee.Formatters.Console, comparison: true},
{Benchee.Formatters.HTML, file: "output/benchmark.html"}
]
)defmodule StringOperations do
def concat_loop(strings) do
Enum.reduce(strings, "", fn s, acc -> acc <> s end)
end
def concat_join(strings) do
Enum.join(strings)
end
def concat_comprehension(strings) do
for s <- strings, into: "", do: s
end
end
strings = for i <- 1..1000, do: "string_#{i}"
Benchee.run(%{
"reduce" => fn -> StringOperations.concat_loop(strings) end,
"join" => fn -> StringOperations.concat_join(strings) end,
"comprehension" => fn -> StringOperations.concat_comprehension(strings) end
}):fprof.trace(:start, file: 'trace.trace')
MyApp.SlowFunction.run()
:fprof.trace(:stop)
:fprof.profile(file: 'trace.trace')
:fprof.analyse(dest: 'analysis.txt'):eprof.start()
:eprof.start_profiling([self()])
MyApp.SlowFunction.run()
:eprof.stop_profiling()
:eprof.analyze()
:eprof.stop()# .github/workflows/benchmark.yml
name: Benchmark
on:
push:
branches: [main]
jobs:
benchmark:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Run benchmarks
run: |
mix deps.get
MIX_ENV=prod mix run bench/suite.exs --output results.json
- name: Store results
uses: actions/upload-artifact@v3
with:
name: benchmark-results
path: results.json# bench/compare_with_baseline.exs
baseline_file = "bench/baseline.json"
results =
Benchee.run(
%{
"current" => fn -> MyApp.FastFunction.run() end
},
time: 5,
formatters: [{Benchee.Formatters.Console, comparison: true}]
)
if File.exists?(baseline_file) do
baseline = File.read!(baseline_file) |> Jason.decode!()
current_ips = results.scenarios |> hd() |> Map.get(:ips)
baseline_ips = baseline["ips"]
regression = (baseline_ips - current_ips) / baseline_ips * 100
if regression > 10 do
Mix.raise("Performance regression detected: #{regression}% slower")
end
end
File.write!(baseline_file, Jason.encode!(%{ips: results.scenarios |> hd() |> Map.get(:ips)}))bench/
├── string_benchmark.exs # String operations
├── list_benchmark.exs # List operations
├── json_benchmark.exs # JSON encoding/decoding
├── suite.exs # Run all benchmarks
└── baseline.json # Baseline for regression detection# bench/suite.exs
Code.require_file("bench/string_benchmark.exs")
Code.require_file("bench/list_benchmark.exs")
Code.require_file("bench/json_benchmark.exs")# bench/json_benchmark.exs
data = %{
users: for i <- 1..1000 do
%{id: i, name: "User #{i}", email: "user#{i}@example.com", active: true}
end,
metadata: %{created: DateTime.utc_now(), version: "1.0"}
}
json_string = Jason.encode!(data)
Benchee.run(
%{
"Jason.encode!" => fn -> Jason.encode!(data) end,
"Jason.encode_to_iodata!" => fn -> Jason.encode_to_iodata!(data) end,
"Poison.encode!" => fn -> Poison.encode!(data) end,
"Jason.decode!" => fn -> Jason.decode!(json_string) end,
"Poison.decode!" => fn -> Poison.decode!(json_string) end
},
time: 10,
warmup: 2
)Benchee.run(
%{
"String manipulation" => fn ->
list = for i <- 1..1000, do: "item_#{i}"
Enum.join(list, ",")
end,
"Binary manipulation" => fn ->
list = for i <- 1..1000, do: <<("item_#{i}"::binary)>>
IO.iodata_to_binary(Enum.intersperse(list, <<","::binary>>))
end
},
memory_time: 5,
reduction_time: 5
)