Developing Elixir
Expert guidance for building robust, scalable Elixir/Phoenix applications.
Quick Start
For immediate help, identify your task type and consult the relevant reference:
| Working On | Reference File | Key Topics |
|---|---|---|
| Controllers, routing, plugs, channels | phoenix-framework | MVC patterns, authentication, WebSockets |
| LiveView components, forms | liveview | Real-time UI, hooks, streams |
| Schemas, queries, migrations | ecto-database | Associations, changesets, transactions |
| GenServer, Supervisor, processes | otp-patterns | Fault tolerance, state management |
| Domain modeling, value objects | functional-modeling | Parse-don't-validate, DDD |
| GraphQL schemas, resolvers | graphql-absinthe | Subscriptions, dataloader |
| ExUnit tests, TDD workflow | testing-exunit | Test organization, assertions |
TDD Phase Awareness
All guidance in this skill is phase-aware. Identify your current phase:
RED Phase (Writing Failing Tests)
- •Write the smallest test that captures intent
- •Use hard-coded values directly in tests
- •Skip edge cases and parameterization initially
- •Focus on what behavior the test demands
GREEN Phase (Making Tests Pass)
- •RESIST over-engineering at all costs
- •Start with pure functions and simple data structures
- •Recommend primitives and maps before structs
- •Defer abstractions, smart constructors, and validations
- •Focus only on making the current test pass
REFACTOR Phase (Improving Design)
- •NOW apply proper patterns and abstractions
- •Extract value objects from primitives
- •Add comprehensive error handling
- •Introduce OTP patterns if genuinely needed
- •Improve test structure and coverage
Cross-Cutting Principles
These principles apply across all Elixir development:
Functional-First Approach
- •Prefer pure functions over stateful processes
- •Use explicit state passing through function parameters
- •Only introduce OTP patterns when tests require them
- •Push side effects to system boundaries
Progressive Abstraction
- •Start with primitives and maps
- •Introduce structs when structure is genuinely needed
- •Add type specs when interfaces stabilize
- •Extract domain modules when concepts are proven
Parse, Don't Validate
- •Transform unstructured data into guaranteed-valid types at boundaries
- •Once data is parsed, it's always valid throughout the system
- •Prefer constructors that return
{:ok, value} | {:error, reason}
Error Handling Philosophy
- •Use tagged tuples consistently:
{:ok, result}or{:error, reason} - •Implement proper error types for domain-specific errors
- •Never expose internal implementation details in errors
Examples
Creating a Phoenix context with Ecto:
User: "I need to add a checkout feature for orders" → Consult ecto-database.md for schema design, phoenix-framework.md for controller
Implementing real-time updates:
User: "Show live order status updates to the customer" → Consult liveview.md for socket state and PubSub patterns
Refactoring to proper domain model:
User: "This order calculation has grown complex with many edge cases" → Identify TDD phase (likely REFACTOR), consult functional-modeling.md
Adding background job processing:
User: "Process order confirmations asynchronously" → Consult otp-patterns.md for process decisions, phoenix-framework.md for Oban
Anti-Patterns to Avoid
Premature OTP
- •GenServer for data that could be function arguments
- •Supervisors for processes that don't need restart strategies
- •ETS tables for small, static datasets
- •Message passing when direct function calls suffice
Premature Abstraction
- •Creating types for single-use values
- •Building generic solutions for specific problems
- •Introducing abstractions without duplication
- •Modeling future requirements
Testing Anti-Patterns
- •Writing multiple assertions before any pass
- •Creating elaborate test fixtures prematurely
- •Testing implementation details
- •Adding error case tests too early
Reference File IDs
For programmatic access (e.g., parallel reviews), use these identifiers:
phoenix-framework · liveview · ecto-database · otp-patterns · functional-modeling · graphql-absinthe · testing-exunit