While preparing for another AWS Pro cert, I came across an interesting article by Martin Fowler that highlights the cost of cruft. Cruft is badly designed, unnecessarily complicated, or unwanted code.
Having run a lot of software projects in my time and established and managed app development teams, Martin’s articles around software architecture and code quality really resonated with me.
Just the other day I came across some code that had more comment lines than actual code, and the code that was there wasn’t architecturally sound. It had a somewhat obvious bug due to an oversight as to how a user might interact with the application. This was making remediation of the code difficult and time consuming.
I feel that 4 of the most powerful lessons I’ve learnt in my IT career are:
1. Always understand the root cause of an error. Don’t just “fix” stuff without fully identifying and understanding the root cause.
2. Architect everything modularly. Learning OOP with C++ was probably one of the best things I did very early in my career.
3. Always ask yourself “Will this scale?” or, what will this look like scaled out 10x, 1,000x, 100,000x.
4. Introduce standards fast and early with well documented examples of “why” for others to follow.
I’m going to focus on the “why” in point 4.
Far too many times I’ve been involved in projects where a rough proof of concept has been developed, the idea catches on and before you know it, badly written developer code is in production.
Martin Fowler correctly points out that the time impact of this becomes realised in weeks not months. More often than not the code won’t scale. More features create more cruft. Finding the root cause of errors becomes more cumbersome and time consuming. Before long, all hands are busy bailing a leaky boat. Rather than finding ways to make the boat sail much faster and leaner.
I feel that point 2 and point 4 go hand in hand. Point 2 is reflected in the 12 Factor app. OOP encourages abstraction, so I’ve always created applications this way.
The main benefit of standards in my view, is having a whole team code consistently at speed. Everyone can understand everyone else’s code quickly, and there’s a certain amount of quality baked into the code immediately.
It’s likely that some people might cringe at the idea of coding standards, but that might be because they’ve had standards forced upon them with no rhyme or reason.
In my experience, it’s best if the product development team come up with standards together, and agree why a standard is important.
I think another point to emphasise is that this should be a set of guidelines rather than rigid rules that are enforced blindly.
These days many standards exist that you can just pick up and use. PEP8 from Python is a good example. Further to this, most languages now have linters that ensure that developers are adhering to code style recommendations.
Agreeing on things like meaningful names of modules, functions and variables so their purpose is self-evident is a worthwhile investment of time. One example is deciding that all repos for front-end code should have -frontend- in their name, and backend code similar. You won’t need to look in the repo to figure out what part of the application the code deals with. It’s easy to search for packages or modules in the repo, by filtering on these naming conventions.
I’ve worked with coders that thought the height of genius was writing code nobody else but them could understand. Single letter variable names and aliases. Unnecessary LEFT and RIGHT join statements in SQL. All it does is make the code near impossible to understand, let alone maintain.
Whatever standards you come up with, there should be a sound reason for them. That reason shouldrelate back to quality at scale. Although good standards might mean a 10-15% increase in time to develop initially, when you’re even more time poor later on, that investment will pay huge dividends when it really counts.
Understanding the outcome you’re trying to accomplish with a standard is more important than the means by which you’re trying to accomplish it. I see this a lot in the security, governance and privacy space.
In many large organisations the why, the desired outcome, is completely lost in the complications of the process. The process is so cumbersome, lengthy and unworkable that everyone avoids it whenever they can. This defeats the purpose of it existing in the first place.
When coming up with standards with your team, always frame them with “we want to use this standard so that we accomplish this outcome.” This opens the floor for a better way to accomplish the outcome if the standard is too tight or rigid.
Ask yourself why the approach might not work rather than validating why it will. What’s the cost and consequences vs the cost and consequence of other options?
I feel it’s just as important to review and revise standards as things change. Are the standards you’ve established still fit for purpose? Are they accomplishing the objectives you intended? Sadly there are far too many times when a development team is stuck on a set way of doing things but have forgotten why they do it that way. There’s a real risk of locking yourself in the dark ages if you’re not reviewing and incrementally improving the effectiveness of your approach.
In summary, establishing some sound standards that encourage common patterns so that new problems can be solved with quality code is a worthwhile investment.
The cost of not doing this is poorly written code that typically doesn’t scale and is difficult and time consuming to maintain. It will almost certainly need to be completely rewritten at some time.