Onion Architecture


This is a placeholder to hold reference links until I've got time to build a project or two with this pattern. See ## HEX ## in project for notes-during-construction.

Why Bother?

Better minds have written better texts on this form of architecture. This text is my own, a translation of a Good Idea for me.

Aggregate Root
A collection of domain objects (dataclasses) which together form a conceptual space that is both bounded and useful. Often turned into a single Repository.
Composition Root
The entrypoint that instantiates all the pieces of a hexagon and puts them together.

Purpose of a Hexagon

A hexagon is not a universal solution to every problem. It is just another design pattern at the end of the day; albeit with some power behind it.

When a sub-set of a project is chunked into a hexagon we are bounding the scope explicitly. By setting the domain (perhaps as a subset of the total database) we determine the amount of the overall model the programmer must load into her head when operating within that space.

This is perhaps the fundamental purpose of a hexagon. It breaks large intractable problems down into smaller tractable ones and pretty rigidly prevents spillover between those bits.

When choosing this tool, I must keep in mind this scope aspect above all else. What is the right scope for a hexagon?

Strategy and Tactics

Choosing hexagon scope is to set the engagement. The engagement, then, is creating a hexagon that functions. So all the choices within the hexagon are tactical in nature.

However, it does not stop there. The real value of this architecture is that it makes it very easy to airgap design (when writing the domain, blogic, and interfaces) from implementation (when actually writing the adapters). The human mind shifts gears between structuring code and debugging.

So designing within the hexagon is tactical. Actually banging out adapters is implementation (or maybe operations?).

Mocking

This probably won't be an h2 after refactor.

Mocking should be done with a flow like:

  1. mock data json
  2. neested instantiation (into DC's)
  3. feed into adapters (like Repo to DB, or API to mem)

This is powerful because it makes writing tests really fast. You spend less time writing loads of fixtures. It also makes general mocking really easy. A critical component is that you can define ID's and relationships in the json, not in the code where you set up mocking and/or tests.

This does require some extra work, particularly in repos. There must be an additional from_json method or something like that, or an entire real mocking Repo must be made. Still experimenting with that.