Assembling the machine…

MCH-001 is running

Software architecture, drawn as machines you can run.

Each concept is a 3D machine in your browser. Scroll, and a real request travels through the first one, hexagonal architecture, step by step. Then a switch changes the machine, and you see what the pattern protects you from.

Scroll to run MCH-001

MCH-001 · Place an order

Hexagonal architecture, step by step.

Also called ports and adapters: the business core owns its interfaces and depends on nothing outside it. Scroll, and one order goes through it.

  1. Step 1 / 8 · Place an order

    The application starts

    Before any request, the configurator creates each adapter and plugs it into its port. Postgres answers OrderRepository: decided here, once, not in the core.

    1. 0.00 msCONFIGPlaceOrder ← HttpAdapter
    2. 0.00 msCONFIGOrderRepository ← PostgresAdapter
    3. 0.00 msCONFIGPaymentGateway ← PaymentProviderAdapter
  2. Step 2 / 8 · Place an order

    A request arrives

    POST /orders reaches the HTTP adapter. It turns the request into a PlaceOrder command, nothing more.

    1. 0.00 msREQPOST /orders → HttpAdapter
  3. Step 3 / 8 · Place an order

    Through the input port

    The adapter calls PlaceOrder, an interface the core owns. The adapter depends on the core, not the other way round.

    1. 0.05 msREQHttpAdapter → PlaceOrder (in port)
  4. Step 4 / 8 · Place an order

    The core applies the rules

    An order needs at least one line and a positive total. Pure business logic: no SQL, no HTTP, no framework.

    1. 0.06 msRULEorder#1042 lines > 0 OK · total > 0 OK
  5. Step 5 / 8 · Place an order

    Out through OrderRepository

    The core saves the order through a port it declares. It does not know which storage will answer.

    1. 0.07 msWRITEOrderRepository.save(order#1042)
  6. Step 6 / 8 · Place an order

    Postgres answers

    The Postgres adapter implements OrderRepository and runs the INSERT. The core never wrote a line of SQL.

    1. 4.27 msWRITEPostgresAdapter INSERT INTO orders
  7. Step 7 / 8 · Place an order

    Payment through PaymentGateway

    The core charges the customer through another port. The payment provider is only one adapter behind it.

    1. 184.28 msREQPaymentGateway.charge(49.00 EUR) → PaymentProviderAdapter
  8. Step 8 / 8 · Place an order

    The response goes back

    201 Created. The HTTP adapter turns the result into a response. The core never saw HTTP.

    1. 184.34 msRESP201 Created order#1042
  9. What if · Step 6 / 8

    InMemory answers

    Same port, different adapter: a Map answers in a hundredth of a millisecond. Not a single domain file changed.

    1. 0.08 msWRITEInMemoryAdapter map.set(1042)
  10. What if · Step 6 / 8

    The swap breaks the core

    InMemory is plugged into OrderRepository, but the core still calls Postgres, now on the bench. Changing storage means editing the domain.

    1. 4.26 msERROrder domain → PostgresAdapter · not wired, the core must change

End of the run · 184.34 ms

One request, one machine, every step on the record.

On its own page, MCH-001 plays two more scenarios, a declined payment and an empty order, and lets you flip every switch yourself.

Drawing register

Eight machines on the drawing board.

One is issued each week, and which one comes next is put to a vote on X. Point at a sheet to pull it from the drawer.

Vote for the next one on X
Driving sideApplicationDriven side

Hexagonal architecture

Scale
NTS
Rev
A
Source
A. Cockburn, 2005
Run MCH-001
Drawing register
Dwg no.TitleFamilyStatusRev
MCH-001Hexagonal architectureBackendIssuedA
MCH-002JavaScript event loopFrontendIn draft—
MCH-003Domain-driven designBackendIn draft—
MCH-004Offline-first syncMobileIn draft—
MCH-005CQRS and event sourcingBackendIn draft—
MCH-006React renderingFrontendIn draft—
MCH-007Redis cache-asideInfraIn draft—
MCH-008Kafka partitions and consumer groupsInfraIn draft—

Legend

Learn to read one machine, and you can read them all.

Every machine is drawn with the same symbols. Here they are on MCH-001, seen from above: point at a note, and its line lights up.

  1. Balloon

    A part's number. The same disc marks the part in the scene and its row in the bill of parts: click either, and both light up.

  2. Dimension

    A route's modelled latency: here, 4.2 ms from OrderRepository to Postgres.

  3. Flow colour

    What travels a pipe: a request, a write, a response or an error.

  4. Arrowhead

    Which end depends on the other in source code: here the payment provider adapter depends on PaymentGateway, the port the core declares.

  5. Title block

    Code, scale, revision, and the reference the machine was checked against.

Driving sideApplicationDriven side4.2 ms12345678910Hexagonal architectureCODEMCH-001SCALENTSREVASOURCEA. Cockburn, 2005

General notes

  1. Latencies are modelled, in milliseconds. They are not measured.
  2. Every machine is checked against the reference in its title block, and never shows a behaviour the real system does not have.
  3. The engine steps at a fixed 1/60 s, so a run plays the same on every screen. MCH-001 places an order in 184.34 ms of simulated time.
  4. Vermillon marks errors and violations, and nothing else.

Build log

Built in public, one machine a week.

The engine, the drawings and the mistakes, posted as they happen.

Follow @ewenlq on X
Revisions
DateKindChange
12 OCTSHIPnightprint.dev is live: a static export on a VPS, republished on every push to main.
12 OCTPERFThe machine assembles in 1.5 s on first load. Materials compile while the stage is still hidden: no frame over 40 ms once it shows.
12 OCTUIThe home page runs MCH-001 as you scroll: each note plays its step on one drawing sheet that stays put.
12 OCTSEOEvery step of every scenario is now plain HTML. Crawlers never see the canvas.
12 OCTFIXA what-if switch stalled 166 ms compiling materials. Every route is now mounted up front and fades in: 25 ms.
12 OCTOPENThe repo is public on GitHub. Every commit passes lint, types and tests on its own.
12 OCTFIXdrei <Html> + Strict Mode: 9 React errors per page. Part numbers are now one DOM layer.
12 OCTUIThe design system went atomic: 25 components, none of them knows the engine.
Full history on GitHub