Skip to content
academia.sh

Course Intermediate

Design Principles

By the end of this course

Start course

01

SOLID

The measurable counterparts of five design principles: a module's number of reasons to change, the lines changed and added when a new tariff type is added, a class that breaks the subtype contract failing a contract test, the number of methods a client calls against the number an interface imposes, and which side an abstraction is defined on.

  1. 01 Single Responsibility Principle Counting a module's number of reasons to change with an actor table: comparing a single module that carries three different actors' decisions against a design with the decisions separated, and measuring whether an accounting-driven change leaks into the operations report by counting output lines.
  2. 02 Open–Closed Principle Measuring a design that is open to extension and closed to modification: a new tariff is added both to the version where the same tariff type is chosen through two separate switches and to the version where tariffs write themselves into a registry, and the number of existing files edited, the number of lines added, and whether the fee module changed are compared.
  3. 03 Liskov Substitution Principle Defining the subtype contract through preconditions and postconditions: running a contract test that operates through the supertype against every tariff in the registry, two tariffs that strengthen the precondition and weaken the postcondition breaking the test, and satisfying the same requirement without breaking the contract.
  4. 04 Interface Segregation Principle Counting the cost a bloated carrier interface imposes on clients: scanning and comparing the number of methods each client genuinely calls against the number of methods the interface imposes, measuring the total method count in fake dependencies, and finding with a run how many fakes break when a ninth method is added to the interface.
  5. 05 Dependency Inversion Turning which side an abstraction is defined on into a number: counting the direction of the import edges between the rule and carrier packages across three versions, measuring the contract's owner and its number of incoming edges, and testing with a run whether the rule module can load without the carrier package.

02

Coupling and Cohesion

Counting the strength of the bond between two modules and whether the parts inside a module belong together: types of coupling, the cohesion measure, the law of Demeter, the tell, don't ask principle, command–query separation, isolating axes of change, the cost of binding to a concrete type, and inversion of control.

  1. 01 Types of Coupling Counting the strength of the bond between two modules: writing a script that measures the number of shared names, the number of parameters passed, and the state modules change in common, then comparing the measurements across three designs that produce the same invoice line.
  2. 02 Cohesion Counting whether the parts inside a module belong together: clustering functions by the module-level names they touch, computing the component count against the number of function pairs that share nothing, splitting a low-cohesion module and repeating the measurement, and showing that the split produces no new coupling edge.
  3. 03 Law of Demeter Limiting chained access: writing a scan that counts access chain depth, comparing the finding count in two designs that produce the same five outputs, and measuring how many files get edited when the address record is restructured.
  4. 04 Tell, Don't Ask Moving behavior into the data: comparing a design where four clients each build the same dispatch rule with a design that tells the object the decision, counting the number of files that know the rule's fields, measuring the clients' divergent result set, and finding the number of files edited when the rule changes.
  5. 05 Command-Query Separation Separating operations that change state from ones that only read it: writing a scan that finds methods which both write and return, counting how many records a report-only path changes, and showing with a run that a log line writes the opposite of what actually happened.
  6. 06 Encapsulate What Varies Isolating axes of change: deriving the file sets touched by two changes coming from the price list and output format axes, counting their intersection, and showing that a layout which pulls each axis into its own module drives the intersection to zero.
  7. 07 Programming to Abstractions Counting the cost of binding to a concrete type: comparing the number of files edited and lines touched in two layouts when a second price list is added, finding the number of places that make the choice, and showing that a fake price list only takes effect for the client bound to an abstraction.
  8. 08 Hollywood Principle Reversing the direction between caller and callee: comparing an arrangement where three separate callers write the step order against one where the steps register themselves with a skeleton, counting how many files know the order, and measuring the files edited and lines touched when a new step is added.

03

Boundaries and Component Principles

Separating stable policy from changeable detail, narrowing the contract surface between modules, putting an outside tool dependency behind an adapter, extracting the component boundary from files that change together, measuring component stability, and finding cycles and layer violations in the dependency graph.

  1. 01 Policy and Detail Separation Separating the stable rule from the changeable detail: extracting the number of changes per decision from a shipping fee library's change log, counting file touches under a single-file and a split layout, and showing that the split does not change behavior.
  2. 02 Drawing Boundaries Measuring the contract surface between modules: the number of names exposed, the number of fields crossing the boundary, and the number of names the other side must know; comparing a wide and a narrow boundary definition with the same measure, and testing which side breaks when internal naming changes.
  3. 03 Keeping Framework Code at Arm's Length Isolating a framework dependency: counting, under two layouts, the files that touch a small external tool's contract; comparing how many files must be fixed in each layout when the tool's contract changes; and measuring the adapter's cost in files and lines.
  4. 04 Component Cohesion Principles Extracting the component boundary from files that change together: computing the co-change count from a change log, clustering files by a threshold, and comparing the directory split with the co-change split by component count, republish count, and files bound to a capability.
  5. 05 Component Coupling Principles Measuring the direction of the bond between components: computing the instability metric from fan-in and fan-out, counting edges that do not flow in the stable direction, deriving a release order with topological sort, and showing how a single import into the stable core makes ordering impossible.
  6. 06 Dependency Graph Health Extracting the import graph from source files and auditing it at the component level: listing cycles by name with a depth-first search, counting edges that violate layer order, showing what a cycle looks like at runtime, and confirming both numbers drop to zero after the repair.

Start typing to search.

↑↓ Esc navigate · open · close