Episode 17 – Component Coupling

Clean Code

Episode 17

This episode talks about how components should depend on each other.

  • Overview
    • Acyclic Dependencies Principle
    • Stable Dependencies Principle
    • Stable Abstractions Principle
  • The Acyclic Dependencies Principle
    • Cyclic module cause those module to force to release at the same time
    • Solution is either split the component out or use dependency inversion
  • The Stable Dependencies Principle
    • Stability is something that is hard to change.
    • A component should depend on something more stable
    • Stability correlates with number of incoming dependency and inversely correlates to number of outgoing dependency.
  • The I metrics
    • I metrics = Fan-out / ( Fan-in + Fan-out )
    • All dependency arrow point toward decreasing I.
  • The Stable Abstractions Principle
    • Use open-close principle for the module at the bottom of the dependency.
    • The more stable a component, the more abstract it should be.
    • Abstract number = number of abstract classes / number total classes
    • A + I = 1
  • Distance
    • D = | A + I | – 1
    • Zone of uselessness is where there many abstraction but nothing using it
    • Zone of pain is there are too many concrete classes depend on each other
    • Distance metric between zone of uselessness and zone of pain
  • References

Episode 16 – Component Cohesion

Clean Code

Episode 16

This episode talks about how components should work together.

  • Overview
    • Release Reuse Equivalency Principle
    • Common Closure Principle
    • Common Reuse Principle
  • Cohesion
    • What is inside a component? The pieces is functions and the force to bind them is cohesion
  • False Cohesion
    • A group class work together to achieve a common goal is not a good reason to bind them together as a component.
    • Base class and their derivative are often package into separate component, with class that use base class package with the base class.
    • When one class polymorphic uses another class, those classes should be separate into different components.
    • Goal is interdependent deployability
  • Release Reuse Equivalency Principle
    • The granulate of reuse is granulate of release, you can’t reuse a component unless the author is willing to manage it thru a release cycle
    • You want a few strategic components instead of managing hundreds of tiny components
  • Common Closure Principle
    • Component don’t cross boundary
    • When requirement change, best outcome is one component per layer changes.
    • Minimize the number of component change when requirement changes.
    • The classes we grouped together should be closed to the same kind of changes.
    • We gather the classes that change for the same reason and separate the classes that changes for different reason.
    • This is similar to interface Segregation Principle
    • Those class that group into a component should have same responsibility, serve the same actor.
  • Common Reuse Principle
    • Group together classes that are using together, separate classes that are not. In another word, when you use a component, you use all the classes within that component.
  • The Tension Diagrams
    • CRP & REP → component affected by many responsibility
    • CRP & CCP → component aren’t reusable
    • CCP & REP → component are needlessly affected
    • As project mature, it moves from CRP & CCP to REP.
    • Component partitioning changes with project maturity
  • References

Episode 15 – Solid Component

Clean Code

Episode 15

This episode gives an overview of the component principles.

  • What is a Component
  • Relocatable Module
    • The creation of linker to link the subroutine library and create executable binary
  • Explosion of Libraries
    • Application call subroutines
    • Framework call applications
    • Dependency inversion of Framework and Application
    • Framework → flow of control → Application
    • Application → source code dependency → Framework
  • Linker’s Demise
    • Component is an independent deployable library (dll, gem, or jar)
    • Independent deployable mean change in one doesn’t cause another to recompile or redeploy.
    • The key is Application depends on Subroutine and Framework but not the other way around.
  • Coffee Maker Requirements
    • void setBoiler(bool);
    • void setWarmer(bool);
    • void setValve(bool);
    • void setLight(bool);
    • bool getBoiler();
    • int getPlate():
    • bool getButton();
  • The Architect’s Solution
  • A Real Design
    • Apply Single Responsibility Principle first
    • Who is the actor?
    • Brewer, Hot Drinker, Now Drinker
  • High Level Modules
    • Three Actors means at least 3 modules. One Module per Actor
    • Describe abstract purpose of component because High level module should not depend on low level details.
  • Methods and Relationships
    • Examine the methods and relationships of the modules by moving up and down the abstractions.
    • First, the actor send a start message to UI module.
    • Then, if UI not brewing? and HotWaterSource & ContainmentVessel ready? then send start message to HotWaterSource
    • This shows there is a start method for UI and HotWaterSource and ready?method for HotWaterSource and ContainmentVessel.
  • Brewing Begins
    • When the pot is removed, ContainmentVessel send suspend message to HotWaterSource
    • When the pot is replaced, HotWaterSource send resume message to ContainmentVessel
    • The take away is that message being send between module on high level abstraction
  • Implementation
    • Use Open-Close Principle
    • Creating a derivative for each of the modules.
    • Main call the derivative.
  • Components
    • All the dependency crossing from main to the application is pointing inward to the application
    • Benefit from good component design: Interchangeability, Interdependent deployability, the physical separation from high level policy to low level details.
  • Conclusion
    • Component Cohesion
    • Component Coupling
  • References

