Domains & teams

·5 min read·Updated

Shared Kernel: When Two Teams Are Better Off Sharing Part of the Model Than Duplicating It

A quote and an invoice need the same calculation. Sharing a library can help, but identical source code does not guarantee identical results across two products.

Two teams build shipment booking and customer billing. In this example, both need the same rule for deriving chargeable weight from measurements. One implementation rounds earlier than the other. The quote and final invoice disagree even when the supplied dimensions are identical.

Extracting the calculation into a shared library sounds sensible. First establish whether the rule really is the same. A quote might deliberately use estimated dimensions while the invoice uses a verified measurement. That difference needs a product explanation, not code consolidation that erases distinct responsibilities.

Agree on a small piece of common meaning

A Shared Kernel is an explicitly bounded part of a model and its associated implementation maintained jointly by the participating teams. Eric Evans's reference emphasises a small scope, consultation over changes and regular integration. Joint ownership is part of the arrangement, not an accidental consequence of installing a package.

For shipping, the kernel might include measurement units, valid ranges and the agreed calculation. Tariff selection, customer-specific discounts and payment terms can remain outside when they have different owners and reasons to change. The boundary is useful precisely because it can reject the next request to “add this while we are here”.

A logging library is not automatically a Shared Kernel: shared technical functionality need not represent a joint domain model. Conversely, a kernel need not consist only of classes in a package. Teams may explicitly share part of a database design, accepting the coordination that changing that design entails.

What exactly is supposed to agree?

Assume the business confirms one rule for identical measurements. Specify precision, conversion order, missing values and boundary cases. Tests using convenient whole numbers may never expose the rounding discrepancy that prompted the work.

Common code cannot make different inputs identical. Booking may have used an estimate while billing has corrected dimensions. Recording the inputs and the rule version for a disputed calculation makes the result explainable. Otherwise “we use the same algorithm everywhere” becomes another obstacle to investigating a legitimate difference.

Someone must resolve disputes about meaning, with both teams assessing the consequences. A maintainer can publish the package without gaining unilateral authority to change a commercial rule for one consumer's convenience. Joint ownership requires time for this work.

A shared package does not require one release for every product

Compatibility can let teams upgrade at different times. A correction that preserves the agreed behaviour can be adopted and verified independently. When an algorithm changes chargeable weight, however, coexistence becomes a product question: are different results acceptable, and which shipments should use the new rule?

Semantic Versioning helps communicate compatible and incompatible changes to a public API. A version number does not prove behavioural compatibility. A method can accept the same arguments and return the same type while calculating a different result.

Choose the transition deliberately. Options include supporting both rule versions with an explicit selection per operation, or enabling the new behaviour after consumers have upgraded. Compare both implementations against agreed examples and track the versions actually running. Automatically taking the latest package is not a migration policy.

Already accepted quotes need a separate decision. A library upgrade does not authorise silently rewriting historical calculations. Correcting an error may require recalculation and communication rules, not merely a new software release.

A shared correction can spread a shared bug. Know the consumers, check a limited set of operations first and be able to stop adoption. Reinstalling the previous library does not repair invoices already produced. Find those results by calculation version and handle them separately. Otherwise the rollback promise covers code but not the consequences of running it.

Sharing a model is not sharing unrestricted data access

Two applications can use the same chargeable-weight type while keeping their operational records separate. A shared package does not require both teams to update each other's tables. Direct writes add another dependency on schema and migration order.

Microsoft's data-ownership guidance discusses how these dependencies affect service autonomy. Here the useful distinction is a jointly maintained rule versus jointly modified state. If a shared table is intentional, negotiate its constraints, migration process and permissions separately.

Nor should the calculation become a network service solely to call it centralised. That creates an operational dependency even as it centralises execution. Sometimes the trade-off is justified; sometimes a compact, versioned package is cheaper. Choose according to consistency needs and what the teams can operate.

When the common kernel stops being common

A year later, one product may introduce a different measurement policy. If every change adds a switch for booking versus billing, revisit the original claim of one shared rule. Limited configuration can be useful; persistent branching on consumer identity suggests the models are diverging.

Coordination cost is another signal. A local improvement waits for a neighbour that does not need it, while a kernel fix requires checking many unrelated scenarios. Compare that burden with two maintained implementations or exchanging an authoritative calculated result. Duplication is not always more expensive than coupling.

A gradual exit can preserve the genuinely shared portion while separating the differing rules and assigning owners. For shipping, the meaningful outcome is explainable agreement where the customer was promised agreement. If the promises differ, the models should be allowed to differ as well.