Claude Code Plugins

Community-maintained marketplace

Feedback

otp-patterns

@layeddie/ai-rules
0
0

Implements OTP design patterns including GenServer, Supervisor, and Application behaviors.

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

name otp-patterns
description Implements OTP design patterns including GenServer, Supervisor, and Application behaviors.

OTP Patterns Skill

Use this skill when implementing OTP behaviors and patterns in Elixir.

When to Use

  • Creating new GenServers or Supervisors
  • Designing supervision trees
  • Implementing process-based features

GenServer Pattern

Basic GenServer

defmodule Cache.Worker do
  use GenServer

  # Client API
  def start_link(opts), do: GenServer.start_link(__MODULE__, opts, name: __MODULE__)
  def get(key), do: GenServer.call(__MODULE__, {:get, key})
  def put(key, value), do: GenServer.cast(__MODULE__, {:put, key, value})

  # Server Callbacks
  @impl true
  def init(opts), do: {:ok, %{cache: %{}, opts: opts}}

  @impl true
  def handle_call({:get, key}, _from, state) do
    {:reply, Map.get(state.cache, key), state}
  end

  @impl true
  def handle_cast({:put, key, value}, state) do
    {:noreply, put_in(state.cache[key], value)}
  end
end

Named Processes

# ✅ Good - Named process
{Cache.Worker, name: {:via, Registry, {MyRegistry, :worker}}

# ✅ Good - Module name
{Cache.Worker, name: Cache.Worker}

# ❌ Bad - PID dependencies
pid = Process.whereis(:some_process)

Supervisor Pattern

One-For-One

defmodule MyApp.Application do
  use Application

  def start(_type, _args) do
    children = [
      MyApp.Repo,
      {Registry, keys: :unique, name: MyApp.Registry},
      {MyApp.WorkerSupervisor, []},
      MyAppWeb.Endpoint
    ]

    opts = [strategy: :one_for_one, name: MyApp.Supervisor]
    Supervisor.start_link(children, opts)
  end
end

Dynamic Supervisor

defmodule DynamicSupervisor do
  def start_link(init_arg, opts \\ []) do
    DynamicSupervisor.start_link(__MODULE__, init_arg, opts)
  end

  @impl true
  def init(init_arg, opts) do
    DynamicSupervisor.init(init_arg, opts)
  end
end

Common Anti-Patterns

Blocking GenServer Callbacks

# ❌ Bad - Blocks entire GenServer
@impl true
def handle_call(:slow_operation, _from, state) do
  result = HTTPoison.get!("https://api.example.com")
  {:reply, result, state}
end

# ✅ Good - Use Task for async
@impl true
def handle_call(:slow_operation, from, state) do
  Task.start(fn ->
    result = HTTPoison.get!("https://api.example.com")
    GenServer.reply(from, result)
  end)
  {:noreply, state}
end

Overusing Shared State via ETS

# ❌ Bad - Breaks immutability
ETS.update(:cache, :key, value)

# ✅ Good - Use GenServer for stateful operations
GenServer.call(__MODULE__, {:update, new_value})

Tools to Use

  • Use :observer.start() to visualize processes
  • Use :erlang.system_info(:process_count) to check process count
  • Use Process.info(pid) for process details

Best Practices

  • Clear separation between client API and server callbacks
  • Use named processes for long-running services
  • Avoid blocking handle_call callbacks
  • Use handle_cast for fire-and-forget operations
  • Document restart strategies and fault boundaries
  • Separate OTP processes from business logic functions