← Back to the roundtable

Pattern Organization

1. The solution folder

the top of the tree: everything hangs off this one folder

Inside the solution folder sit six folders as siblings: none of them is nested inside another. That flatness is the whole point of an n-tier layout: every folder holds one job, and its name tells you what it is allowed to know about.

2. webhost

the front door: hosts the HTTP endpoints and starts the application

This folder is the front door of the application. Every request from the outside world arrives here, and every check that has to pass before the application will answer it is made here. Nothing reaches the folders behind webhost until this layer says it may.

That is the boundary in one line: if a check is about trusting a stranger, it belongs in webhost; if it is about the business, it belongs in logic. webhost is the only folder allowed to know that HTTP exists.

3. logic

the business rules: nothing here knows a web request exists

The rulebook: what has to be true, in what order, and who may change it. Everything in this folder decides, and anything it needs from the outside arrives through a contract it does not implement itself, which is why the patterns that shape decisions rather than plumbing live here. These five turn up again and again.

Notice what the five have in common: none of them is about infrastructure. Each one lets logic grow by adding a class rather than editing one that is already trusted, and each can be exercised in a test with plain objects and no server in sight. Anything that needs a socket, a vendor SDK or a table belongs in webhost, adapter or data instead.

4. data

talks to the store: the entities, the queries, the code that saves them

The only folder allowed to know what a store is. It owns the tables, the queries and the transactions, and everyone else asks it for things and gets objects back; logic never learns whether the answer came from SQL, a document store or a file on disk.

What it must never do is have an opinion. A rule like "an order needs at least one line" is a decision, and decisions live in logic; data records decisions and answers questions about them. Holding that boundary is what keeps the store swappable.

5. adapter

the translator: turns an outside service into a shape logic already understands

The outside world, behind a wall. A payment provider, a mail relay, a tax service: each one arrives here and is translated into the shape logic already speaks, so no folder above has to learn a vendor's name, its error codes, or what it calls a date.

This is the anti-corruption layer, and the point of it is a direction of travel: outside shapes move inward and are translated on the way, never carried in raw. If a rule cannot be tested without a network connection, something from out here has leaked into logic.

6. shared

the small, boring things more than one folder needs: contracts, constants, helpers

The smallest folder, and the one that has to stay the smallest. It holds the vocabulary the other folders agree on: the contracts, types and constants that have to mean the same thing in more than one place.

The danger of a folder with this name is that everything eventually lands in it. Two questions keep it honest: does more than one folder need it, and can it be written without depending on any of them? A type that fails either question belongs where it is actually used.

7. initializer

startup wiring that runs once: configuration, dependencies, schema setup

The only folder that sees the whole application at once. Every piece the other folders ask for is chosen, configured and handed over here (once, at startup, before the first request arrives), and then this folder gets out of the way.

The rule that keeps this folder safe is a direction: initializer may know about every other folder, and no other folder has a reason to know about it. It is the one place allowed to see the whole picture, which is exactly why no business rule is allowed to live here.