Skip to content
kc@kumarChandrachooda.com:~$ cd /blog/four-years-cold && read --section="top" 0%
Architecture

Four Years Cold

Inflow's last commit landed on 23 July 2022 and nothing in the repository says so. The retrospective on eleven parts of reading a teaching repo as an artefact - what it gets right, what it costs, and what four passes over one estate add up to.

By Kumar Chandrachooda 12 Feb 2026 8 min read
A burst of activity on a timeline, then a long flat run

Part 10 ended on a repository whose intent went into a room instead of a file. Four months after that room, on Saturday 23 July 2022, 39e96da landed — seven .csproj files, thirty-four insertions, thirty-four deletions, subject packages update. Nothing has happened since.

Nothing in the repository says so. There is no status line, no “last verified against” note, no archive banner, no deprecation marker. The README's present tense is unchanged: “is the sample virtual payments app”, “can be found on microservices branch”, “The complete, microservices based solution can be found in Inflow-micro”. A reader arriving today gets a document written by someone who expected to be back next week.

What four years of stillness does to a clone

The code has not changed, which means everything around it has.

The target framework is out of support. All twenty projects are hard-coded to net6.0, twenty times over, with no Directory.Build.props to hoist it. .NET 6 went out of support in November 2024. The estate still builds if you install the SDK, and it is a teaching repository, so this is a footnote rather than a failure — but the first thing a reader does is install a runtime nobody patches.

The package set is frozen at a single day. Twenty-one of the estate's twenty-six distinct package references live in one file, Inflow.Shared.Infrastructure.csproj, pinned at 6.0.7, 6.0.5, 2.14.1, 6.4.0 and so on. There is no Dependabot config, no Directory.Packages.props, no nuget.config. A version bump is a four-file edit for the test SDK alone, which is exactly the work 39e96da had to do.

One dependency is a curiosity. Inflow.Modules.Saga.Api references Chronicle_ — with a trailing underscore in the package id — at 3.2.1, consumed as using Chronicle;. That id is identical on origin/net5 and origin/microservices, so it has been Chronicle_ since init. It is the only module-specific package in the entire estate.

The one thing that does drift is the database. docker-compose.yml declares image: postgres with no tag. The documented run-book, docker-compose up -d, therefore pulls whatever latest is on the day you run it — which today is several major versions past anything this code was ever tested against. The single most likely way a reader in 2026 fails to start Inflow is not the code. It is one missing :14.

The documentation drifts without a commit. The estate's only architecture diagram is a PNG on a CDN. The explanations are a knowledge-base site, a YouTube playlist and a paid course. Each of those can change, move or vanish independently of this repository, and git will record nothing.

And the governance surface is what you would expect of a repository that was published rather than maintained: MIT, Copyright (c) 2021 DevMentors — a trading name, stale by a year against a 2022 tip — with zero copyright headers across 496 C# files, no CONTRIBUTING.md, no SECURITY.md, no CODEOWNERS, no issue or PR templates. That is not a criticism. It is the accurate description of an artefact that accompanies a course.

The honest ledger

What this repository does genuinely well, and it is more than the previous ten parts might suggest:

  • The reference graph is clean, exhaustively. Thirty-four ProjectReference edges across twenty projects and not one crosses between modules. The strongest claim in the README, and it holds.
  • Four architectures in one host, staged as a contrast. Two-layer, two-layer-with-a-domain, aggregate-split, full onion — deliberately different so the module boundary reads as the unit of autonomy.
  • The contract registry is a real idea. A boot-time reflective check on locally re-declared message shapes, throwing on drift, defending a failure mode the compiler cannot see.
  • Module enable/disable is dual and it works. One boolean both prevents assembly load and strips the module's MVC application parts, so a disabled module's routes vanish.
  • Users.rest proves the author could build a self-contained request collection. He did. Once.
  • The outbox is complete. Not a sketch — sixteen implemented files, ready behind a flag.
  • The workshop branches are a better teaching artefact than the README. Five commits across one Saturday reconstruct a curriculum: naive, synchronous, asynchronous, contract-verified, end to end.

