Refactoring | improving the design of existing code

Refactoring is the process of improving the design of code, keeping it as simple as possible without affecting its external behavior or breaking it. Automated unit testing with NUnit is a prerequisite, and should be performed after each change has been made to prove that the code still functions correctly. This testing provides the confidence to refactor and instills the courage to refactor often, which keeps the code base maintainable. Each refactoring step is reversible, promoting experimentation and a learning attitude towards code.

Refactoring works in unison with test-driven development. The tests and the code should be developed iteratively, running the tests compulsively as the code takes shape. Both the tests and the code should then be refactored to progressively improve their design and performance. Refactoring facilitates change by maintaining a good design, keeping it flexible and easy to modify. The cleaner the code, the faster existing features can be changed or new ones added.

Catalogs of refactorings are available for reference. Some refactorings are trivial, e.g. renaming or moving variables or functions; other more complex refactorings exchange procedural logic with polymorphism, apply abstraction to remove duplicate code from concrete implementations, or introduce design patterns.

When to refactor, and when not to refactor

Refactoring is typically performed as part of normal code-writing activities. It is usually triggered by code smells, i.e. places where refactoring will improve the design of the code. Two regular opportunities to refactor are before and after implementing a new feature - sometimes refactoring existing code can make implementing a new feature easier, and sometimes the code that implements a recent feature can be simplified further. Refactoring can be performed at other similar opportunities, e.g. when fixing bugs not caught by unit tests, or when performing a code review.

Refactoring should not be started too soon. Code should be made to run first, supported by automated tests that pass with a 100% success rate. Only refactor when an improvement is assured, and do not refactor beyond the customer's requirements. There will always be some refactoring that was not possible in the time-frame, just like there are some features that could not be included in an iteration.

Design progressively with on-going care

Instead of producing a comprehensive design up-front, a small but capable initial design should be created, and then evolved with continuous care over the life of the software system. Indeed through refactoring, a greater emphasis is placed on this subsequent care, than upon the initial design.

Through refactoring and a focus on simple design, a software system can be built incrementally with small improvements made to the code, so that the latest version is always better than its predecessor. Continuous care helps prevent the accumulation of dependencies, removes duplicate code or unnecessary architecture, and eliminates localized brittleness or rigidity.

Back to top ^^

This page is valid XHTML 1.0 This page uses valid CSS

Iterative Development | Developer Testing | Continuous Integration | Refactoring

Methodologies | Project Management | Analysis & modeling | Development | Testing | Quality Assurance

Home | Services | Contact Us