Sunday 12 July 2015

Evolving Decomposition


Software is a living document it evolves, isn't written in stone and as time goes on will require changes to be made to it.
Sometimes these changes are not for the better, we may add a new feature but we do so at the expense of the integrity of the code base. Often these destructive changes are gradual, one minor sub-optimal change builds on another and so on until at some point the structure of the code has been compromised and is no longer a good solution to the original problem.
This situation is often called code rot and the solution to it is re-factoring.
Sometime this re-factoring can be pre-emptive, our experience and our nose tells us that this code is heading down the wrong road.
No matter what triggers the re-factoring it should achieve one of two things, increase maintainability and/or increase extensibility.
Exactly how this re-factoring can be achieved and the effects it should have is a vast topic, entire books have been written on the subject, but lets look at some of the common goals of re-factoring and the techniques we can use. 
Applying Some Abstract Thinking
Abstraction deals with complexity by hiding detail, a good abstraction talks only in terms of the functionality on offer not implementation, the "what" not the "how".
Rot can occur if overtime the abstraction starts leaking detail about what's going on under the hood, very often this is caused by a short-cut being taken because this leaking of information is easier then maintaining the abstraction.
This might be a problem with the abstraction itself or the under lying implementation either way its not what we want.
Re-factoring techniques to improve abstraction usually revolve around increasing encapsulation or generalisation. This might be putting fields behind getters and setters, changing a method signature to require less type checking or making better use of polymorphism.
The goal should be to ensure dependencies relate to abstraction not implementation and increase resilience to changes in detail.  
Separating Oranges From Apples
Another key aspect to a code base is the level of cohesion, this indicates the closeness of the relationship between data and functionality within the same class.
If classes are doing one thing and doing it well their should be a high level of cohesion, each cog of the class playing a role in that single outcome.
Rot can set in when functionality and data is placed in a convenient location for the developer making the change not in the most logical location for the design, this also often involves wide spread duplication.
Once again if your taking a sub-optimal decision because its easier that way something is wrong, either with the design or with the change your making.
Re-factoring techniques to increase cohesion generally involve recognising when more than one class or more than one method are co-existing.
In the case of a class this might be multiple methods all operating on different pieces of data within the class, in the case of a method it might sections of the method that do not operate on the operations from previous lines.
The goal here is to divide and conquer, split out the new class or the new method, reaching for ever smaller building blocks to make up the overall design. 
Changing What It Says On The Tin
Deciding on names within code either for a class, method or variable may sometimes seem like pedantry but problems relating to names often tell us a lot about the health of the code.
Difficulty in naming an element of code usually means what that unit does or represents is not well defined or is a list and not a single purpose.
Rot can very easily be introduced around naming, a change to what a method does or what a variable represents can mean the name is no longer accurate.
Names should always the reflect the functionality that a method offers or the data a variable represents, modern IDEs make re-naming a relatively trivial re-factor so their is no excuse.
Names are the first and in many cases only documentation for your code make sure its accurate.
Re-factoring should be a continual process of trying to evolve the code base in to an ever better solution to the problem, this is not always easy because sometimes the problem changes.
This is why maintainability and extensibility are such important qualities, code rot is an inevitable consequence of having multiple people operate on a code base that requires ever more features to be added to it, the key is to not let the mould spread. Recognise when its starting to take hold, cut it out and replace it with clean, healthy code.   

No comments:

Post a Comment