Write unit tests as you write code.
There are several benefits to writing unit tests:
- you have confidence that the code works
- you can change the code and have confidence that it still works
- you design from the point of view of a client
- your code is loosely coupled and more reusable
Write the tests as you write the code. It is very difficult to retrofit tests to existing code.
- When writing tests there are occasional rough spots where some scaffolding must be created. For existing code this can be a daunting task. If you write tests with code, your scaffolding will develop as needed.
- Untested code is often monolithic and tightly coupled making it difficult to test. Writing tests forces the code to be loosely coupled and testable.
You think you don't have time to write tests? I don't have time not to! Unit testing helps me go faster.
Unit testing is for bug-fixes, too! Before you fix a bug, write a test that exposes the bug. Then fix the bug to make the test pass.
One benefit of unit testing is not realized until you have to make a change to code that has tests. Unit testing is an enabling technology. It lets you refactor with confidence.
See also: Test Driven Development
Refactoring is the process of changing a software system in such a way that it does not alter the external behavior of the code yet improves its internal structure. -- Martin Fowler
Many mature software projects calcify. They have been built and rebuilt and patched and shoehorned to death. The developers don't fully understand the code. There are sections of code that they know are badly in need of a rewrite, but they don't dare touch them because they have no tests or clear specifications. Progress is slow, bugs are plentiful. Making changes is like running with your shoelaces tied together - you keep falling down.
What is the alternative? Keep the code clean, always. This is a key aspect of agile development and implicit in the simplicity rules above.
The current code should always reflect the simplest thing that could possibly work. It should always be designed to meet the current requirements. As requirements change and features are added, these goals are easily broken. Refactor to bring the design back in line with the requirements.
Include refactoring in your work cycle. Periodically step back and evaluate what you have done. If the design is lacking, if there is duplication, if the code is not expressive of what it does, then it is time to refactor.
You can also refactor when you start making a change. If you find you have to make a change, and you don't see an easy way to make the change, then refactor until the change is easy.
Martin Fowler's book Refactoring: Improving the Design of Existing Code is the classic introduction to refactoring. It includes an extended example, a catalog of refactorings, and a chapter on Code Smells.
See also: Refactor mercilessly
The goal of software development is ultimately to deliver value to the customer - the person who will use the software.
Focus on the highest value tasks first. Use your to do list as a priority queue. Pick the highest value task and do it. When you finish, pick the new highest value task and do that. It's helpful, but not necessary, to have a rough order for the top of the list. All you really need is to know what is at the top. Expect the order to change with time.
Release incrementally so the customer receives the value and can provide feedback. Frequent releases and customer feedback ensure that you are on track and providing something useful. Your goal should be to delight your customer!