Software Architecture Books Summary And Highlights -- Part 7 Interface and Module Design

 

Interface and Module Design 

Highlights

Programming Paradigms

Dijkstra showed that sequential statements could be proved correct through simple enumeration.

The goal is to eliminate GOTO statement

  • Structured programming imposes discipline on direct transfer of control.
    • Allows modules to be recursively decomposed into provable units, which in turn means that modules can be functionally decomposed。
  • Object-oriented programming imposes discipline on indirect transfer of control.
    • Object oriented design is the ability, through the use of polymorphism, to gain absolute control over every source code dependency in the system. It allows the architect to create a plugin architecture, in which modules that contain high-level policies are independent of modules that contain low-level details. e.g. use interface to decouple caller and implement and achieve dependency inversion.
  • Functional programming imposes discipline upon variable assignment.
    • Has no mutable variable.

CLA Part II Starting with the Bricks: Programming Paradigms


Implement domain model with ubiquitous language

The code’s variable name and terms must follow the domain model’s terms.

Object oriented design is good for model based design because it has similar paradigm.

DDD Ch 3 Binding Model and Implementation


SOLID

  • The goal of the principles is the creation of mid-level software structures that:
    • Tolerate change,
    • Are easy to understand, and
    • Are the basis of components that can be used in many software systems.
  • Single Responsibility Principle
    • A module should be responsible to one, and only one, actor.
  • Open-closed Principle
    • If component A should be protected from changes in component B, then component B should depend on component A.
    • The goal is to make the system easy to extend without incurring a high impact of change.
  • Liskov Substitution Principle
    • The LSP can, and should, be extended to the level of architecture. A simple violation of substitutability, can cause a system’s architecture to be polluted with a significant amount of extra mechanisms.
  • Interface Segregation Principle
    • The lesson here is that depending on something that carries baggage that you don’t need can cause you troubles that you didn’t expect.
  • Dependency Inversion Principle
    • the most flexible systems are those in which source code dependencies refer only to abstractions, not to concretions.
    • We want to avoid depending on volatile concrete elements. It is fine to depend on stable ones
      • Don’t refer to volatile concrete classes.
      • Don’t derive from volatile concrete classes.
      • Don’t override concrete functions.
      • Never mention the name of anything concrete and volatile.
      • Use factory class to instantiate interface

CLA Part III Design Principles


Duplication don’t share code if 2 seemingly similar components will be changed at different rates, and for different reasons and become very different in the future

CLA Part V: Architecture


Interface design

Intention revealing interface

If the client developer’s mind is flooded with detail about how a component does its job, his mind isn’t clear to work out the intricacies of the client design.

Name classes and operations to describe their effect and purpose, without reference to the means by which they do what they promise. This relieves the client developer of the need to understand the internals . These names should conform to the UBIQUITOUS LANGUAGE so that team members can quickly infer their meaning. Write a test for a behavior before creating it, to force your thinking into client developer mode.

DDD Ch 10 Supple Design

Design principles:

  1. least surprise: match actor expectation
  2. small interfaces: exchange least amount of information for each purpose
  3. uniform access: avoid leaking implementation details, A resource should be accessible to its actors in the same way regardless of how they are implemented
  4. don’t repeat your self
  5. consistency

SAP Ch 15 software interface

Common anti patterns:

  • Interfaces that are changed frequently
  • Modularity violation: multiple modules are usually modified together
  • unhealthy inheritance:
    • a base class depends on child class
    • a client depends on both base class and child class
  • cyclic dependency in both modules and classes
  • crossing: A file has both a high number of dependent files and a high number of files on which it depends, and it changes frequently with its dependents and the files it depends on.

SAP Ch 23 Managing Architecture Debt


Service interface

Data storage design could influence the model microservice sends to other services. But how the consumers wanted to use the service should drive the design and implementation decisions. So we can design the service interface first and delay the implementation of proper persistence for the microservice, until the interface had stabilized enough.

MSV Ch 4 Integration

DRY more accurately means that we want to avoid duplicating our system behavior and knowledge.

don’t violate DRY within a microservice, but be relaxed about violating DRY across all services. The evils of too much coupling between services are far worse than the problems caused by code duplication

