Cisco 350-901 DEVCOR/AUTOCOR study materials
Cisco 350-901 DEVCOR/AUTOCOR study resources

Extracting the First Service from a Shared-Schema Monolith

Cisco 350-901 DEVCOR/AUTOCOR · Put your knowledge to work in context.

All case studies

Extracting the First Service from a Shared-Schema Monolith

Your team runs a 14-engineer Django monolith on Kubernetes serving 2,400 requests/second at peak. Six teams deploy from one repository; a change to the billing module still requires a full regression run, and the integration suite fails 18% of runs, concentrated in checkout where tests share a database and depend on wall-clock time. A 90-day initiative wants 'microservices', but the CEO has ruled out a feature freeze and the SLA is 99.95%. Postgres is a single shared schema: orders, inventory, and billing tables are joined in 23 places, and circular imports between orders and inventory block any clean split. Deployments take 47 minutes because every service must be rebuilt together. Two teams already maintain long-lived branches that diverge for weeks. You have one platform engineer and no budget for new managed services beyond the existing Kubernetes cluster and Postgres.

1. You must choose the first extraction seam. Compare extracting inventory versus billing, and justify a choice using coupling, transaction boundaries, and rollback risk.

Read the worked answer

Choose inventory, but only after breaking the orders-to-inventory import cycle with an anti-corruption layer and domain events. Reasons:

  • Transaction boundaries: billing touches money. Extracting it first would force sagas or distributed transactions on day one, with double-charge and reconciliation risk. Inventory is read-mostly and can tolerate seconds of staleness.
  • Coupling: inventory has a narrower API surface (reserve, release, query) than billing, so a strangler facade is testable. The 23 joins are a real constraint, but inventory reads can be served from a facade while the monolith keeps writing.
  • Rollback: rollback for inventory is a routing change behind a feature flag. Rollback for billing is a financial correction process, which is the highest-cost failure mode.

Sequence: put a facade in front of inventory, dual-write through a transactional outbox, compare reads, migrate writes in a maintenance window, then revoke the monolith's direct table permissions. Success criteria: zero cross-schema joins from the new service, a p99 latency budget, and a tested route-back flag. Do not start with a 'microservice' that shares the database and call it done; that preserves the coupling and adds a network hop.

2. The integration suite fails 18% of runs. Design a testing strategy that reduces flakiness and still catches cross-module contract breaks during the extraction.

Read the worked answer

Flakiness at 18% is a signal problem, not a reason for more end-to-end tests. Fix determinism first: give each test worker its own schema or transaction, inject a clock instead of calling datetime.now(), seed random generators, and replace live network calls with recorded contract stubs. Quarantine the remaining flakes with an owner and a 10-day fix SLA; deleting them hides coverage but leaving them erodes trust.

Then add consumer-driven contract tests between orders and inventory: the consumer publishes expectations, the provider verifies them in CI. This catches the break that unit tests miss without requiring a full environment. Keep a small suite of critical end-to-end journeys (checkout, refund) and run them after deploy, not on every commit. Add schema migration tests using expand/contract, because the shared Postgres is the real coupling. Track two metrics: flake rate per test and contract verification failures. A green pipeline that lies is worse than a slower one that tells the truth, especially when the SLA is 99.95%.

3. Recommend a branching and release model for the 90-day period. Explain how it interacts with the 47-minute build and the no-freeze constraint.

Read the worked answer

Move to trunk-based development with branches living under two days and feature flags for incomplete work. Long-lived branches made the integration problem worse: the 23 joins and circular imports mean every branch merge is a semantic merge, and a 47-minute full rebuild discourages small merges.

Build once per commit, tag the artifact with the commit SHA, and promote that same artifact through environments; do not rebuild per environment. Split the monolith build with path filters so only affected test suites run, but keep a nightly full regression. Use expand/contract migrations: add column, dual-write, backfill, switch reads, then drop. Release behind flags with a canary at 1%, 10%, 50%, watching error rate and p99. The 99.95% SLA argues for small blast radius, not for a freeze. Rollback is flag-off plus a compatible schema, so never ship a destructive migration in the same release as the code that stops using the column.