OTAKU / The three shapes

Chapter 02 — the taxonomy

The three shapes

Modularity is not reviewed after the fact — it is enforced by the shape of the repository. Every repository must fit exactly one of three archetypes. There is no fourth option and no hybrid.

1 — Atom

The smallest possible unit of granularity. If a component can be broken down further, it is not an atom.

  • Structure: flat. A single level of directory inside the source root.
  • Rule: no subdivisions. It fulfils one specific contract.
  • Test: can you describe it with one sentence that has no “and”?
  • Examples: a value object, a string utility, a single HTTP client, a contract-only package.

2 — Assembly

A connection point. Assemblies contain no logic; they orchestrate the union of atoms so that one dependency declaration installs ten packages.

  • Structure: no source code. Composition is declared in the package manifest.
  • Rule: if it has behaviour, it is not an assembly.
  • Test: can you delete its manifest and have nothing left but a README?
  • Examples: a meta-package that bundles the HTTP atoms, a “commons” bundle.

3 — Application

The living system. Not a library, but the implementation of the business heart, following Clean Architecture and DDD.

  • Structure: domain, application, infrastructure, interface — dependencies pointing inwards.
  • Rule: stay lean. Anything generic is pushed down into atoms.
  • Test: does it contain a use case that a business expert would recognize?
  • Examples: a payment gateway, an identity service, a kanban board.

The same idea in four ecosystems

The names of the artifacts change; the shapes do not.

ShapePHP / ComposerC# / NuGetJava / MavenC++ / Conan
Atomtype: library, one namespaceclass library, one namespacejar, one packageheader + library, one namespace
Assemblytype: metapackage, only requirepackage with no compiled code, PackageReference onlypom with <dependency> only, no sourcesconanfile that only requires
Applicationtype: project, src/Domain, src/Application…executable / web project with layer foldersbootable app with layer modulesexecutable target with layer directories

How to classify a repository

Ask the three questions in order and stop at the first “yes”.

QuestionIf yes
Does it contain use cases and business rules?Application
Does it contain only dependency declarations?Assembly
Does it fit in one sentence with one responsibility?Atom

If none of the answers is “yes”, the repository is not ready to exist. That is not a stylistic judgement; it is the signal that the boundary has not been found yet.

Why three, and not more

More shapes mean more places to hide. A fourth archetype — “shared utilities”, “common”, “core” — always becomes the place where unrelated things accumulate until nobody can delete anything.

Three shapes also give a mechanical rule for leaks: code that belongs to an atom but lives in an application will eventually be copied into another application. The taxonomy makes that leak visible at review time, because the reviewer can ask a single question: does this file belong to this shape?

Enforcement

A taxonomy that lives in a document is a suggestion. To enforce it, put the shape in machine-readable metadata and check it in CI:

  • PHP: composer.json → type must be library, metapackage or project.
  • C#: an assembly must have no .cs files; the .csproj should be Microsoft.NET.Sdk with no compile items.
  • Java: an assembly module must have an empty src/main/java.
  • C++: an assembly is headers-only or absent; the conanfile must declare requires and no sources().

For the application shape, the check is structural: assert that the domain layer has no import of infrastructure, framework or database packages. Every ecosystem has a tool for that — deptrac (PHP), NetArchTest (C#),ArchUnit (Java), include-what-you-use plus build-graph rules (C++).

Continue to the guide →