Search documentation of macula

# Development Guide

View Source

This guide covers setting up a development environment for contributing to Macula.

## Prerequisites

- Erlang/OTP 26+ - Installation Guide
- Rebar3 - Erlang build tool (Installation)
- Git - Version control
- Docker (optional) - For multi-node testing

## Quick Setup

    # Clone the repository
    git clone https://github.com/macula-io/macula.git
    cd macula

    # Fetch dependencies
    rebar3 get-deps

    # Compile
    rebar3 compile

    # Run tests
    rebar3 eunit

    # Start a shell with Macula loaded
    rebar3 shell

## Project Structure

Macula is organized as a single Erlang/OTP library with ~68 modules:

    macula/
    ├── src/                    # Source code (~68 .erl files)
    │   ├── macula_quic*.erl   # QUIC transport layer
    │   ├── macula_protocol*.erl # Wire protocol encoding/decoding
    │   ├── macula_connection*.erl # Connection management
    │   ├── macula_gateway*.erl # Gateway components
    │   ├── macula_routing*.erl # Kademlia DHT routing
    │   ├── macula_pubsub*.erl # Pub/Sub messaging
    │   ├── macula_rpc*.erl    # RPC operations
    │   └── macula_*.erl       # Core utilities
    ├── test/                  # EUnit tests
    ├── include/               # Header files (.hrl)
    ├── architecture/          # Architecture documentation
    ├── docs/                  # User-facing documentation
    ├── examples/              # Example applications
    └── rebar.config          # Build configuration

See Project Structure for complete module documentation.

## Running Tests

### All Tests

    rebar3 eunit

### Specific Module Tests

    rebar3 eunit --module=macula_id_tests
    rebar3 eunit --module=macula_gateway_client_manager_tests

### Test Coverage

    rebar3 do eunit, cover

### Multi-Node Integration Tests

    cd docker
    docker compose -f docker-compose.multi-node-test.yml build --no-cache
    docker compose -f docker-compose.multi-node-test.yml up

## Code Quality Standards

Macula follows Idiomatic Erlang principles:

### Core Principles

- ✅ Pattern matching on function heads - Avoid `if` and `cond`
- ✅ Guards instead of case - Use guards for simple conditions
- ✅ Shallow nesting - Keep nesting to 1-2 levels maximum
- ✅ Let it crash - Don't catch errors unless you can handle them meaningfully
- ✅ OTP behaviors - Use gen_server, gen_statem, supervisor where appropriate

### Example: Good vs. Bad

❌ Bad:

    process_message(Msg, State) ->
        if
            is_binary(Msg) ->
                case decode_message(Msg) of
                    {ok, Data} ->
                        if
                            Data#data.type == request ->
                                handle_request(Data, State);
                            Data#data.type == response ->
                                handle_response(Data, State)
                        end
                end
        end.

✅ Good:

    %% Guard ensures binary input
    process_message(Msg, State) when is_binary(Msg) ->
        case decode_message(Msg) of
            {ok, Data} -> handle_decoded_message(Data, State);
            {error, Reason} -> {error, Reason}
        end;
    process_message(_Msg, _State) ->
        {error, invalid_message}.

    %% Pattern match on data type
    handle_decoded_message(#data{type = request} = Data, State) ->
        handle_request(Data, State);
    handle_decoded_message(#data{type = response} = Data, State) ->
        handle_response(Data, State).

See CLAUDE.md (at repository root) for complete coding guidelines.

## Building Documentation

Macula uses ex_doc for documentation generation:

    rebar3 ex_doc

Generated docs appear in `doc/` directory. Open `doc/index.html` in a browser.

## Docker Development

### Clean Build (Always After Code Changes)

    # Prune cache and rebuild from scratch
    docker builder prune -af
    docker compose -f <compose-file> build --no-cache

Why? Docker build cache can use stale layers even after code changes. Always prune and rebuild when testing code changes.

### Multi-Node Test Environment

    cd docker
    docker-compose -f docker-compose.multi-node-test.yml up

This starts:

- 1 registry node (gateway)
- 3 provider nodes (advertise services)
- 1 client node (discovers and calls services)

## Memory Management

Macula implements comprehensive memory leak prevention. See Memory Management for details.

Key Mechanisms:

- Bounded connection pools (max 1,000 connections, LRU eviction)
- Client connection limits (max 10,000 clients, configurable)
- Service TTL/cleanup (5-minute TTL, 60-second cleanup interval)
- Stream cleanup on disconnect
- Caller process monitoring for RPC handlers

Monitoring:

    %% Check connection pool size
    macula_gateway_mesh:pool_size(GatewayPid).

    %% Check client count
    macula_gateway_client_manager:client_count(ManagerPid).

    %% Check service registry size
    macula_service_registry:service_count().

## Refactoring Status

### Gateway Refactoring (COMPLETED - Jan 2025)

The gateway module has been refactored into 6 focused modules with comprehensive tests:

- ✅ `macula_gateway_client_manager.erl` - Client lifecycle (24 tests)
- ✅ `macula_gateway_pubsub.erl` - Pub/Sub routing (31 tests)
- ✅ `macula_gateway_rpc.erl` - RPC handler management (20 tests)
- ✅ `macula_gateway_mesh.erl` - Mesh connection pooling (16 tests)
- ✅ `macula_gateway_dht.erl` - DHT query forwarding (stateless)
- ✅ `macula_gateway_rpc_router.erl` - Multi-hop RPC routing (17 tests)
- ✅ `macula_gateway_sup.erl` - Supervision tree (24 tests)

Total: 132 tests, all passing.

### Connection Refactoring (COMPLETED - Nov 2025)

The v0.7.0 nomenclature refactoring achieved separation of concerns:

- `macula_peer` - High-level API facade for mesh operations
- `macula_connection` - Low-level QUIC transport layer

See CLAUDE.md for current architecture details.

## Contributing Workflow

1. Read the documentation

   - README.md (at repository root) - Project overview
   - CLAUDE.md (at repository root) - Coding guidelines

2. Create a feature branch

       git checkout -b feature/your-feature-name

3. Write tests first (TDD approach preferred)

       # Create test file
       touch test/macula_your_module_tests.erl

       # Write failing tests
       # Implement functionality
       # Verify tests pass
       rebar3 eunit --module=macula_your_module_tests

4. Follow code quality standards

   - Pattern matching over conditionals
   - Guards instead of case where possible
   - Maximum 1-2 levels of nesting
   - Comprehensive tests for new functionality

5. Commit and push

       git add .
       git commit -m "Add feature: your feature description"
       git push origin feature/your-feature-name

6. Create pull request

   - Describe what the PR does
   - Reference any related issues
   - Ensure all tests pass
   - Follow PR template guidelines

## Getting Help

- Issues: GitHub Issues
- Documentation: See `architecture/` directory for detailed architecture docs

← Back to Documentation

← Previous Page MRI (Resource Identifiers)
Next Page → Performance Guide