Bassam Ismail
When a Product Brief Wants a New Service Before the System Map Exists
Thought Leadership

When a Product Brief Wants a New Service Before the System Map Exists

7 min read

At the architecture readout, the product brief showed a clean set of customer-facing pages ready for a new Go service. The first preference check broke that picture: only the existing Django application could interpret the value and retrieve it from the profile database. That was where the discussion about microservice boundaries stopped being abstract.

TL;DR

Product grouping does not establish microservice boundaries. Before extraction, identify who owns each capability, which system is authoritative for its data, what happens when dependencies fail, and who carries operational responsibility. A staged decision can preserve current authority while making the cost of latency, replication, or eventual ownership transfer explicit.

The page boundary was not the system boundary

The customer wanted to rebuild several search and discovery experiences. The existing implementation lived in a mature Django application, while the proposed Go service had already received some exploration.

The decomposition looked plausible because the pages shared a customer purpose and could be developed together. Yet a page is a presentation boundary. It does not establish where identity is resolved, which system authorizes preferences, how localized content is selected, who corrects bad data, or where administrative changes take effect.

The dependency inventory exposed the difference. Search behavior relied on data whose authority was not consistently documented. Preferences affected results but remained part of the existing Django application and its profile database. Localization included selection and fallback behavior, not merely translated labels. Administrative workflows and operational procedures were still embedded in the existing Django application.

Routing traffic to the proposed Go service would move an entry point, while authority and failure responsibility remained in the existing Django application. A credible service boundary eventually needs both to move deliberately. During a staged extraction, leaving them in Django can be the safer decision, provided the runtime dependency is explicit.

This aligns with Microsoft's microservices architecture guidance, which describes services around cohesive business capabilities and ownership of domain logic and data. The implementation language matters after the ownership model is credible.

Testing microservice boundaries with one preference read

Consider an explicitly illustrative request. A browser asks the proposed Go service for a customer-facing page. Rendering that page requires one saved preference. The preference is currently owned by the existing Django application and stored in the profile database. The proposed Go service therefore cannot answer independently unless the architecture changes.

ILLUSTRATIVE PREFERENCE READload pageread preferencequeryvaluepreferencepagebrowserGo serviceDjangoprofile DBbrowserGo serviceDjangoprofile DB

The runtime dependency is defensible only when its stage, owner, and failure behavior are explicit.

The smallest stage is a synchronous adapter. The proposed Go service requests the preference from the existing Django application, which remains authoritative and continues to read the profile database. This preserves one source of truth and avoids premature data movement. It also adds network latency and couples page availability to the existing Django application. Timeouts, load limits, error semantics, observability, and degraded behavior become part of the contract.

More runtime autonomy requires a replicated read model. Preference changes could be published and projected into storage available to the proposed Go service. Reads would no longer require the existing Django application to be available. In exchange, the architecture acquires freshness targets, replay procedures, reconciliation checks, schema evolution rules, event-contract ownership, and a policy for missing or out-of-order changes. Engineers would need evidence that the customer experience can tolerate stale values and that the projection can be rebuilt safely.

Transferring ownership is a different class of decision. Moving the preference capability would require a migration plan covering existing records, validation, write ownership, administrative behavior, consent semantics, rollback, and a controlled cutover. Casual dual writes are especially hazardous: if both applications accept authoritative changes, conflicting order, partial failure, and retries create two authorities. Dual writing is defensible only with rigorous reconciliation, an explicit conflict policy, measurable convergence, and a bounded retirement plan.

The review treated these as possible stages, not completed work. The choice turns on required availability, acceptable staleness, migration cost, and whether preference ownership belongs inside the proposed boundary at all.

Turn uncertainty into a decision artifact

When no complete map exists, waiting for comprehensive documentation is rarely useful. Start with the smallest dependable baseline for the decision. Discovery Baselining When Nobody Owns the Whole System Map describes the broader practice. For this decision, the baseline should become a capability-and-boundary matrix.

CapabilityCurrent authorityReads and writesRuntime dependencyFailure responsibilityEvidence requiredStaged disposition
Search presentationExisting Django applicationReads records, identity context, locale, and preferencesExisting application behavior and upstream dataPage degradation, latency, and result correctnessLoad profile, fallback behavior, parity criteriaCandidate for isolated presentation work
Identity contextExisting Django applicationReads identity and authorization stateExisting identity behaviorAuthentication errors, authorization drift, incident escalationStable contract, timeout policy, operator, audit expectationsKeep authority in place
PreferencesExisting Django application and profile databaseReads and writes saved choices and consent-sensitive stateSynchronous adapter or a future replicated modelStale values, failed reads, incorrect writes, reconciliationAuthoritative write path, freshness target, change contract, correction procedureStage the read; do not transfer ownership yet
LocalizationExisting Django applicationReads locale, content, and fallback rules; administration updates contentExisting localization behaviorWrong locale, missing content, fallback mismatchUpdate workflow, cache behavior, fallback parity, operatorPreserve current behavior behind an explicit contract
AdministrationExisting Django applicationWrites managed records, permissions, and audit stateExisting administrative workflowsUnauthorized change, incomplete audit history, support failureWorkflow inventory, permission model, audit retention, support ownerKeep with current authority
Search dataAuthority not yet reduced to one systemReads source records; corrections may originate elsewhereSource and correction pathsStale results, conflicting corrections, incomplete recoverySystem of record, freshness objective, correction owner, recovery procedureDefer ownership decision

The matrix should be challenged row by row. Which value wins when systems disagree? Who corrects it? What must remain behaviorally identical during a transition? What is the availability impact of every synchronous call? Can replicated state be replayed and reconciled? Which operator receives an alert, and what action can that operator take?

An unknown entry is useful because it creates discovery work. An unstated assumption is dangerous because it becomes architecture without a decision. In practice, the hardest conversation is often not about technology. It is asking someone to accept responsibility for a failure mode that previously belonged elsewhere.

A credible assessment of microservice boundaries should produce three outcomes: work that can proceed under current authority, work blocked by missing evidence, and work that requires a deliberate ownership migration. This keeps a page rebuild from quietly absorbing data migration, operational transfer, and administrative replacement.

The readout did not approve a wholesale extraction. It separated presentation work that could continue from dependencies that still needed evidence and ownership changes that required a later decision. The visible architecture became less tidy, but the decision became more honest.

The approach has a real cost. Clarifying authority delays visible delivery, and a synchronous stage creates temporary runtime coupling between the proposed Go service and the existing Django application. Those costs should be stated directly and compared with the operational and data-integrity risks of choosing a boundary that exists only in a deployment diagram.

FAQ

What evidence is needed before extraction?

At minimum, establish the authoritative system for each required value, the read and write paths, behavioral parity requirements, availability and freshness expectations, correction procedures, migration constraints, and named operational responsibility. Evidence should include observed call paths and data flows, not only intended architecture.

Is a shared database acceptable?

It can be a constrained transitional choice, but it weakens autonomy and makes schema changes a cross-boundary event. Direct access by the proposed Go service to the profile database would also bypass behavior and authorization held by the existing Django application. If temporary shared access is considered, define permitted tables and operations, schema-change coordination, security controls, observability, failure ownership, and an exit condition.

How should work proceed when the system map is incomplete?

Map only the capabilities and dependencies needed for the next decision, record unknowns in the matrix, assign evidence owners, and separate reversible presentation work from authority changes. Use a synchronous adapter when its coupling is explicit and acceptable, while gathering the evidence needed to choose replication, transfer, or continued ownership.

A boundary becomes credible when the responsibility on each side is clearer than the box drawn around it.

More to read