Cartography of a Successor
The series retrospective - what fourteen parts of reading Pacco as a system of systems actually taught, the absences the estate confesses when you list them together, how the successor evolved past DShop and where it stopped, and what the MIT licence makes of all of it.
Fourteen parts ago I claimed that some findings can only be made by reading an estate — not a service, not a framework, but the connective tissue: compose files, gateways, headers, manifests, naming conventions. The claim is now testable, because every finding this series led with lived in exactly that tissue. The gateway that changes transport depending on which compose file you ran (part 1, part 3). The saga service missing from the PM2 manifests (part 11). The event bound to the wrong exchange (part 14). None of these is visible from inside any single repository, and none would surface in a code review scoped the way code reviews are scoped. This closing part is the retrospective the estate has earned: what it teaches, what its absences confess, how it evolved past its predecessor, and what its licence makes of both.
What the estate genuinely teaches
Credit first, because Pacco — the MIT-licensed teaching estate by DevMentors (Piotr Gankiewicz and Dariusz Pawlukiewicz, github.com/devmentors) — contains more real distributed-systems thinking than most production estates I have read.
The async-REST loop is complete. Edge-minted resource ids, 202 with an operation handle, a Redis state machine with a saga override, per-user SignalR push — part 5 traced a full, working answer to “what does asynchronous REST feel like to a client”, the diagram every conference talk hand-waves, running end to end.
Identity travels as data. One correlation blob born at the gateway, carried by HTTP header, AMQP header and SignalR group, so every service consumes identity second-hand instead of re-deriving it (part 7). The copy-pasted class that carries it is the tax; the design is right.
The estate has a nervous system. Operations subscribing to ~70 messages via types emitted at runtime from a JSON file (part 2) remains the single cleverest artefact in the thirteen repos — a genuinely original answer to the shared-contracts problem, workable because the watcher never reads message bodies.
Configuration can be architecture. A ~90-line gateway whose entire behaviour — routing, auth, and even which transport a request becomes — lives in YAML (parts 3–4) is a sharper lesson in the code/config boundary than any essay on the subject.
Names can carry the map. The grammar of part 13 — exchange per context, queues that spell their own bindings, _rejected twins — kept thirteen hand-synced repositories legible with no registry at all. And the umbrella's executable onboarding (part 11) turns the whole domain into a file you can run.
The absences, read together
Each gap got a paragraph somewhere in the series; listed side by side they stop being trivia and become a posture. What the estate does not have:
| Absence | Where it bit |
|---|---|
| No Kubernetes, no IaC — compose and PM2 only, under a “cloud-agnostic CNCF” pitch | the platform diagram describes an estate the repos cannot deploy |
| No estate-level CI — twelve independent pipelines, none for the whole; the umbrella repo, which defines the estate, is the one repo with no CI at all | nothing ever compiles, composes or smoke-tests the thirteen repos together (part 10) |
| The Ocelot gateway — built, tested, pushed to Docker Hub, never composed | the estate's only circuit breakers live in the gateway nobody runs (part 4) |
| Operations' Mongo — registered in DI, configured in appsettings, used by nothing | the “operations API” is a five-minute Redis cache impersonating an audit log (part 5) |
The Ntrada .schema validation files — referenced in YAML, never committed |
request validation is configured intent with no artefacts (part 3) |
No API versioning — no /v1, no header scheme, while swagger config says version: v1 |
every contract change is a breaking change with no migration lane |
No health checks in compose — services expose /ping and Consul uses it, but compose relies on restart: unless-stopped alone |
the orchestrator that starts the estate cannot tell whether the estate is up |
The pattern across all seven: the estate consistently builds the shape of a discipline and stops before the discipline's enforcement point. A secrets manager, disabled where it matters (part 8). Observability, without memory (part 12). Contract copies, without a cross-check (part 14). A registry, validated by nobody. For a teaching estate this is arguably the correct trade — each absence is one lesson deferred to keep the running system approachable — but nothing labels the stopping points, and samples travel: the compose files and appsettings get copied into systems that are not samples, and the absences ride along silently. If I could add one file to the estate it would not be code; it would be an honest PRODUCTION-GAPS.md.
What the successor evolved, and where it stalled
Pacco is the successor to DShop, the same authors' earlier teaching estate, and reading them as two editions makes the evolution measurable. The shared messages package that calcified in DShop became copy-per-consumer contracts — decoupling bought at the price part 14 invoiced. The code-first gateway became configuration-first Ntrada, with the code-first approach demoted to the undeployed Ocelot comparison. DShop's dedicated SignalR service folded into the Operations aggregator, which doubled its push surface with gRPC — half of which never worked in Docker (part 6). And DShop's two full frontends became none: the .rest scenario file replaced the UI as the demo surface, a deliberate narrowing that made the estate's backend lessons denser.
Where it stalled is just as instructive. Estate coherence is still a branch convention and a floating wildcard — 0.4.* everywhere, no lock, no snapshot of SHAs that worked together — the exact flaw the predecessor had, carried forward unfixed (part 10). The identity of “the estate” still lives in three disagreeing registries (README, clone script, GitHub). Successors, it turns out, evolve what their authors found painful and inherit what they had merely normalised. The domain-side half of this verdict — rich rules over demo-grade data — is the sibling series' retrospective, rich rules, demo-grade data.
The MIT posture
Last, the licence, because it frames everything above. Eleven of the thirteen repositories carry an MIT LICENSE (© 2019 DevMentors); Pricing and Vehicles simply lack the file — presumably an oversight, but strictly speaking two of the thirteen repos ship with no licence at all, which in a copy-me estate is its own small contract-governance finding. The MIT posture is what makes this series possible and fair: the authors published a full estate, warts deliberately included, for people to read, run and copy. That generosity is also precisely why the honest ledger matters. MIT means the dev-mode Vault token, the commented-out volumes, the copied [Message] attributes travel wherever the code is copied — the licence transfers the code and quietly transfers the posture. Read estates like this one with gratitude and a red pen in the same hand; the gratitude without the pen is how sample defaults end up in production.
When to read it, and how
My closing recommendations, in the spirit of the series:
- Read Pacco if you want to see event choreography, gateway design, correlation and async REST wired together at honest scale — it is the best free system-of-systems reading I know for .NET.
- Run it with the umbrella's two-step compose bring-up and the
.restscenario; expect the era (netcoreapp3.1, dead Travis badges) and read the ideas, not the package versions. - Copy patterns, not files. The 202 loop, the grammar, the correlation spine, exchange-per-context — take them. The appsettings, compose files and copied contract classes carry the absences listed above; every one needs its enforcement point added before it earns production.
- Steal the two best artefacts outright: the executable scenario file as onboarding, and the idea (not the implementation) of a machine-readable message registry — then validate it, which is the step the estate leaves as an exercise.
Fifteen parts: two gateways, one nervous system, an umbrella, a spine, a grammar, a map with a broken cell, and an estate that taught most by where it stopped. The cartography is done; the territory is github.com/devmentors, and it is worth your own expedition.