Episode 14 – Solid Summary

Clean Code

Episode 14

This episode reiterates all five SOLID principles.

  • Requirement and Use Cases
    • Use Case List (action)
    • Entity List (subject)
    • Building the data dictionary to support the requirement
  • The Single Responsibility Principle
    • Looking at which module belong to which actors
  • Diagrams and YAGNI
    • Diagram is usually using by communicate thought process and become obsolete
    • YAGNI – You ain’t gonna need it.
    • Separate each module to only one actor.
  • The Open-Closed Principle
    • Controller should not depend on the details of the data structure
    • Using Builder, Factory, and Interface to decouple the controller from the data structure and use cases.
  • The Liskov Substitution Principle
    • Don’t put a method in an interface that does apply to all the derivatives.
    • Only ok when all the methods of a derivative do nothing, then you have an null object pattern.
  • The Interface Segregation Principle
    • Violation indicated by the growing fan in from the controllers to the use case and the builder.
    • Let the use case Factory makes the controller by passing the type of controller it will use. This is dynamically create the controller.
  • The Dependency Inversion Principle
    • High level policy should not depend on the low level details
    • The algorithms should be generic without the details
  • Conclusion
    • Use these principles but use engineering judgement.
  • References

Episode 13 – The Dependency Inversion Principle

Clean Code

Episode 13

This episode talks about the Dependency Inversion principle.

  • Dependency Inversion Begins
  • Independent Deployability
  • What is dependency
    • Run Time Dependency exist whenever two module interact at run time.
    • Compile Time (Source Code) Dependency exist when a name is define in one module but use in another module.
      • If Module A uses the name from Module B, then you can’t compile Class A only, you must also compile both A and B because Class A depends on Class B.
  • Structured Design
    • A top-down methodology by start with main and design what main should call and so on down the tree.
    • The source code dependency follows the same path as the run time dependency.
  • Dependency Inversion
    • The purpose is to have source code dependency going the opposite of the run time dependency path.
    • The solution is polymorphism.
    • Example,
      • A –> B [+f()], if A call f() in B, then A has both run-time and source-code dependency on B.
      • A–> Interface[+f()] <– B [+f()], insert an interface between A and B by having A uses the Interface while B implement it. Then A has run-time dependency on the Interface but not compile time dependency. And B has source-code dependency on the Interface.
  • Plugins
    • Dependency Inversion create a boundary for the software. We want all the dependency across the boundary are pointing to the same direction, the application.
    • This is by creating plugin that depend on the application.
  • Architectural Implications
    • High level policy should not depend on low level details
    • Low level details should depend on high level policy.
    • High level like use cases.
    • Low level like web pages and database.
    • Therefore, design the low level details as plugin to the application.
  • A Reusable Framework
    • Building the reusable framework should be done parallel between those application that uses it.
  • The Inversion
  • Independent Developability
    • Developers can work separately without interfere each other’s module.
  • Dependence Inversion Example
  • The Furnace Example
  • Plugins
  • References

Episode 12 – The Interface Segregation Principle

Clean Code

Episode 12

This episode talks about the Interface Segregation principle.

  • Interfaces
    • Example: A light switch
    • switch —>> Interface <|—- light
    • The interface is couple with the switch more than the light object. Should call switchable.
    • Interfaces have more to do with the class that use them then the class that implement them.
           /--- D1 <---\
