Composite Simpler Than the Sum of Its Parts
The API of a composite object should not be more complicated than that of any of its components.
All objects in a system, except for primitive types built into the language, are composed of other objects. When composing objects into a new type, we want the new type to exhibit simpler behavior than all of its component parts considered together. The composite object’s API must hide the existence of its component parts and the interactions between them, and expose a simpler abstraction to its peers. Think of a mechanical clock: It has two or three hands for output and one pull-out wheel for input but packages up dozens of moving parts.
When you notice that a group of values are always used together
This may serve as a suggestion that there’s a missing construct.
A first step might be to create a new type with fixed public fields — just giving the group a name highlights the missing concept. Later we can migrate behavior to the new type, which might eventually allow us to hide its fields behind a cleaninterface, satisfying the “composite simpler than the sum of its parts” rule.
Growing Object Oriented Software guided by Tests p58
Use the Same Techniques to Break Dependencies in unit tests as in Production Code
There are several frameworks available that use techniques such as manipulating class loaders or bytecodes to allow unit tests to break dependencies without changing the target code. As a rule, these are advanced techniques that most developers would not use when writing production code. Sometimes these tools really are necessary, but developers should be aware that they come with a hidden cost.
Unit-testing tools that let the programmer sidestep poor dependency management in the design waste a valuable source of feedback. When the developers eventually do need to address these design weaknesses to add some urgent feature, they will find it harder to do. The poor structure will have influenced other parts of the system that rely on it, and any understanding of the original intent will have evaporated. As with dirty pots and pans, it’s easier to get the grease off before it’s been baked in.
Some of the test smells we’ve identified, such as needing “magic” to create mocks, are to do with knowledge leaking between components. If we can keep knowledge local to an object (either internal or passed in), then its implementation is independent of its context; we can safely move it wherever we like. Do this consistently and your application, built out of pluggable components, will be easy to change.