What it costs a reader, in the order you hit it:

  1. Thirty-seven requests in the shipped collection; nine return a 2xx cold, and eight of those are in one file.
  2. The estate's central demonstration — money reaching a wallet — takes fourteen steps, nine of them invisible, and appears in no file.
  3. GET /payments 404s, and it does so because the architecture claim is true.
  4. The documented path requires an anonymous caller to self-assign the admin role, and nothing records that as deliberate.
  5. The invariant the whole repository is named for is guarded by nothing.
  6. Seven substantial design decisions have no record anywhere a reader will look.

When not to reach for this

Do not use Inflow as a template. It is not one, it never claimed to be one, and the parts that make it a good teacher are the parts that make it a bad starting point — the disabled outbox, the swallowed handler failures, the fixed-string deposit secret, the role on sign-up, the committed signing key in appsettings.json. Every one of those is right for a repository you run on a laptop for an afternoon and wrong for anything else.

Do use it as a reading exercise, which is what it was built to be. The shared framework in particular is worth an afternoon on its own; the companion series The Framework Underneath spends fifteen parts there.

What I would change, in order of cost

  1. A “what this sample deliberately does not do” section. Six bullets, fifteen lines. It converts seven apparent defects into visible pedagogy and it is the highest-value change available to this repository by an enormous margin.
  2. Tag the Postgres image. One line, and it is the difference between the run-book working in 2026 and not.
  3. A root-level walkthrough file. One .rest file that signs up, completes, escalates, verifies, deposits and completes, in order, with variables harvested from responses — the thing Users.rest already demonstrates the technique for.
  4. A twenty-line architecture test, and somewhere for it to run.
  5. A status line in the README. “Last verified against .NET 6, July 2022.” One sentence, and every reader after it calibrates correctly.

Note what is not on that list: rewriting the code. The code is fine. Every one of those five is a documentation or configuration change, and that is the shape of the whole series.

The lesson the repository is

I have read a lot of repositories for this corpus and this one is unusual, because its defects are almost entirely in the layer around the code, and its virtues are almost entirely inside it. The C# is careful. The .csproj graph is disciplined. The one boot-time guard that exists is thoughtful. And a reader following the documented path bounces off four 401s and a 404 in the first minute.

Three rules come out of it, and none of them is about modular monoliths:

A repository's request collection is its real front door, and it must be executable top to bottom on a fresh clone. Not “correct”. Runnable, in order, from empty. Users.rest shows the technique; nothing extends it across the seam.

Organise documentation by the thing being demonstrated, not by the structure of the code. Inflow's .rest files are per-module because everything here is per-module. That is the architecture working as designed, and it is precisely why the estate's own subject — the seam between modules — has no home.

Every simplification you make on purpose costs one line to record, and costs a reader an hour if you don't. An unrecorded simplification is indistinguishable from a bug. The single comment above TryComplete is proof of how cheap the fix is.

Closing four series

This is the last of four series on one repository, and reading it four ways was the point.

The Framework Underneath took the shared mini-framework — the dispatchers, the in-process broker, the contract registry, the outbox that never runs. Five Modules, One Database Each took the domain code, module by module, including the wallet that adds itself up and the saga whose compensations cannot fire. One Module Leaves the Process took the microservices branch and the honest hundred-and-eight-file diff of extracting a module into a service. And this one stayed outside the C# entirely and read the packaging.

Four passes, four different verdicts on the same twelve commits, and they do not contradict each other — which is the argument for reading a codebase more than once, from more than one altitude. The framework series found careful engineering. The domain series found real modelling with real gaps. The extraction series found a seam that held. This one found that none of that reaches a reader who follows the instructions.

Inflow belongs to a family — the same author's DShop, Convey, Pacco and ModularMonolith are all in this corpus, and Inflow is the large sibling of the small teaching monolith, the one that actually ships the extraction the others gesture at. Reading four of them in sequence, the pattern that repeats is not architectural. It is that the code keeps getting better and the artefact around it stays the same size.

The last commit was on a Saturday, four years ago, and it updated seven package versions. It is a good place to stop, and a strange place to leave a document written entirely in the present tense.