Skip to content

domain-modularization

domain-modularization

Organizes code into domain modules (capabilities) instead of only technical layers; splits large files, keeps public vs internal boundaries, and reduces scattered domain logic. Use when restructuring a codebase, planning module layout, refactoring for maintainability, or when navigation and ownership by business capability are unclear.

When to apply

Use this skill when:

  • Features or logic are hard to locate because they span many unrelated folders.
  • New work repeatedly touches the same "god" files or ambiguous catch-all packages.
  • The team wants clearer ownership aligned with business capabilities.
  • A refactor is needed to improve reuse, testing, or extension without changing product behavior.

Principles

  1. Organize by domain (capability), not only by layer
    Prefer folders/modules named for what the product does (e.g. billing, documents, auth) over a flat split of models/ / services/ / controllers/ that mixes unrelated concerns.

  2. Co-locate what changes together
    Inside a domain module, group related models, services, workflows, UI bindings (when applicable), and tests when it improves clarity—without forcing a rigid template if the stack suggests a different local layout.

  3. Split large units
    Break oversized files and modules into smaller units with a single, obvious responsibility and a stable name.

  4. Explicit public surface
    Expose domain behavior through clear, stable interfaces (e.g. exported functions, hooks, facades). Keep implementation details internal to the module.

  5. Contain domain logic
    Avoid duplicating or scattering the same business rules across unrelated trees. If logic leaks out, move it behind the domain's public interface.

  6. Refactor when navigation fails
    When "where does this live?" becomes a recurring question, prioritize restructuring toward domain modules over adding more cross-folder glue.

Workflow

  1. Map capabilities — List business capabilities and the main user journeys that touch them.
  2. Inventory current pain — Note god files, circular dependencies, and folders where unrelated features mingle.
  3. Target module boundaries — Define one module per capability (or cohesive sub-capability if size warrants); document what is public vs internal.
  4. Move in small steps — Prefer incremental moves (with tests passing) over a big-bang rewrite when possible.
  5. Verify — After each meaningful step: imports resolve, tests pass, and "where does X live?" has one obvious answer.

Anti-patterns to avoid

  • Purely technical top-level trees that force every feature to touch the same global utils or common without domain context.
  • Leaky modules where UI or API layers re-implement business rules instead of calling domain interfaces.
  • Premature abstraction — splitting into many tiny files before boundaries are understood; start from real cohesion and pain.

Expected outcomes

  • The codebase reads in terms of business capabilities.
  • Related logic is easy to find and evolve in one place.
  • Reuse and maintainability improve as boundaries and public APIs stabilize.

Related skills

  • lean-implementation — Use alongside modularization to keep domain interfaces narrow and avoid premature abstraction.
  • housekeeping-docs — After restructuring, update docs to reflect the new module layout.