Software design is about change. A good design facilitates adding features—and adding new developers to the team. Yet any change to the code impacts design and could damage existing functionality. Without design idioms and practices, the code can degrade into a "big ball of spaghetti” and a maintenance nightmare. Your team must know which decisions to make early in design and which to defer. Rob Myers reviews “families” of design attributes and practices, showing the common principles within each. Exploring emergent design by tracing how the concept itself has evolved and matured over time, Rob covers traditional attributes of good object-oriented code (cohesion, encapsulation, polymorphism, coupling); design patterns and the wisdom discovered within; S.O.L.I.D. principles—all culminating in emergent design, where simple (not easy) practices meet the simplest of guidelines, such as Kent Beck’s “Four Rules of Simple Design.” And the result is code that is easy to understand and delightful to work on.
Be sure to pass out files or have someone establish a read-only share.
25 yrs in the industry
Using TDD and coaching XP/Scrum since 1998
Teaching TDD courses since 2001
Fractals of course
Mountains and rivers
We tend to find these in nature. We tend to think of them as elegantly beautiful, and either relaxing or fearsome.
snowflakes
Romanesco broccoli
A selfie of the early universe.
Requires energy.
Same rules apply at macro/micro level, as well as creating path from micro to macro and back again.
From simple rules, complex behaviors arise.
Ant hills, termite mounds, wasp nests, fractals, weather patterns, tree growth, rivers, galaxies, and quite possibly the multiverse.
To succeed at this game, you have to trust the practices and the rules.
In order to trust, you have to see where they’ve been.
Maintainability, not secrecy.
<click>
Maintainability
Maintainable systems should be as decoupled as possible. That does not mean we can have no coupling. Coupling is what makes a system work - object must be able to work together to create the architecture of the application in the first place.
We want to understand, control, and simplify the coupling in the system.
Four kinds:
Identity Coupling – is when one type is coupled to the fact that another type exists.
class WidgetContainer {
Widget myWidget; // WidgetContainer is Identity coupled to Widget
}
Representational Coupling – is when you call a method on a class
myWidget.doWidgetStuff(); // This is representational coupling
Inheritance Coupling – when have a derivation, what is the coupling of different subclasses to its inheritance hierarchy
Subclass Coupling – if the client only knows about Widget (doesn’t know about sub-classes) then there is no subclass coupling, otherwise there is. Not having subclass coupling allows me to change subclasses without affecting the client object using them. WOULD BE GOOD TO INCLUDE PRINCIPLES THAT ALLOWS THIS TO HAPPEN.
Maintainable systems should be as decoupled as possible. That does not mean we can have no coupling. Coupling is what makes a system work - object must be able to work together to create the architecture of the application in the first place.
We want to understand, control, and simplify the coupling in the system. Here are the four types of coupling we have to deal with (explain them).
The strongest form of coupling.
A Perfectly Good Editing Technique…Not a good DESIGN technique. YOU must clean it up!
Two classes have similar interfaces or encapsulate similar concepts.
Use class hierarchy to categorize, not specialize.
One level is usually enough. Abstraction, and concrete implementation.
Originally “Design to interfaces”
Concrete code delegates to abstractions.
Favor Representational coupling over subclass coupling.
Increases flexibility! Replacing structural code with runtime state, then behaviors can change at runtime!
Objects encapsulate data and related behavior.
Hierarchy encapsulates variation of implementation.
Many other things can be encapsulated.
Originally “Design to interfaces”
Concrete code delegates to abstractions.
Favor Representational coupling over subclass coupling.
Increases flexibility! Replacing structural code with runtime state, then behaviors can change at runtime!
SRP: Cohesion
OCP: Points to an advanced use of encapsulation and polymorphism.
Liskov: Semantic not syntactic. Behavioral inheritance, not literal. CatTigerBengal TigerWhite Bengal Tiger & the Mantecore Confusion
Interface Segregation: Relates to cohesion. Using narrow interfaces. Since we’re not really talking about a particular language, essentially narrow type interfaces: few public methods, small objects.
DIP: Inversion compared to traditional old structured analysis and decomposition. Top-down doesn’t work, bottom-up creates similar couplings. Decoupling via abstractions where necessary. Layers of abstraction. Design to types, + Encapsulates Variation “up” or “down”. The types you communicate with should make sense for what you are trying to accomplish. And so it goes at every level, and in every direction. This is also the primary legitimate use of Java interfaces, as contracts to be established between client and service.
SRP: Cohesion
OCP: Points to an advanced use of encapsulation and polymorphism.
Liskov: Semantic not syntactic. Behavioral inheritance, not literal. CatTigerBengal TigerWhite Bengal Tiger & the Mantecore Confusion
Interface Segregation: Relates to cohesion. Using narrow interfaces. Since we’re not really talking about a particular language, essentially narrow type interfaces: few public methods, small objects.
DIP: Inversion compared to traditional old structured analysis and decomposition. Top-down doesn’t work, bottom-up creates similar couplings. Decoupling via abstractions where necessary. Layers of abstraction. Design to types, + Encapsulates Variation “up” or “down”. The types you communicate with should make sense for what you are trying to accomplish. And so it goes at every level, and in every direction. This is also the primary legitimate use of Java interfaces, as contracts to be established between client and service.
That’s a lot to learn!
Learn them at your own pace.
In the mean time, we need to keep designs fluid, so they can change.
In fact, one very good definition of a good design is a design that can adapt to change: Maintainability and extensibility.
So, beyond keeping every possible variation open-closed and decoupled, and yet still readable and maintainable by humans, what can we do?
Order arising from chaos in a series of tiny steps, resulting in “emergent properties.”
Requires energy.
Same rules apply at macro/micro level, as well as creating path from micro to macro and back again.
From simple rules, complex behaviors arise.
Ant hills, termite mounds, wasp nests, fractals, weather patterns, tree growth, rivers, galaxies, and quite possibly the multiverse.
Note what Kent isn’t talking about here: OO! Why? He’s either forgotten, or is assuming, all the prior OO/DP knowledge. In an emergent context, as you work with an OO language with these rules, you will eventually “re-learn” all prior wisdom. It’s easier if you know it, but not impossible if you don’t.
Refactoring IS design!
TDD (pairing doesn’t hurt either)
YOU are the engine of emergence!
Thank you!
Spontaneous order arises from chaos.
From simple rules, complex behaviors manifest.
Tiny steps, repeated many times, perhaps recursively.
Same “rules” apply at macro/micro levels; same “paths” exist to/from another level.
Require a rich supply of “food”: time, energy, RAM…