- Published 4/18/2017
- 2nd Edition
Write code that can adapt to changes.
By applying this book’s principles, you can create code that accommodates new requirements and unforeseen scenarios without significant rewrites. Gary McLean Hall describes Agile best practices, principles, and patterns for designing and writing code that can evolve more quickly and easily, with fewer errors, because it doesn’t impede change.
Now revised, updated, and expanded, Adaptive Code, Second Edition adds indispensable practical insights on Kanban, dependency inversion, and creating reusable abstractions. Drawing on over a decade of Agile consulting and development experience, McLean Hall has updated his best-seller with deeper coverage of unit testing, refactoring, pure dependency injection, and more.
Master powerful new ways to:
• Write code that enables and complements Scrum, Kanban, or any other Agile framework
• Develop code that can survive major changes in requirements
• Plan for adaptability by using dependencies, layering, interfaces, and design patterns
• Perform unit testing and refactoring in tandem, gaining more value from both
• Use the “golden master” technique to make legacy code adaptive
• Build SOLID code with single-responsibility, open/closed, and Liskov substitution principles
• Create smaller interfaces to support more-diverse client and architectural needs
• Leverage dependency injection best practices to improve code adaptability
• Apply dependency inversion with the Stairway pattern, and avoid related anti-patterns
About You
This book is for programmers of all skill levels seeking more-practical insight into design patterns, SOLID principles, unit testing, refactoring, and related topics. Most readers will have programmed in C#, Java, C++, or similar object-oriented languages, and will be familiar with core procedural programming techniques.
Table of Contents
TOC
Chapter 1 Introduction to Scrum
Scrum versus waterfall
Roles and responsibilities
Product owner
Scrum master
Development team
Artifacts
The Scrum board
Charts and metrics
Backlogs
The sprint
Release planning
Sprint planning
Daily Scrum
Sprint demo
Sprint retrospective
Scrum calendar
Agile in the real world
Rigidity
Untestability
Metrics
Conclusion
Chapter 2 Introduction to Kanban
Kanban quickstart
The information radiator
Limiting work in progress
Protecting against change
Defining “done”
Event-driven ceremonies
Classes of service
Service level agreements
Class WIP limits
People as a class of service
Analysis
Lead time and cycle time
Cumulative flow diagrams
Conclusion
Part II Foundations of adaptive code
Chapter 3 Dependencies and layering
Dependencies
A simple example
Framework dependencies
Third-party dependencies
Modeling dependencies in a directed graph
Managing dependencies
Implementations versus interfaces
The new code smell
Alternatives to object construction
Resolving dependencies
Dependency management with NuGet
Layering
Common layering patterns
Cross-cutting concerns
Asymmetric layering
Conclusion
Chapter 4 Interfaces and design patterns
What is an interface?
Syntax
Explicit implementation
Polymorphism
Adaptive design patterns
The Null Object pattern
The Adapter pattern
The Strategy pattern
Further versatility
Duck-typing
Mixins
Fluent interfaces
Conclusion
Chapter 5 Testing
Unit testing
Arrange, Act, Assert
Test-driven development
More complex tests
Unit-testing patterns
Writing maintainable tests
The Builder pattern for tests
The Builder pattern
Clarifying unit test intent
Writing tests first
What is TDD?
Test-driven design
Test-first development
Further testing
The testing pyramid
Testing pyramid anti-patterns
The testing quadrant
Testing for prevention and cure
How do you decrease MTTR?
Conclusion
Chapter 6 Refactoring
Introduction to refactoring
Changing existing code
A new account type
Aggressive refactoring
Red, green, refactor…redesign
Making legacy code adaptive
The golden master technique
Conclusion
Part III SOLID code
Chapter 7 The single responsibility principle
Problem statement
Refactoring for clarity
Refactoring for abstraction
SRP and the Decorator pattern
The Composite pattern
Predicate decorators
Branching decorators
Lazy decorators
Logging decorators
Profiling decorators
Decorating properties and events
Conclusion
Chapter 8 The open/closed principle
Introduction to the open/closed principle
The Meyer definition
The Martin definition
Bug fixes
Client awareness
Extension points
Code without extension points
Virtual methods
Abstract methods
Interface inheritance
“Design for inheritance or prohibit it”
Protected variation
Predicted variation
A stable interface
Just enough adaptability
Predicted variation versus speculative generality
Do you need so many interfaces?
Conclusion
Chapter 9 The Liskov substitution principle
Introduction to the Liskov substitution principle
Formal definition
LSP rules
Contracts
Preconditions
Postconditions
Data invariants
Liskov contract rules
Code contracts
Covariance and contravariance
Definitions
Liskov type system rules
Conclusion
Chapter 10 Interface segregation
A segregation example
A simple CRUD interface
Caching
Multiple interface decoration
Client construction
Multiple implementations, multiple instances
Single implementation, single instance
The Interface Soup anti-pattern
Splitting interfaces
Client need
Architectural need
Single-method interfaces
Conclusion
Chapter 11 Dependency inversion
Structuring dependencies
The Entourage anti-pattern
The Stairway pattern
An example of abstraction design
Abstractions
Concretions
Abstracting capabilities
The improved client
Abstracting queries
Further abstraction
Conclusion
Part IV Applying adaptive code
Chapter 12 Dependency injection
Humble beginnings
The Task List application
Constructing the object graph
Beyond simple injection
The Service Locator anti-pattern
Illegitimate Injection
The composition root
Convention over configuration
Conclusion
Chapter 13 Coupling, cohesion, and connascence
Coupling and cohesion
Coupling
Cohesion
Connascence
Name
Type
Meaning
Algorithm
Position
Execution order
Timing
Value
Identity
Measuring connascence
Locality
Unofficial connascence
Static vs. dynamic connascence
Conclusion
Appendix Adaptive tools
Source control with Git
Cloning a repository
Switching to a different branch
Continuous integration