MSV Ch 4 Integration

Increase cohesion

  • split module
  • redistribute responsibilities

This can improve modifiability

SAP Ch 8 Modifiability

Three principles of component cohesion:

  • REP: The Reuse/Release Equivalence Principle
    • The granule of reuse is the granule of release.
    • Classes and modules that are grouped together into a component should be releasable together.
  • CCP: The Common Closure Principle
    • Gather into components those classes that change for the same reasons and at the same times. Separate into different components those classes that change at different times and for different reasons.
  • CRP: The Common Reuse Principle
    • Don’t force users of a component to depend on things they don’t need.
    • classes that have lots of dependencies on each other should be in same component.
  • Trade offs of the 3 principles:
    • An architect who focuses on just the REP and CRP will find that too many components are impacted when simple changes are made.
    • an architect who focuses too strongly on the CCP and REP will cause too many unneeded releases to be generated
    • The 3 principles form a triangle. Your app resides in somewhere of that triangle and position may change depending on different phases of development. In early phase, CCP is prioritized because it makes developments easier. In mature phase, REP and CRP is prioritized to increase reusability.

CLA Part IV: Component Principles


Coupling Two artifacts (including services) are coupled if a change in one might require a change in the other to maintain proper functionality.

SAH ch 1 What Happens When There Are No “Best Practices”

Reduce coupling

  • encapsulate
  • Use an intermediary
  • Abstract common services
  • Restrict dependencies
  • Defer binding e.g. bind something at compile time, deployment time, runtime
    • But late binding is more expensive when implementing.

This can improve modifiability

SAP Ch 8 Modifiability

The acyclic dependency principle

Allow no cycles in the component dependency graph.

This makes each component being released in their own pace and reduce conflict resolution troubles when compiling all the change together.

2 ways to break a cycle:

  1. Apply the Dependency Inversion Principle
  2. Split common dependencies into separate components

CLA Part IV: Component Principles

Top-down design

For components graph, it is hard to do top-down design. Because components are refactored and created during development process depending on real development pattern and needs

CLA Part IV: Component Principles

The Stable Dependencies Principle Depend in the direction of stability.

Any component that we expect to be volatile should not be depended on by a component that is difficult to change.

CLA Part IV: Component Principles

Not All Components Should Be Stable

If we really want to make a stable component depend on an instable component, we can create an abstract component such as interface of that instable component, and make the stable one depend on the interface.

CLA Part IV: Component Principles

The Stable Abstractions Principle

  1. a stable component should also be abstract so that its stability does not prevent it from being extended.
  2. an unstable component should be concrete since it its instability allows the concrete code within it to be easily changed.

CLA Part IV: Component Principles


Small modules

Pros:

  1. Increase speed-to-market
  2. Availability
  3. Scalability

SAH Ch 3 Architectural Modularity


Component boundary

Boundaries are drawn where there is an axis of change. The components on one side of the boundary change at different rates, and for different reasons, than the components on the other side of the boundary.

Some complicated thing can be designed later. Draw the line to cut them out first and use a simple implementation first so that core business rules are immune to their changes.

Full-fledged architectural boundaries are expensive. which means the 2 directions of components dependency are both implemented through interfaces

Maintaining separation in both directions is expensive both in initial setup and in ongoing maintenance.

Alternatives:

  1. define the one direction interface first which is needed now and leave the other unused direction empty.
  2. Facade pattern. In this case, even the dependency inversion is sacrificed. The boundary is simply defined by the Facade class, which lists all the services as methods, and deploys the service calls to classes that the client is not supposed to access.

A boundary is expensive to build. And it is hard to foresee future abstraction need. But when it is needed, it is very expensive to migrate. So you need to make tradeoff and try to foresee by watching the development progress at an ongoing paces.

Your goal is to implement the boundaries right at the inflection point where the cost of implementing becomes less than the cost of ignoring.

CLA Part V: Architecture


