Skip to content

ADR-0002: Project Structure and Development Tools

Status

ACCEPTED

Date: 2025-07-05

Changelog

Date Revision Description Author
2025-07-05 1.0 Initial version souperk
2025-07-19 1.1 Added subdomain service organization AI Assistant

Context

As we begin development, we need to establish a clear and consistent project structure that:

  • Promotes code organization and maintainability
  • Supports modularity and separation of concerns
  • Provides consistent development workflows
  • Ensures code quality through automated checks
  • Facilitates local development and testing

Currently, we need to define:

  • How code should be organized
  • What development tools to use
  • How to ensure code quality
  • How to support local development

Decision

Project Structure

We will organize the project with the following directory structure:

server/ 
├── libs/      # Reusable library packages 
├── services/  # Service implementations 
└── tools/     # Development and operational tooling

Each directory serves a specific purpose:

  • server/libs/: Contains shared library code that can be reused across services
  • server/services/: Contains individual service implementations, each potentially with its own deployment
  • server/tools/: Contains utility packages and tools for development, deployment, and operations

Package Structure

Each package will maintain a consistent structure with the following key files:

package/
├── Makefile                  # Build, test, and development commands
├── src/                      # Package source code
│  └── loryth/                # Loryth namespace package
│     └── package/            # Package module
│        ├── api/             # (service) API module
│        ├── worker/          # (service) Worker module
│        ├── domain/          # (service) Domain module
│        │  └── sub_domain/   # Subdomain modules and implementations
│        ├── config/          # (service) Config module
│        ├── persistence/     # (service) Persistence module
│        └── __init__.py      # Module 
├── tests/                    # Package test suite
├── pyproject.toml            # Python package configuration and dependencies
└── docker-compose.yml        # Local development environment (for services)

Domain Structure

The domain module will be organized with subdomains, where each subdomain contains its own services and domain models:

  • All services should be implemented within their respective subdomain folder: loryth.package.domain.sub_domain
  • This maintains clear separation of concerns and makes it easier to identify which subdomain owns each service
  • It provides consistent organization that scales as the application grows
  • Domain models related to a specific subdomain should also be placed within the subdomain folder

Development Tools

We will use the following tools for development and quality assurance:

  1. Type Checking: mypy

    • Strict type checking enabled
    • Required for all Python code
    • Configuration in pyproject.toml
  2. Code Linting: ruff

    • Modern, fast Python linter
    • Enforces code style and catches common errors
    • Configuration in pyproject.toml
  3. Testing: pytest

    • All code must have unit tests
    • Integration tests for services
    • Configuration in pyproject.toml
  4. Dependency Management: uv

    • Fast, reliable Python package management
    • Handles local development dependencies
    • Supports editable local package installations
    • Configuration in pyproject.toml under [tool.uv.sources]

Build and Development

  • Makefile will provide standard targets:
    • make build: Build the package
    • make test: Run tests
    • make lint: Run linting
    • make typecheck: Run type checking
    • make check: Run all checks (lint, typecheck, test)
    • make clean: Clean build artifacts

Consequences

Positive

  • Clear organization of code by responsibility
  • Consistent development experience across packages
  • Easier to find and understand code organization
  • Automated quality checks ensure code standards
  • Local development environment matches production
  • Standardized build and test processes
  • Reusable code properly separated in libs

Negative

  • Additional setup time for new packages
  • Learning curve for developers new to the tools
  • Need to maintain consistency across multiple packages
  • Docker overhead for local development

Neutral

  • Regular updates needed for development tools
  • May need to adjust structure as project grows
  • Teams need to agree on when to create new services vs libraries

Alternatives Considered

  1. Monolithic Repository Structure

    • Description: Single flat directory structure
    • Pros:
      • Simpler initial setup
      • Easier dependency management
    • Cons:
      • Harder to scale
      • Less clear separation of concerns
    • Not chosen because we need better separation for maintainability
  2. Black for Code Formatting

    • Description: Using Black instead of ruff for formatting
    • Pros:
      • More established tool
      • Zero configuration
    • Cons:
      • Slower than ruff
      • Less comprehensive (formatting only)
    • Not chosen because ruff provides more features and better performance
  3. Poetry for Package Management

    • Description: Using Poetry instead of standard setuptools
    • Pros:
      • Better dependency resolution
      • Modern tooling
    • Cons:
      • Additional tool to learn
      • Not as widely adopted
    • Not chosen to keep tooling minimal and standard
  4. Virtualenv for Dependency Management

    • Description: Using virtualenv directly instead of uv
    • Pros:
      • Established, standard tool
      • Well-known workflow
    • Cons:
      • Slower than uv
      • Less robust dependency resolution
      • More complex editable package handling
    • Not chosen because uv provides better performance and reliability

    • Alternative Service Organization Approaches

    • Description: Placing services directly at the domain level (loryth.package.domain) or using a mixed approach
    • Pros:
      • Flatter hierarchy in the domain level approach
      • More flexibility in the mixed approach
    • Cons:
      • Less clear ownership boundaries
      • Harder to maintain consistency
      • Potential service location confusion
    • Not chosen because placing services in their respective subdomains provides clearer ownership boundaries and better separation of concerns

References