Skip to content

CONCEPT Cited by 1 source

Separation of concerns

Definition

Separation of concerns is the practice of organising a system so that each component has a single, well-defined responsibility, and components interact only through explicit interfaces. A change inside one concern should not ripple into others. The term is due to Dijkstra (1974) but the principle is older than the word.

At practical altitudes it surfaces as:

"Separation applies to the whole system"

A recurring insight in production-engineering retrospectives is that separation of concerns applies to everything, not just application code. Slack's Quip/Canvas team articulated this as the core lesson of their 60 min → 10 min build refactor:

Once we understood the problem through the lens of separation of concerns, it became clear we couldn't succeed with changes to the build system alone. We had to cleanly sever the dependencies between our frontend and backend, our Python and TypeScript, our application and our build.

— Slack, Build better software to build software better

And:

The whole system is more than our application code. It's also our build code, our release pipeline, the setup strategies for our developer and production environments, and the interrelations between those components.

Slack identified three couplings that each violated separation of concerns and together produced a 60-minute build:

  1. Backend ↔ frontend: the Python backend's built artifacts were transitive inputs to every TypeScript-frontend bundle, so every Python change invalidated every frontend cache entry.
  2. Python ↔ TypeScript toolchains: Python scripts orchestrated tsc and webpack, fusing two unrelated languages' build pipelines and forcing them to share state.
  3. Application code ↔ build code: build logic was in Python, imported application modules, and ran inside the same process — so a refactor of an application module could break the build, and vice versa.

Each of the three couplings had both correctness and performance consequences.

Why separation of concerns improves performance (not just maintainability)

Slack's refactor is a good case study because the performance lesson is often underweighted relative to the maintainability lesson:

  • Cache hit rate is higher when fewer inputs leak into each unit of work — separation of concerns makes explicit which inputs actually matter. (See concepts/cache-granularity.)
  • Parallelism is higher when units of work don't share mutable state — separation lets a scheduler run them concurrently.
  • Blast radius is smaller when a change to one concern cannot reach another — engineers can reason about the consequences of their changes, which itself accelerates velocity.

The "whole system" inventory

The Slack framing is worth lifting verbatim as a reminder of which concerns deserve separation discipline:

Concern Typical artefacts
Application code business-logic source, app binaries
Build code BUILD files, Makefiles, build rules
Release code deploy scripts, rollback procedures
Setup code Terraform, Ansible, provisioning scripts
Test code fixtures, harnesses, mocks
Observability code instrumentation, dashboards, alerts

Each should be authored, versioned, and evolved with its own lifecycle; couplings between them should be explicit and minimal.

Anti-patterns

  • Build code imports application code. Tempting when both are in the same language; creates a coupling where app refactors break the build. Slack's rewrite-in-Starlark is a defence against this.
  • Deploy scripts with embedded business logic. The release pipeline should not know why a deploy is happening; the application should not know how it's being deployed.
  • Test fixtures referencing production configuration. Makes tests brittle to config changes unrelated to what they verify.
  • One repository, no boundaries. Monorepos are fine, but monorepos without explicit intra-repo separation of concerns (via build graphs, visibility rules, ownership files) collapse into balls of mud.

Seen in

  • sources/2025-11-06-slack-build-better-software-to-build-software-better — canonical articulation that separation of concerns applies to build code, release code, and setup code, not just application code; three specific couplings (backend↔frontend, Python↔TypeScript toolchain, application↔build) producing a 60-minute build and quantitative impact on blast-radius reasoning.
Last updated · 470 distilled / 1,213 read