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
-
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 ofmodels//services//controllers/that mixes unrelated concerns. -
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. -
Split large units
Break oversized files and modules into smaller units with a single, obvious responsibility and a stable name. -
Explicit public surface
Expose domain behavior through clear, stable interfaces (e.g. exported functions, hooks, facades). Keep implementation details internal to the module. -
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. -
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
- Map capabilities — List business capabilities and the main user journeys that touch them.
- Inventory current pain — Note god files, circular dependencies, and folders where unrelated features mingle.
- Target module boundaries — Define one module per capability (or cohesive sub-capability if size warrants); document what is public vs internal.
- Move in small steps — Prefer incremental moves (with tests passing) over a big-bang rewrite when possible.
- 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
utilsorcommonwithout 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.