B (v) <---|             |--- M
           \--- D2 <---/
  • The Interface Rant
    • Deadly diamond of death
    • M could either have one instance variable v or two coming from each D1 and D2.
  • Fat Classes
    • The main class multiple inheritance many interface classes. Isolate fat classes by isolated each client specific interfaces and deploy them separately and able to develop separately.
  • The ATM example
  • Physical Structure
    • Ensure you don’t depend on method that you don’t call, otherwise, unnecessary coupling.
  • Factory
  • Dynamics and Injection
    • Dependency Injection
    • Main should create the messenger instance, all of the interactors, and main should takes the interactors and pass them across the boundary to the application.
  • The Need to know
    • Don’t force the user to depend on thing that you need
  • References

Episode 11 – Liskov Substitution Principle

Clean Code

Episode 11

This episode talks about the principle govern inheritance, polymorphism and subtyping.

Part 1:

  • Type Theory
    • “This statement is false” is a paradox.
  • Types
    • Solution is typing to avoid paradox loop.
  • What is a Type?
    • A Type is a bag of operations and how the data is stored is not matter to us as long as the operation is done correctly.
    • Similar to a class, a class is nothing but its methods and the data is hidden as private.
  • Subtypes
    • A subtype relationship of described point as a subtype of point is when described point can be cast into point but not visa versa.
  • Liskov & subtypes
    • What is wanted here is something like the following substitution property: If for each object 01 of type of S there an object 02 of type T such that for all programs P defined in term of T, the behavior of P is unchanged when 01 is substituted for 02 then S is a subtype of T.
  • Duck typing
    • Invoking method vs Send Message (Static vs dynamic language)
  • Refused Bequest
    • Refused Bequest is when an object invoke a method or send a message that is not expected.
    • Exception and side effect by the subtype that the base type didn’t expect
  • The Representative Rule
    • Rectangle and subtype Square with setHeight and setWidth vs setSide
  • Refused Bequest!
    • When program setHeight on an object of square, there is an undefined behavior of how to handle a setHeight in a square.
  • Latent OCP Violation
    • Dependency will be created when fixing the problem by checking if a Rectangle is a Square in the program. This is a violation of Open Close Principle.
  • Solution
    • Treat square and rectangle completely different type.
  • The Representative Rule
    • Representative does not share the same relationship of the objects that they represent
  • Number
    • Integer is subtype of Real and Real is subtype of Complex
    • However, complex number has two parts of Real number, one for the real value, and the other for the imaginary.
    • In programming, this complex and real relationship will create a recursive definition similar to the paradox at the beginning of the episode.
    • This is an example where real world model does not work with a computer representation
  • Lists
    • If S is subtype of T, List of S is not a subtype of List of T
    • For example, a Circle is a subtype of Shape but List of Circle is not a subtype of List of Shape because a List of Shape could include Rectangle, Square and other Shapes.

Part 2:

  • Heuristics
    • If base class does something, the derived class must do it too in a way that does not violate the expectation of the caller. This is appearance when a derived class throw an unconditional exception for a method or override with an empty method that the base class implemented.
    • Another indicator is the usage of if instanceof is being used.
    • Only use instanceof when you know the type to help the complier.
  • Typecases
    • The use of if instanceof can lead to additional else if instanceof and should replace with polymorphic dispatch.
  • Statics vs Dynamics
    • Dynamics language use TDD to help with type checking
  • Design by Contract
    • invariant, precondition and postcondition.
  • The Modem Problem
  • Long Distance Rigidity
  • Adapter
    • Adapter is derive from the Modem and delegate to the Ded Modem in the example.
    • If you need an ugly hack, make sure to isolate it from the system by pointing all the dependency away from it.
  • Conclusion
  • References
    • The Annotated Turing by Charles Petzold
    • Advanced C++ Programming Style and Idiom by James Coplien
    • Refactoring: Improving the design of existing code by Martin Fowler
    • Object-oriented Software Construction by Bertrand Meyer