The onion cut into vertical slices
Pinch or Ctrl+scroll to zoom; the text is selectable.
Source
·
TheYard
The onion cut into vertical slices: the five rings as bands with references pointing inward, four slices cut through every ring, each a folder in the host and in Application and its adapters and rules at the inner rings' roots, the Shared column beside them, the rules the gate holds, and one bid followed through one slice
The onion cut into vertical slices: five rings, one folder name per feature in every ring
Read top to bottom for the rings, which point inward as they always did; read a dashed column for one feature, which now lives in one place in each ring and nowhere else.
TheYard.Api, the host
Features/<Slice>/Module.cs: Register and Map; Program.cs alone at the root; everything shared in Shared/<Concern>/
TheYard.Infrastructure and .Cosmos, the adapters
the same ports answered twice, relational and document, in Features/<Slice>/ or Shared/<Concern>/; only the mapped rows stay at the root
TheYard.Application, the use cases
Features/<Slice>/: one handler per request, one HandleAsync; the auction, the stores and the kept history in Shared/<Concern>/
TheYard.Domain, the rules
pure functions and records, in Shared/Auction or the slice that owns the rule; no clock, no disk, no network
TheYard.Data, the records
zero dependencies, zero behaviour
Shared/, the same in every ring
Activity, Auth, CostReadings
Documentation, Edge, Grades, Hosted
Instance, MachineReadings
Observability, PlanReadings, Proof
Resources, Sites, Stores, Usage, Wire
Wiring
ContextFactory.cs, CosmosStore.cs
OutboundHttp.cs, one pool
AzureMetrics.cs, the host's
StandingReader.cs, the reads
Ports.cs, IStoreDiagnostics
CardFrame.cs, CloudWire.cs
Fnv1a.cs, AuctionSchedule.cs
CardTone.cs, the one tone rule
Features/Bids
Module.cs
BidEndpoints.cs, the wire too
EfBidStore.Standing.cs
CosmosBidStore.Standing.cs
PlaceBidHandler.cs
BidReadHandlers.cs
IBidStore in Ports.cs
BidRules.cs, StandingRules.cs
in Shared/Auction
Features/Vehicles
Module.cs
VehicleEndpoints.cs
VehicleWire.cs, in Shared/Wire
EfVehicleCatalogue.cs
CosmosVehicleCatalogue.cs
VehicleHandlers.cs
IVehicleCatalogue in Ports.cs
VehicleFilter.cs and
VehicleOrdering.cs
Features/Accounts
Module.cs
AccountEndpoints.cs
AccountEndpoints.SignIn.cs
Features/Accounts/
IdentityAccountStore.cs
CosmosUserStore.cs
SessionHandlers.cs
ResetHandlers.cs
AccountPorts.cs
(no rule of its own;
the session is Application's)
Features/Admin/Cloud
Module.cs
CloudEndpoints.cs
SqlCard.cs and every reader
YardModelFacts.cs
the readers' requests go
out through OutboundHttp
ReadCloudCardHandler.cs
ICloudCards, beside it
CardTone.cs, in Shared/Cards
and Admin/Plan, Admin/Operations, Docs, Health, Visitors, each a column like these
inward
only
Held by the gate
the ten ring rules
a slice depends on its
own folders and Shared/
every slice has a Module;
Program.cs maps nothing
one handler, one
HandleAsync, ports by
constructor
no RequestServices,
Environment or
Configuration outside
Program and *Module
sites and stores are
lists; no host or store
literal in the host
only Infrastructure
opens a socket
no typed resource name,
SKU, price or date
One request, through one slice
POST /api/vehicles/{id}/bids. Nothing on this path reads RequestServices, Environment or configuration; the store was chosen once, in Shared, and handed in.
The edge, the host
X-Yard-Host, X-Yard-Store
The name and the store
the request carries.
Shared pipeline
Shared/RequestPipeline.cs
Timing, forwarded headers,
problems, the warm store.
Bids/Module.Map
Features/Bids/Module.cs
The one place this route
is mapped.
BidEndpoints.PlaceBid
Features/Bids/BidEndpoints.cs
Binds the wire, calls the
handler, writes the answer.
PlaceBidHandler.HandleAsync
Features/Bids/PlaceBidHandler.cs
Ports by constructor: the
store, the clock. One method.
BidRules, then IBidStore
Domain/BidRules.cs, EfBidStore
The rule decides, pure; the
adapter writes, Ef or Cosmos.
The slice's tests: BidHandlerTests gives the handler a fake IBidStore and a fixed clock and asserts every outcome BidRules can reach; BidEndpointStatusTests is one integration case per status code.
Adding a slice is one folder in the host and one in Application, and one Module; nothing in Program.cs changes. Removing one is deleting those folders; the gate says what else referred to it.
Until 1.0.4.0 the host was sliced by kind instead: Endpoints/, Composition/, Cloud/ and ninety files at the root. The rings were held; the slices were not, and a feature was spread across all four folders.
Source: docs/images/vertical-slices.svg, drawn by docs/images/vertical-slices.mjs from the Features/ folders, OnionTests.cs and SliceTests.cs. The gate holds every claim on it.