Why MIC?¶
MIC grew from pain observed across six production Python services: every service rewrote the same foundation, with variations that eventually made behavior diverge. The Node.js implementation does not copy Python line by line; it verifies that the same guarantees can remain explicit and idiomatic in another runtime.
Problems MIC Solves¶
1. The same foundation, rewritten differently¶
Symptom. Every service owns its route builder, response envelope, and error
mapping. Two services return a domain failure as 400 or 409; another lets it
bubble up as 500.
With MIC. Python uses HttpRouteSpec; TypeScript uses route(). In both
cases, adapters share the contract, envelopes, and canonical mapping. A fix is
made in the library and proved across every supported adapter.
2. Framework details leak into domain code¶
Symptom. Domain code imports fastapi.HTTPException, Express Request, or
a NestJS decorator. Testing without starting the framework becomes difficult,
and switching adapters requires use-case rewrites.
With MIC. Handlers receive validated data and return a canonical MIC result. Domain code knows only its contracts and domain errors. Parity tests then verify that every adapter exposes the same behavior.
3. Service authentication diverges in production¶
Symptom. A shared key is hardcoded, rotation breaks one call, or a token for
service-A is accepted by service-B.
With MIC. ServiceAuthSigner and ServiceAuthVerifier bind each token to
an audience, support controlled rotation, and enforce exact scopes. A
compromised collector remains limited to explicitly granted operations.
4. Flattering tests do not prove the boundaries¶
Symptom. Coverage is high, but error mapping, a correlation header, or the archive that is actually published is never exercised.
With MIC. The Python implementation requires mirror tests with 100% line and branch coverage. The Node.js implementation runs native tests, inspects npm archives, then installs published packages into an empty project and verifies the generated service. Both prioritize public behavior.
5. Services communicate through a shared database¶
Symptom. Two services share one table. A migration from the first can break the second without any change to its code.
With MIC. Each service owns its data. Communication uses signed HTTP, versioned events, or explicitly synchronized read models. See the shared-database anti-pattern.
6. Adding a service consumes domain-delivery time¶
Symptom. The first endpoint arrives after days of copying setup, authentication, health checks, configuration, and repetitive tests.
With MIC. The Python cookiecutter and Node.js
@mic-struct/create-mic-service generate a verifiable service with liveness,
readiness, observability, an example module, and tests. The Node generator also
provides an OpenAPI contract and operator CLI.
Problems MIC Does Not Solve¶
- MIC does not write your domain. Product rules, invariants, and decisions remain in your service.
- MIC does not deploy for you. Kubernetes, Compose, a VPS, and supervision remain infrastructure choices.
- MIC does not write migrations. Alembic, Node.js tooling, and engine-specific SQL remain service responsibilities.
- MIC does not operate observability for you. Logging, metric, and tracing primitives are provided; backends, retention, alerts, and SLOs remain yours.
- MIC is not your infrastructure scheduler. It provides locking, checkpoints, execution tracking, and silence detection; infrastructure triggers and supervises the process.
- MIC cannot make a raw store safe by magic. Organization-scoped relational views fail without context, but the application must inject them everywhere and may add database policies.
- MIC does not replace Python, TypeScript, or their libraries. Pydantic, SQLModel, FastAPI, Node HTTP, and Node frameworks remain building blocks; MIC organizes their boundaries.
The scope, maturity level, and exit strategy are documented separately so silence cannot be mistaken for a promise.
How to Know Whether MIC Is for You¶
You are the target audience if:
- you have multiple Python services, TypeScript services, or both, and they communicate;
- you want the same quality baseline without copy-paste;
- you accept strict contracts and demanding tests as design constraints;
- you want framework portability to be proved;
- you want contracts that humans and machines can read.
MIC will provide less value if:
- you have one isolated service with no external boundary;
- you are exploring a disposable prototype whose shape will change completely;
- you reject strict contracts or tests of error paths;
- you require a framework without a MIC adapter and do not want to write that adaptation.
Start with the Python quickstart or the Node.js / TypeScript quickstart.