Book notes: Agile Technical Practices Distilled, 50 years of Cohesion and Coupling
As the 50th anniversary of cohesion and coupling concepts I decided to read this book in order to refresh concepts and compare how things has change (or not) since that. This is a great book by Pedro Moreira Santos, Marco Consolaro & Alessandro Di Gioia published in 2018 about agile technical practices
Many of the topics in this book are connected with my previous post: The Software Development Pyramid
The big picture
The general idea of the book is about the different and most popular concepts that we have today in the industry, their meaning, when they should be used, and what relationship they have with each other. To understand the principles behind everything i recomend to take a look of the book
To do this, it gives us a big picture:
Object-oriented programming (OOP) began to be used in the 1960s with that in the Object oriented software design (OOD) began . Now a days, we can find relevant topics like:
Rules
- Transformation Priority Premise (TPP), Evan Coplien and James Coplien, 2005 , to keep complexity in control you can transform the code using those premises (transformations on the top are preferred to those on the bottom)
- ({}–>nil) no code at all->code that employs nil
- (nil->constant)
- (constant->constant+) a simple constant to a more complex constant
- (constant->scalar) replacing a constant with a variable or an argument
- (statement->statements) adding more unconditional statements
- (unconditional->if) splitting the execution path
- (scalar->array)
- (array->container)
- (statement->recursion)
- (if->while)
- (expression->function) replacing an expression with a function or algorithm
- (variable->assignment) replacing the value of a variable
- Object Calisthenics, Jeff Bay, 2008
- Only One Level Of Indentation Per Method
- Don’t Use The ELSE Keyword
- Wrap All Primitives And Strings (wrap primitive types in classes)
- First Class Collections (wrap collections in classes)
- One Dot Per Line
- Don’t Abbreviate
- Keep All Entities Small
- No Classes With More Than Two Instance Variables
- No Getters/Setters/Properties
- All classes must have state
Consequences
- Code Smells, Kent Beck and Martin Fowler, 1999
- Bloaters
- Long Method (cohesion++ too much)
- Large Class (cohesion++ too much)
- Primitive Obsession (cohesion–)
- Long Parameter List (cohesion++ too much)
- Data Clumps (cohesion++ too much)
- Object-Orientation Abusers
- Alternative Classes with Different Interfaces
- Refused Bequest
- Switch Statements
- Temporary Field
- Change Preventers
- Divergent Change (coupling++) (cohesion++ too much)
- Parallel Inheritance Hierarchies
- Shotgun Surgery (coupling++) (cohesion–)
- Dispensables
- Comments
- Duplicate Code (cohesion++ too much)
- Data Class (cohesion–)
- Dead Code
- Lazy Class (cohesion–)
- Speculative Generality
- Couplers
- Feature Envy (coupling++)
- Inappropriate Intimacy (coupling++)
- Incomplete Library Class
- Message Chains (coupling++)
- Middle Man (coupling++) (cohesion–)
- Bloaters
- Solve with Refactoring, Kent Beck and Martin Fowler, 1999
- Composing Methods
- Extract Method
- Inline Method
- Extract Variable
- Inline Temp
- Replace Temp with Query
- Split Temporary Variable
- Remove Assignments to Parameters
- Replace Method with Method Object
- Substitute Algorithm
- Moving Features between Objects
- Move Method
- Move Field
- Extract Class
- Inline Class
- Hide Delegate
- Remove Middle Man
- Introduce Foreign Method
- Introduce Local Extension
- Organizing Data
- Change Value to Reference
- Change Reference to Value
- Duplicate Observed Data
- Self Encapsulate Field
- Replace Data Value with Object
- Replace Array with Object
- Change Unidirectional Association to Bidirectional
- Change Bidirectional Association to Unidirectional
- Encapsulate Field
- Encapsulate Collection
- Replace Magic Number with Symbolic Constant
- Replace Type Code with Class
- Replace Type Code with Subclasses
- Replace Type Code with State/Strategy
- Replace Subclass with Fields
- Simplifying Conditional Expressions
- Consolidate Conditional Expression
- Consolidate Duplicate Conditional Fragments
- Decompose Conditional
- Replace Conditional with Polymorphism
- Remove Control Flag
- Replace Nested Conditional with Guard Clauses
- Introduce Null Object
- Introduce Assertion
- Simplifying Method Calls
- Add Parameter
- Remove Parameter
- Rename Method
- Separate Query from Modifier
- Parameterize Method
- Introduce Parameter Object
- Preserve Whole Object
- Remove Setting Method
- Replace Parameter with Explicit Methods
- Replace Parameter with Method Call
- Hide Method
- Replace Constructor with Factory Method
- Replace Error Code with Exception
- Replace Exception with Test
- Dealing with Generalization
- Pull Up Field
- Pull Up Method
- Pull Up Constructor Body
- Push Down Field
- Push Down Method
- Extract Subclass
- Extract Superclass
- Extract Interface
- Collapse Hierarchy
- Form Template Method
- Replace Inheritance with Delegation
- Replace Delegation with Inheritance
- Composing Methods
- You can use:
- You can also use Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides, “Gang of Four” (GoF), 1994, when specific problem occurs
- Creational patterns
- Abstract factory
- Factory method
- Builder
- Prototype
- Singleton
- Behavioral patterns
- Strategy
- Template method
- Command
- Observer
- State
- Chain of responsibility
- Visitor
- Iterator
- Mediator
- Memento
- Structural patterns
- Proxy
- Adapter
- Decorator
- Facade
- Composite
- Bridge
- Flyweight
- Creational patterns
Principles
High cohesion and low coupling was first introduced by Stevens, Myers & Constantine in 1974 and popularized by the book Structured Design by Larry Constantine and Edward Yourdon in 1979. It has become a standard in the industry. For example, in 2002, Martin Fowler’s Enterprise Application Patterns, it becames one of the Layering Principles: Low coupling between layers, high cohesion within them
Coupling: Degree of interdependence between software components
- Interaction
- Message, communication (Good)
- Data, share data through parameters
- Stamp, data structure
- Control flow of another component
- External data or protocol
- Commonm, shared global data
- Content, depends on other components’ data (Bad)
- Method coupling premises => Impact
- void Method() => 0 (Less coupling)
- void Method(int x) => 1
- int Method() => 1
- void Method(ClassA a) => 1 + FanIn
- ClassA Method() => 1 + FanOut
- void Method(int x, int y) => 2
- int Method(int x) => 2
- void Method(ClassA a, ClassB b) => 2 + 2FanIn
- ClassA Method(ClassB b) => 2 + FanIn + FanOut (More coupling)
- etc…
- Inheritance
- Strongest king of coupling (When using inheritance)
- Interaction
Cohesion: Is a measure of how strongly related and focused the various responsibilities of a software module are
- Other indicators:
- Static methods in class (cohesion–)
- Helper classes (cohesion–)
- Criteria for grouping things (*helper, *core, *utils, *shared) (cohesion–)
- Class cohesion
- Ideal, no other mixed cochesion (Good)
- Mixed-Role, one or more fields with types in the same abstraction layer, and types have nothing to do with the semantic of the class
- Mixed-Domain, one or more fields with types in different abstraction layer, and types have nothing to do with the semantic of the class
- Mixed-Instance, class represent two different types and should be splited in two classes (Bad)
- Method cohesion
- Functional (Good)
- Sequential
- Communicational
- Procedural
- Temporal
- Logical
- Coincidental (Bad)
- Other indicators:
Connascence Meilir Page-Jones, In 1995, A three degree Metric to measure:
- Strength (stronger connascences are harder to discover, or harder to refactor) (Weak-Strong)
- Degree (size of the impact, estimated by the number of occurrences and the number of entities it affects)
- Locality (connascent elements that are close together in a codebase are better than ones that are far apart)
- Types:
- Static connascences
- Connascence of name (CoN) (Weak)
- Connascence of type (CoT)
- Connascence of meaning (CoM) or connascence of convention (CoC)
- Connascence of position (CoP)
- Connascence of algorithm (CoA)
- Dynamic connascence
- Connascence of execution order (CoE)
- Connascence of timing (CoT)
- Connascence of values (CoV)
- Connascence of identity (CoI)
- Manual Task (CoMT) (Strong)
- Static connascences
SOLID: Robert C. Martin (aka Uncle Bob), 2000, paper Design Principles and Design Patterns
- Single responsibility principle, (Tom DeMarco and Meilir Page-Jones on cohesion and coupling in the 1980s). More info in this codesai post.
- Open/closed principle (Bertrand Meyer, 1988).
- Liskov substitution principle(Barbara Liskov, 1987)
- Interface segregation principle(Robert C. Martin (aka Uncle Bob) in the late 1990s)
- Dependency inversion principle (Robert C. Martin (aka Uncle Bob) in the mid-1990s)
Balanced Abstraction Principle, Sandro Mancuso 2015: All code constructs grouped by a higher-level construct should be on the same level of abstraction. That means:
- All instructions inside a method should be at the same level of abstraction
- All public methods inside a class should be at the same level of abstraction
- All classes inside a package/namespace
- All sibling packages/namespace inside a parent package/namespace
- All modules, sub-systems, etc.
The Four Elements of Simple Design, Kent Beck in the 1990s.
- Passes the tests
- Reveals intention
- No duplication
- Fewest elements
On the other hand we can also see some topics related to:
Passes its tests
Flow:
- Red Green Refactor
- Test behaviour
- Triangulation
- Degrees of freedom
- Naming
- Fake it
- Obvious implementation
- Rule of three
- Duplication
- Arrange Act Assert
- Start from assertion
- Unit test principles (FIRST)
- Fast
- Isolated
- Repetable
- Self-validating
- Timely
- Test Doubles
- Only use in classes that you own
- Do not add behaviour
- Only use for immediate neighbors
- Outside–in development
- Schools
- London (Mockist TDD, commonly know as Outside-In) (useful when there are complex interactions)
- Chicago (Classicist TDD) (useful when states are clear)
- Types of tests:
- End to end (E2E) tests
- Acceptance tests
- Integration tests
- Unit test, began to be used in the 1960s
- Schools
Other types:
- Manual tests
- Performance tests
- Stress tests
- Smoke tests
- Snapshot tests
- Property based tests
- Other types
- etc.
Great habits:
- Considerations when writing a new test
- Tests should test one thing only
- Create more specific tests to drive a more generic solution (triangulate)
- Give your tests meaningful names (behavior/goal-oriented) that reflects your business domain
- See the test fail for the right reason
- Ensure you have meaningful feedback from failing tests
- Keep you tests and production code separate
- Organize your unit tests to reflect your production code (similar project structure)
- Organize your test in arrange, act and assert blocks
- Write the assertion first and work backward
- Write fast, isolated, repeteable and self-validating tests
- Consider using object calisthenics to drive design decisions
- Consider adding tests to legacy code
- Consider using classic TDD or Outside-In TDD
- If use Outside-In, start with acceptance test and folow the double loop TDD
- Considerations when making a failing test pass
- Write the simplest code to pass the test
- Write any code that makes you get to the refactor phase quicker
- Use Transformation Priority Premise (TPP)
- Considerations after the test passes
- Use the rule of three to tackle duplication
- Refactor design constantly
- Apply object calisthenics to improve your design
- Stay on the green while refactoring
- Use the IDE to refactor quickly and safely
- Refactor code for redability/understandability first
- Look out for code smells and refactor your code accordingly
- Refactor to patterns when the context is appropiate
- Considerations when writing a new test
More agile techniques
Unified model language, by Grady Booch, James Rumbaugh, Ivar Jacobson, “Three Amigos”, in the 1990s.
The Agile Manifesto, in 2001 by Kent Beck,Mike Beedle, Arie van Bennekum, Alistair Cockburn, Ward Cunningham, Martin Fowler, James Grenning, Jim Highsmith, Andrew Hunt, Ron Jeffries, Jon Kern, Brian Marick, Robert C. Martin, Steve Mellor, Ken Schwaber, Jeff Sutherland and Dave Thomas:
- Individuals and interactions over processes and tools
- Working software over comprehensive documentation
- Customer collaboration over contract negotiation
- Responding to change over following a plan
The Principles behind the Agile Manifesto:
- Our highest priority is to satisfy the customer through the early and continuous delivery of valuable software.
- Welcome changing requirements, even late in development. Agile processes harness change for the customer’s competitive advantage.
- Deliver working software frequently, from a couple of weeks to a couple of months, with a preference to the shorter timescale.
- Business people and developers must work together daily throughout the project.
- Build projects around motivated individuals. Give them the environment and support they need, and trust them to get the job done.
- The most efficient and effective method of conveying information to and within a development team is face-to-face conversation.
- Working software is the primary measure of progress.
- Agile processes promote sustainable development. The sponsors, developers, and users should be able to maintain a constant pace indefinitely.
- Continuous attention to technical excellence and good design enhances agility.
- Simplicity–the art of maximizing the amount of work not done–is essential.
- The best architectures, requirements, and designs emerge from self-organizing teams.
- At regular intervals, the team reflects on how to become more effective, then tunes and adjusts its behavior accordingly.
Extreme programming (XP), Kent beck in the 1990s
- Values
- Communication
- Simplicity
- Feedback
- Courage
- Respect
- Principles
- Feedback
- Assuming simplicity
- Embracing change
- Practices
- Fine-scale feedback
- Pair Programming
- Planning game
- Test-Driven Development (TDD)
- Whole team
- Continuous process
- Continuous Integration (CI)
- Refactoring
- Small Releases
- Shared understanding
- Coding Standards
- Collective code ownership
- Simple design
- System metaphor
- Programmer welfare
- Sustainable pace (No more than 40h)
- Fine-scale feedback
- Values
The Software Craftsmanship Manifesto, in 2009
- Not only working software, but also well-crafted software
- Not only responding to change, but also steadily adding value
- Not only individuals and interactions, but also a community of professionals
- Not only customer collaboration, but also productive partnerships
Beyond those techniques
Othe interesting topics in the final part of the book about of to connect thoose practices and business and how to understand the business like BDD (2006), user story mapping (2014), DDD (2003), EventStorming (2013), Business Model canvas (2005), impact mapping (2012), DevOps (2009), etc. In my experience I recomend to use: Domain-Driven Design Starter Modelling Process to go depth in this path.