One Shop, Every Shape
DevMentors built the same e-commerce shop twice - once as a monolith, once as nine services - with two gateways and two frontends. This series reads the whole estate as one artefact.
77 articles filed under this topic.
DevMentors built the same e-commerce shop twice - once as a monolith, once as nine services - with two gateways and two frontends. This series reads the whole estate as one artefact.
Opening the Terraform Module Catalog with the library's flagship: how an App Service module bundles VNet integration, dual managed identities and Key Vault TLS into a surface app teams can fill in but not opt out of.
The conventions that let one Terraform sample library serve hundreds of Azure deployments - a five-file layout, workspace-indexed environments, pinned golden modules and pipeline-first delivery. Part 1 of a series on Terraform for the Azure estate.
Five executables, zero queues - how an attendance platform coordinated a web app, three Azure Functions and a console job through one SQL database, and what that choice bought and cost. Part 1 of the series.
Thirteen repositories, one umbrella that runs twelve of them, two interchangeable API gateways and a service that watches everything - the Pacco estate read as a system of systems, and the fifteen-part series it earns.
A practical walkthrough of the pipeline that ships this very website: from push to production on Azure App Service, with secrets kept out of the repository and zero manual steps.
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.
The estate's full who-publishes-what matrix, built from the source - and the one broken cell in it. Orders' copied ParcelDeleted event declares the deliveries exchange while Parcels publishes on parcels, so Orders never learns a parcel was deleted, and neither the Pact tests nor the hand-maintained registry can catch it.
Pacco traces every request, scrapes every service every five seconds and ships every log line to Seq - then forgets all of it on docker-compose down, because the telemetry stores are the containers whose volume blocks are commented out. The wiring is exemplary; the memory is the finding.
Pacco's naming system is consistent enough to parse - exchanges are bounded contexts, queue names spell their own bindings, commands and events conjugate in snake_case, and every command has a _rejected twin. Reading the estate as a language, including its irregular verbs and the fact that no grammar-checker exists.
Pacco's umbrella repository contains no code, yet it decides everything about how the estate actually runs - seven compose files in deliberate layers, two PM2 manifests that quietly forget the saga service, a 460-line docker run-book, and a .rest file that is the best onboarding document in the system.
Pacco is thirteen sibling repositories held together by a solution file of relative paths, clone scripts with a dual-branch habit, and 284 package references that all say 0.4.* - coherence by wildcard, with a name-squatted saga library and a README that forgot a repo along the way.
Pacco's Identity service fits its whole auth machinery - JWT issuance, a refresh-token aggregate, Redis deny-list revocation - in about fifteen files, and most of them are right. The three that aren't teach more - a mapper bug that leaves 202 callers polling forever, a dead password check, and a refresh token that never rotates.
Pacco names every control - JWT validation, a Vault, a log scrub-list, admin-only routes - and then a sign-up body chooses its own role, the signing key lives in every repo, Vault is off in Docker and anonymous callers pass every ownership check. A governance read of which shortcuts survive copy-paste.
One JSON blob born at Pacco's gateway rides the Correlation-Context HTTP header into services and the message_context AMQP header across the bus, surfacing in SignalR pushes - carried by a class copy-pasted into eleven repos and a broker that forwards exactly one header.
Pacco's async gateway answers a POST with two names - the ID a resource will have and the operation that tracks whether it ever gets it. Following both through the Redis state machine, the saga header override and the per-user SignalR push, warts and all - a five-minute memory, a 404 with three meanings, and a status API anyone can read.
Pacco's Operations service narrates the estate twice - once over SignalR with a JWT handshake and per-user groups, once over a gRPC stream with no auth, no filtering, a per-call event-handler leak and a blocking Take. Same data, same service, two security models.
Pacco ships a second API gateway built on Ocelot that hand-rolls everything the Ntrada YAML declares - auth bypass, async bus routes, edge-minted IDs, correlation headers - plus the estate's only circuit breakers. It is instructive, revealing, and deployed by absolutely nothing.
Pacco's Ntrada gateway is ninety lines of C# and five hundred of YAML, and swapping one route key - use downstream for use rabbitmq - turns the same HTTP surface from a proxy into a bus publisher answering 202. The two compose files disagree about which one you get.
Pacco's Operations service listens to all eighty messages in the estate while owning zero contract classes - it reads a JSON registry and forges the CLR types at runtime with Reflection.Emit. The estate's answer to the shared-contracts problem, and the drift it cannot see.
Thirteen repositories, one umbrella that runs twelve of them, two interchangeable API gateways and a service that watches everything - the Pacco estate read as a system of systems, and the fifteen-part series it earns.
The retrospective that closes three series on DShop - the whole map drawn once, the services wired into nothing, the skew across seventeen repos, and what reading someone else's estate end to end actually teaches.
DShop.Api ships three Dockerfiles - plain, multistage, and multistage.advanced - as a teaching ladder. The top rung is broken, and all three share an ENTRYPOINT that quietly defeats graceful shutdown.
DShop wires Serilog, App.Metrics and Jaeger through one shared kernel, propagates a trace span on the message envelope, and hangs its Consul health check on an endpoint no controller defines. A tour of pre-OpenTelemetry observability.
DShop.Blazor is a Blazor 0.7 preview app whose naive choices - component classes as singletons, a silent auto-signup, a shared HttpClient - all work because of the runtime they run on. A study in patterns that are only correct by accident.
DShop.Web is a well-structured Angular 6 SPA whose plumbing leaks at every joint - an auth header discarded, PUT and DELETE that both GET, a paged result that starts empty. A tour of bugs that only survive because nobody ran the code.
DShop has an Angular 6 SPA and a Blazor 0.7 WASM app over the same gateway. One has the right architecture and broken plumbing; the other has naive architecture and a working shop. The contrast is the lesson.
DShop runs a whole SignalR service to push operation results to the browser in real time - JWT handshake, per-user groups, Redis backplane. No frontend connects to it, and both UIs sleep through eventual consistency instead.
DShop's gateway answers a write with 202 Accepted and a header pointing at an operation that hasn't happened yet. Reading the contract shows a clean async-REST design - and two small bugs that undercut it.
DShop puts all its authorization at the gateway and none in the services behind it - then publishes every service port to the host. The compose file quietly defeats the entire security model.
DShop.Api.Next rebuilds the whole code-first gateway as Ntrada configuration - a 17-line Program.cs and a folder of YAML. Reading both side by side shows exactly what you trade when a gateway becomes data.