100%

الدرس 2 من 2

Consistency, Drift, and Where Slices Fit

The real cost of slicing is that nothing enforces a shape. This lesson covers the mechanisms that keep sixty slices coherent, and how slicing combines with a modular monolith.

قراءة 9 دقيقة

Layered architecture gives you consistency for free: there is one shape and everyone follows it. Slicing gives that up deliberately, and the consequence is that consistency must be manufactured. Teams that do not manufacture it end up with sixty slices in forty styles, which is worse than the layered codebase they left.

Manufacturing consistency without a service layer

  1. 1

    One pipeline every slice runs inside

    Validation entry point, principal resolution, transaction, error translation, audit. The slice provides its permission and its handler; the pipeline provides everything that must not vary. This is where "uniform where it matters" lives.

  2. 2

    A slice template, not a base class

    A generator or a copyable example that shows the expected file layout and naming. A template can be ignored when a slice genuinely differs; a base class cannot, which is why it becomes the new shared service layer.

  3. 3

    Shared vocabulary, not shared behaviour

    Value types, error types and small helpers with no business rules are safe to share across slices, because they have one reason to change. Anything that encodes a business decision belongs in a slice or in a domain module the slices call.

  4. 4

    A rule about when a slice may not be thin

    Write down the trigger for a slice needing a real domain model: an invariant that spans fields, a rule that will be needed by a second slice, or a calculation with legal significance. Without a trigger, depth becomes personal preference and the codebase drifts.

  5. 5

    Review for the boundary, not for the shape

    The review question is "does this slice reach into another slice?", not "does this look like the others?". Slices touching each other is the failure that matters; stylistic variation usually is not.

Slices inside modules

The two ideas compose: modules give enforced ownership boundaries, slices organise the features inside a module.

Two modules, learning and assessment, each with an enforced public surface. Inside each module are several feature slices. Slices call the shared domain of their own module freely, call other modules only through the published surface, and never call another slice directly.

Module: learning

slice: enrol-learner

slice: complete-lesson

learning domain

shared within the module

Published surfaces

learning/index.ts

the only way in

assessment/index.ts

the only way in

Module: assessment

slice: start-attempt

slice: grade-attempt

assessment domain

shared within the module

That combination is the arrangement most large systems converge on, and it is what this platform uses: modules provide the enforced ownership boundary that makes extraction possible, and slices organise the features inside a module so a feature change stays local. The two solve different problems and neither replaces the other.

In practice

When slicing was the wrong choice

A payments team adopted vertical slices for a card-processing service after a good experience with them on a customer-facing product. Eighteen months later they reversed the decision for the core authorisation path.

Constraints

  • Every slice touching a card transaction is subject to the same compliance rules
  • Eleven slices performed some form of authorisation against the same rules
  • Auditors require evidence that a rule is applied identically everywhere
  • The rules change two or three times a year, mandated externally

Decision

Keep slices for the surrounding features — reporting, disputes, merchant settings — and move card authorisation into a single domain module that every relevant slice calls.

Why

The deciding property was that all eleven copies had to change together, always, for the same externally imposed reason — the must-change-together test answered yes without ambiguity. Slicing is a bet that features vary independently, and in a compliance core they do not. Proving to an auditor that eleven slices implement a rule identically is also far harder than proving one module does.

What it cost

Slices now call into a shared module, so a change to authorisation rules affects eleven callers and needs coordinated testing — the coupling they had been avoiding, accepted deliberately because the alternative was eleven divergent implementations of a regulated rule. They kept the slices for everything outside the compliance boundary, which is the point: the choice is per area, not per codebase.

A team wants to move a layered codebase to slices

As a developer

Plans the migration as a restructuring project: move files, split the service class, land it over a quarter, then build features in the new shape.

As an architect

Plans it as a policy rather than a project. New features are slices; touched features are extracted as they are touched; nothing is moved for its own sake. This converts a quarter of invisible work into a gradual change paid for by feature delivery, and it leaves untouched code alone — code nobody has needed to change is not causing the pain and does not need to move. The risk to manage is a long period with two shapes, which needs one written rule about which applies when.

Your sliced codebase has 60 slices. Eleven contain nearly identical pagination and sorting logic. Should you extract it?Reveal

Almost certainly yes, and it is worth being clear about why this differs from the earlier query example. Pagination and sorting are technical mechanics with no business meaning: they have one reason to change — a change to how the platform paginates — and no slice will ever need a semantically different version of "skip 20, take 20". That is genuinely shared knowledge, so extracting it is correct. Contrast it with the query that selected different columns for different screens, which looked similar and had eleven independent reasons to change. The test is the same in both cases; only the answer differs. And keep the extracted helper free of business rules, because a shared helper that starts making business decisions is how a service layer grows back.

Key takeaways

  • Slicing trades free consistency for locality, so consistency must be manufactured deliberately.
  • A pipeline every slice runs inside is where the rules that must not vary belong.
  • Slices must never call other slices; use a shared domain module or an event.
  • Slices and modules compose: modules own boundaries and data, slices organise features inside them.
  • Slicing is a bet that features vary independently; where a regulated rule must be identical everywhere, that bet is wrong.