How to refactor components? Some interesting approaches…

  • Gather Common Domain Components Pattern
    • Used to consolidate common business domain logic that might be duplicated across the application, reducing the number of potentially duplicate services in the resulting distributed architecture.
    • Multiple functions or classes might share same lib and reside in similar namespaces. The can be consolidated into one
  • “Flatten Components Pattern”
    • Used to collapse or expand domains, subdomains, and components, thus ensuring that source code files reside only within well-defined components.
    • Component A collection of classes grouped within a leaf node namespace that performs some sort of specific functionality in the application
    • Root namespace A namespace node that has been extended by another namespace node.
    • Orphaned classes Classes contained within a root namespace, and hence have no definable component associated with them.
    • The Flatten Components decomposition pattern is used to move orphaned classes to create well-defined components that exist only as leaf nodes of a directory or namespace, creating well-defined subdomains (root namespaces) in the process.
    • Approaches:
      • refactor the code into new components which is created by real function/feature e.g. CreateAction, AssignAction
      • Put orphaned code into a shared or common folder. Use same folder name in whole repo for ease of analysis

SAH Ch 5 Component based decomposition


Explicit objects for implicit concepts

Explicit constraint

When the constraints are obscuring the object’s basic responsibility, or when the constraint is prominent in the domain yet not prominent in the model, you can factor it out into an explicit object or even model it as a set of objects and relationships.

Processes as Domain Objects

The key to distinguishing a process that ought to be made explicit from one that should be hidden is simple: Is this something the domain experts talk about, or is it just part of the mechanism of the computer program?

Specification

A SPECIFICATION is a predicate that determines if an object does or does not satisfy some criteria. Predicate can be composite from other simple spec

We might need to specify the state of an object for one or more of these three purposes.

  1. To validate an object to see if it fulfills some need or is ready for some purpose
  2. To select an object from a collection (as in the case of querying for overdue invoices)
  3. To specify the creation of a new object to fit some need. e.g. print a complicated file with multiple objects.

DDD ch 9 Making Implicit Concepts Explicit


Immutable Objects

Create side effect free functions by moving complex logic into immutable VALUE OBJECTS when a concept fitting the responsibility presents itself.

  1. So you only create, update value objects instead of modifying entity directly to limit side effect
  2. Entity object point to value object. Value object owns the function. The function could create a new value object and return it to replace the current value object in entity.

DDD Ch 10 Supple Design

  • All race conditions, deadlock conditions, and concurrent update problems are due to mutable variables.
  • Immutability is practical if you have infinite storage and infinite processor speed. Otherwise, you need to make compromise. Compromise option
    • 1: segregate the system into immutable objects and mutable parts
    • 2: event sourcing

CLA Part II Starting with the Bricks: Programming Paradigms





Ideal Abstraction and Instability relationship is the main sequence which is easy for decomposition.

Components that fall too far into the upper-right corner enter into what architects call the zone of uselessness: code that is too abstract becomes difficult to use.

Conversely, code that falls into the lower-left corner enter the zone of pain: code with too much implementation and not enough abstraction becomes brittle and hard to maintain

SAH Ch 4 Architectural Decomposition

DB schema and utilities are in zone of pain.

Nonvolatile components are harmless in the (0, 0) zone since they are not likely to be changed.

Consider a component near (1, 1). This location is undesirable because it is maximally abstract, yet has no dependents.

CLA Part IV: Component Principles


Related Chapters

DDD Ch 3 Binding Model and Implementation

DDD Ch 5 A Model Expressed in Software

DDD Ch 6 The Life Cycle of a Domain Object

DDD ch 9 Making Implicit Concepts Explicit

DDD Ch 10 Supple Design (make object easy to change)

DDD Ch 12 Relating Design Patterns to the Model

SAP Ch 8 Modifiability

SAP Ch 15 software interface

SAP Ch 23 Managing Architecture Debt

SAH Ch 3 Architectural Modularity

SAH Ch 4 Architectural Decomposition

SAH Ch 5 Component based decomposition

CLA Part II Starting with the Bricks: Programming Paradigms

CLA Part III Design Principles

CLA Part IV: Component Principles

CLA Part V: Architecture

MSV Ch 4 Integration

Popular posts from this blog

Does Free Consciousness exist ?

Software Architecture Books Summary And Highlights -- Part 1 Goal, Introduction And Index

拉美500年,荆棘丛生的自由繁荣之路