Yet again here is an explanation from c2.com:
- “Always implement things when you actually need them, never when you just foresee that you need them.”
Even if you’re totally, totally, totally sure that you’ll need a feature later on, don’t implement it now. Usually, it’ll turn out either a) you don’t need it after all, or b) what you actually need is quite different from what you foresaw needing earlier.
This doesn’t mean you should avoid building flexibility into your code. It means you shouldn’t overengineer something based on what you think you might need later on.
This also follows the KISS theorem: Keep it simple, stupid!
There are two main reasons to practise YagNi:
- You save time, because you avoid writing code that you turn out not to need.
- Your code is better, because you avoid polluting it with ‘guesses’ that turn out to be more or less wrong but stick around anyway.
YAGNI is not a software design principle but I think that it needs to be discussed before this series moves on to the Open Closed Principle. There are many people that feel that unit tests are not a first class citizen of design forces: that is testability should not effect design. In opposition to this view some people assert that unit tests should be held to the same standards of quality as production code; they have to be maintained too after all. If so they must exert force on design considerations of the product. They must be a first class citizen.
Lets take the argument to an example. Test subject class A depends on Class B. It is class A’s responsibility to call method Foo on class B. To verify that A fulfilled its responsibility the test will need to sense that the call was made. In general there are only two ways to sense: a change in state or with a test double. If the change in state is strongly coupled to Foo’s responsibility then state based verification is the simplest way to go. Unfortunately this is often not the case. When it is not interaction verification can provide a solution: though it requires refactoring. An interface must be extracted from B. A must know of the new interface and not directly of B. As well A must offer a means for the unit test to provide a test double of the new interface. After this refactoring the test double can record the calls made by A during the test execution. And here is the crux of the example; an abstraction of B was created just to allow testing, or in some cases increase testability, of A. Did the creation of the new abstraction violate YAGNI? In general I think not.
Without stealing too much wind from the Open Closed Principle posting: Bob Martin talks of testability in chapter 9 OPC: The Open-Close Principle of Agile Software Development Principles, Patterns, and Practices.
We write tests first. Testing is one kind of usage of the system. By writing tests first we force the system to be testable. Therefore changes in testability will not surprise us later. We will have built the abstractions that make the system testable. We are likely to find than many of these abstractions will protect us from other kinds of change later.
If you are dedicated to unit testing I am sure that creating and maintaining them needs to fit into your business model. These activities need to utilize as few resources as possible while still serving their purpose. It only makes sense that test subjects that are easy to test contribute to getting the most bang for your buck. Test subjects that are difficult to test can consume resources quickly and for long periods of time.2,299 Total Views