Ugly code, do I tidy first?
Software tends to age and how we structure code will change over time due to technology upgrades, different developers working on it, business needs or simply lack of cohesive approach to new features.
When appointed to work on an aged code base, as developers we must decide if it does worth tidying it first, being generally two dogmatic approaches:
- Sure, always. We are the ultimate responsible of the software. We owed it to ourselves and our craft to get things right at any cost. Even if the business needs pull on a different direction. Too bad if they need to wait for a new feature.
- Never! I deserve to work on mess code like this. I did this mess, I deserve it. Even if it was not me, we collectively need to pay the price for rushing in.
As always, it depends.
Cost of software
When considering expected lifetime of a system, the initial cost of development is minimal when compared to the cost of maintaining, changing and updating that application. So the cost of software can be approximated to the cost of change.
cost(Software) ~= cost(Changes)
Within the cost of any change, it is the big ones that to dwarf even the sum of all small changes. Changes that break the fundamental concepts and logic of a program are the most costly over time.
cost(Changes) ~= cost(Big Changes)
The blast radius of Big Changes is directly proportional to the level of coupling within the system. The more interconnected the code is, the bigger the change and the cost are
cost (Big Changes) ~= Coupling
In summary, the cost of software can be approximated at the level of coupling within the system.
The reason to design software is that we can change it, and do so at a reasonable cost.
As software designers, we can strive to reduce coupling but the amount of time and effort to do so can also add cost (both as monetary and time wise). It is important to find the balance between spending a reasonable amount to reduce coupling and continued development of the application.
Coupling
Two elements are coupled with respect to a specific change when changing one element forces the change to the other.
coupled(E1, E2, ∆):: ∆E1 -> ∆E2
In other words, coupling depends on the type of change between to elements. These elements might be generally related but only some changes might affect them in terms of coupling.
As software developers we need to asses when decoupling parts of a system is valuable to act upon now, or accept it might come back in the future to haunt you.
Coupling is only damaging depending on it’s span. Localized coupling can not only be dismissed but it might even be beneficial.
Cohesion
Cohesion is defined at the span coupling. It is how many elements are related to each other.
cohesion(E):: coupled(E1, E2, ..., En)
Coupling is bad depending on what it is compared to. As an example, if all E elements are coupled but on the same file, it is better than having each element on different files as the coupling is less obvious.
The more spread out coupling is, the more expensive it gets.
Behaviour vs Structure
Sometimes, changes in behaviour can be made simpler with changes on structure first. Behaviour changes are visible, bringing obvious revenue (either increasing value or reducing cost), but structure is not as explicit.
The structure of the system radically affects the cost of changes to behaviour of the system.
Structure changes modifies the optionality of the system, making behaviour changes easier, cheapest or safest. But generally is harder to account for this optionality than actual revenue, so generally gets de-prioritized against new features.
Conclusion
Highly coupled systems results on bigger cost over time, as well as under investing in structure. Over investing in behaviour during a long period of time results on less or slower changes as a result of neglecting the cohesiveness and structure of the system.
Software design is the craft of balancing planning initial system structure to implement behaviour and the continued development of the system.