Page 249 - DCAP305_PRINCIPLES_OF_SOFTWARE_ENGINEERING
P. 249
Unit 12: Refactoring
Like in most techniques, the key to success with indirection is to put just the right amount of it Notes
in the right spot. Too much or badly placed indirection results in a fragmented system. Useless
indirection is often found in a component that used to be shared or polymorphic, but is not
anymore due to changes made during the development process. A refactoring catalog gives you
the starting point for deciding where and how much indirection should be used. Basically, if
you encounter indirection that is not paying for itself, you need to take it out.
12.1.5 Refactoring in Software Development Process
Refactoring essentially means improving the design after it has been implemented. It is an
inherently iterative method, which implies that it does not fit very well to the traditional
waterfall model of software engineering process. With refactoring design occurs continuously
during development.
Refactoring can be thought of as an alternative to careful upfront design. This kind of speculative
design is an attempt to put all the good qualities into the system before any code is written. The
problem with this process is that it so easy to guess wrong. Sometimes extreme programming is
regarded as a paradigm which reacts to that observation by skipping the design phase altogether.
Refactoring can, however, be used also in a more conservative way. Instead of abandoning the
design phase completely, you move from overly flexible and complex think-about-everything-
beforehand designs to simpler ones. This is sensible because you do not need to anticipate
all changes in advance. With refactoring, you can favour simplicity in design because design
changes are inexpensive.
When you develop software using refactoring, you divide your time between two distinct
activities: Refactoring and adding function. When you add function you should not change
existing code. If there is a turn in your development that seems difficult because your
implementation does not support the new feature very well, you need to first refractor your
system to accommodate the modification.
After adding a function you must add tests to see that the function was implemented correctly.
You can even consider tests as explicit requirement documentation for the feature and write
them before you add it. Use existing tests to ensure that refactoring did not change behaviour
or introduce bugs.
Testing should be as easy as possible. That is why all tests should be made automatic and they
should check their own results. This will enable you to test as often as you compile. When you
encounter a failure, you can concentrate your debugging in a narrow area of code you added
after the last successful tests.
The testing technique that works best with refactoring is class-level white-box testing. A good
way to write such unit tests for an object-oriented system is to have a separate test class for each
important production class. You can also use a test framework (e.g. Joint) to handle the test case
management and reporting in a standardized way. The test framework should provide flexible
ways to combine tests so that they can be run in any order.
Testing should be risk driven. This means that you test those parts of a class that are complex
and most valuable. Remember to concentrate your testing on the boundaries of the input range
and other special conditions (e.g. missing input, null values).
Besides testing, code reviews are known to be valuable in verifying software quality. Refactoring
process can be an integral part of reviews, especially if they are conducted in small groups.
Refactoring gives you a chance to see the concrete effect of suggested corrections.
Do not try to test everything or you might end up testing nothing.
LOVELY PROFESSIONAL UNIVERSITY 243