[Cohesion And Coupling]
- keep things that have to change together as close together in the code as possible.
- Allow unrelated things in the code to change independently (also know as orthogonality).
- Minimize duplication in the code.
Decrease coupling
Coupling among classes or subsystems is a measure of how interconnected those classes or subsystems are.
- Make the code easier to read
- Make our classes easier to consume by other developers by hiding the ugly inner workings of our classes behind well-designed APIs.
- Isolate potential changes to a small area of code.
- Reuse classes in completely new contexts.
Code Smells
- Divergent Changes A single class that has to be changed in different ways for different reasons.
- Feature Envy A method in ClassA seems way too interested in the workings and data fields of ClassB.
- Shotgun Surgery A certain type of change in system repeatedly leads to making lots of small changes to a group of classes.
Increase Cohesion
The academic definition of cohesion is that it is a measure of how closely related all the responsibilities, data, and methods of a class are to each other.
cohesion as a measure of whether a class has a well-defined role within the system.
An easy test for cohesion is to look at a class and decide whether all the contents of the class are directly related to and described by the name of the class.
put code where you’d expect to find it.
Eliminate Inappropriate Intimacy
Inappropriate intimacy refers to a method in a class that has too much intimate knowledge of another class.
The Law of Demeter
only talk to your immediate friends
Tell, Don’t Ask
tell objects what to do, not ask an object about its internal state, make some decisions about that state, then tell that object what to do.
the candidate class for a new responsibility is the class who knows the information necessary to fulfill this responsibility.
GRASP, General Responsibility Assignment Software Patterns
- Information Expert
- Creator
- Controller
- Low Coupling
- High Cohesion
- Polymorphism
- Pure Fabrication
- Indirection
- Protected Variations
Say It Once and Only Once
One of the best ways to improve cohesion in your system is to eliminate duplication wherever you spot it.
Wrapping Up
[Design For Testability]
The Value Proposition
testability is all about creating rapid and effective feedback cycles in your development process to find problems in your code.
problems are cheaper to fix the earlier they are detected.
What Is Testability?
The end goal of testability to create rapid feedback cycles in your development process in order to find and eliminate flaws in your code.
- Repeatable
- Easy to Write
- Easy to Understand
- Fast
Mocking Best Practices
- Do not mock or fake out calls to fine-grained or chatty interfaces like ADO.NET that require a lot of calls.
- Do not mock any interface or class that you do not completely understand.
- If you find yourself repeating the same mocking setup across multiple tests, you may want to change your design to separate the code that forces the repetitive mocking setup.
- Do use mock objects as placeholders for class that don;t yet exist especially as a way to help determine what the public interface should be.
Isolate the Ugly Stuff
some things are just plain ugly to deal with in testing.
ugly stuff list
- Database access.
- GUI technologies.
- Active Directory access.
- Web services.
- Configuration files.
SpecUnit
Using Fakes to Establish Boundary Conditions
Mediates between the domain and data mapping layers using a collection – like interface for accessing domain objects.
A Repository mediates between the domain and data mapping layers, acting like an in-memory domain object collection. Client objects construct query specifications declaratively and submit them to Repository for satisfaction. Objects can added to and removed from the Repository, as they can from a simple collection of objects, and the mapping code encapsulated by the Repository will carry out the appropriate operations behind the scenes. Conceptually, a Repository encapsulates the set of Objects persited in a data store and the operations performed over them, providing a more object-oriented view of the persistence layer. Repository also supports the objective of achieving a clean separation and one-way dependency between the domain and data mapping layers.
Aggregate is A cluster of associated objects that are treated as a unit for the purpose of data changes. External references are restricted to one member of the Aggregate, designated as the root. A set of consistency rules applies with the Aggregate’s boundaries.
In a real application often several operations have to be executed inside a single transaction and thus inside a transaction and thus inside a single session (the reason is that a transaction cannot span multiple sessions – at least when not using distributed transactions).
不得不说这是一篇好文章,至少让我明白了 Repository 并不只是字面上的含义,和我一样的 NHibernate 初学者,最好能够看一下前后这两篇文章:The Repository Pattern,Nhibernate and the Unit of Work Pattern。
Unit of Work pattern, UoW
Fake object, such as stubs or mocks, are a huge advantage for doing emergent or continuous design by allowing you to build and even design, a system incrementally by standing in for services that you haven’t ye created.
The Gateway Pattern
An object that encapsulates access to an external system or resource.
Wrap all the special API code into a class whose interface looks like a regular object. Other objects access the resource through this Gateway, which translates the simple method calls into the appropriate specialized API.
- Pipes and Filters How do you implement a sequence of transformations so that you can combine an reuse them independently
Pipes and Filters provides a solution for moving the output of one system into another system. The pipe is the portion of the code that is connected to the source system and to the sink or the receiving system. The filter is the portion of the code that transforms the data so that the sink program can process it.
- Gateway How can you make the application of an integration solution access without introducing many-to-one coupling between the application and the external system.
The Gateway pattern abstracts the access to an external system to a single interface.
Separate Deciding from Doing
treat performing an action and deciding to take an action as two separate responsibilities.
- Prevent duplication in the code.
- Makes the code simpler.
- Infrastructure change easily (robust).
Small Tests before Big Tests
Smaller tests are cheaper to create, easier to understand, faster to run, and much simpler to debug.
The Big Picture
How can I test this in isolation?