DRY, SRP, IoC, DI, and Service Contracts
Keep HelixWorks changeable by assigning one reason to change per service and injecting implementations behind explicit contracts.
System map · Day 16
Whole-system design
Five stable layers. Today's work is expanded and linked; the rest stays in context.
Product and authority
Covered — People and product entry points · Identity and policy · Generated application plane
HelixWorks control plane
Source-backed today
Keeps product policy dependent on small ports while the composition root selects concrete adapters.
Delivery and desired state
Covered — Git desired state · CI and immutable artifacts · Argo CD reconciliation
Cloud and orchestration
Covered — Terraform and AWS APIs · Accounts, VPC, DNS, and private paths · Kubernetes or EKS control plane
Compute and traffic
Covered — Worker compute · Generated app workloadsAhead — Ambient mesh data plane
Platform service workloads
Source-backed today
Wires generator, runtime, broker, and evidence clients without leaking transport choices into domain logic.
Storage and evidence
Covered — Evidence and observabilityAhead — Infrastructure state · Cluster desired and live state
Product data and artifacts
Source-backed today
Selects local SQL or cloud artifact storage behind stable repository and store contracts.
The enterprise problem and today’s slice
Enterprise problem: A platform that can generate Research Brief, Service Desk, and Field Inspection applications becomes fragile when shared code means shared ownership, one service controls unrelated jobs, or business logic constructs databases and cloud clients directly. Whole-course context: The customer lifecycle now reaches verified export and retirement; today uses that evidence to draw internal boundaries that can evolve without breaking the lifecycle. Today’s slice: We apply Don’t Repeat Yourself (DRY), Single Responsibility Principle (SRP), Inversion of Control (IoC), Dependency Injection (DI), and contract tests to the control plane, runtime, and generated applications. End-of-day evidence: A service map, interface contract, positive contract test, rejected incompatible implementation, ownership decision, environment, timestamp, source revision, run, and trace IDs show replaceability. Still unsolved: Kubernetes packaging, infrastructure ownership, Terraform, and AWS isolation remain deferred.
Customer outcome and implementation focus
The customer outcome is a reviewable dry, srp, ioc, di, and service contracts change, not a collection of requirements. This day starts with the implementation boundary, then uses the command or manifest below to produce positive, denied, and recovery evidence.
Components in focus
HTTP controllers, domain services, ports, injected adapters, and evidence adapter; service containers; each service owns its database/object evidence; cache: not involved until a measured read path needs it.
This map names the implementation boundary for this day. The service or controller changes only the state it owns; runtime and audit evidence let the operator distinguish a declared change from an effective one.
Wire service contracts at the composition root
Inject an adapter at one composition root
Domain code that constructs AWS clients cannot run locally without cloud coupling and cannot expose its required authority. This labelled excerpt reflects the public monorepo’s actual Python ports and composition root at services/control_plane/app.py and services/control_plane/adapters.py.
def build_controller() -> ForgeController:
database = Database(os.getenv("CONTROL_DATABASE_URL", "sqlite:///.lab/control.db"))
repository = SqlProjectRepository(JsonProjectRepository(database))
artifact_store = S3ArtifactStore(os.environ["ARTIFACT_BUCKET"]) if os.getenv("ARTIFACT_BUCKET") else SqlArtifactStore(Database(os.getenv("ARTIFACT_DATABASE_URL", "sqlite:///.lab/artifacts.db")))
outbox = OutboxPublisher(database, publisher_from_url(os.getenv("BROKER_TOPIC", "http://broker:8080"), SERVICE_TOKEN)); outbox.start()
forge = Forge(repository, GeneratorClient(os.getenv("GENERATOR_URL", "http://generator:8080")), RuntimeClient(os.getenv("RUNTIME_URL", "http://runtime:8080")), artifact_store, outbox)
return ForgeController(forge)
Key takeaways
Good boundaries preserve customer behavior while allowing one owned implementation to change.
- DRY centralises decisions, not every similar line.
- SRP follows reasons to change and ownership.
- IoC and DI make dependencies explicit but never bypass authorization.
Checklist
A service boundary is credible only when ownership and compatibility are testable.
- [ ] Each record and policy has one mutating owner
- [ ] Ports state tenant, identity, idempotency, and failure semantics
- [ ] Composition occurs at a small number of visible roots
- [ ] Breaking contract and unaffected positive control are proven