8 Signs of Low-Quality Software That Business Stakeholders Can Understand

In a previous article, I laid out 7 Signs of High-Quality Software That Business Stakeholders Can Understand so that good software and their developers would be appreciated. In this article we will examine eight signs that reveal their counterpart, that is, low-quality software.

In a world where the average person cannot tell the difference between high-quality and low-quality code, then unfortunately, all software engineers become ordinary as a result. Indeed, the reality is that developers in general are typically perceived as being exactly on the mean as well as on the median in terms of skill level, thereby reducing them to mere commodities. In essence, from this perspective there are no good, bad, or average developers. There are only developers.

While it is important to recognize highly-skilled developers , it is also important to recognize lower-skilled developers. Because recognizing and rewarding excellence also helps promote a culture of excellence in the organization. And a culture of excellence causes the skill level of bad developers to rise, which then brings about a corresponding increase in the quality of the code produced. But in order to know what is beautiful you must first know what is ugly. Therefore, it is my hope that this two-part series will help you distinguish between high-quality and low-quality software so that you can implement measures that sustain the prevalence of better code.

#1 – Development Takes Relatively Long

Some of these signs are direct opposites of the signs of high-quality code , such as this one. As the software gets closer and closer to completion or after the first version of the software has already been delivered, if at that point development of new features takes relatively long, then this is a sign of bad architecture and low-quality code. When software is well-designed it allows developers to add new features in a relatively short amount of time.

The difference between a long time and a short time depends on many factors. If the requirement is to change a label and it takes a day or two to modify (I have seen this happen), then that is a clear sign that bad code lurks beneath. If the requirement is to add a feature that is new, different, and unanticipated involving multiple artifacts, complex business rules, and/or weird exceptional cases, then the fact that development for this takes a long time should be understandable and appropriate.

In general, over time you should see that ordinary additions to the software should take a reasonable amount of time to implement. But if it takes a strangely long time to implement the requirement, then this is a red flag.

#2 – Development is Relatively Difficult

This item is also an opposite from the signs of high-quality code . In the first part of this series, I described in the second sign that developers will think out loud in terms of what needs to be done to implement a requirement. A quick summary of this is that when discussing a requirement, developers tend to talk about all the things they will need to do to implement the requirement. The more artifacts that are mentioned and the more logic that is mentioned, then the more effort it will take and the more difficult it will be to implement the requirement.

When listening, you don’t necessarily need to understand the mechanics of what the developer is talking about but you should be able to do two things. Count the number of artifacts mentioned and count the number of logic concepts mentioned. If the requirement is simple, then the total number of these concepts should be fewer. If the requirement is indeed more robust, then it is understandable if this number is higher.

As mentioned in the first part, you should keep in mind that the relevant concepts are only those within the control of the developer. In other words, consider only the concepts within the code that the developer builds. If there are concepts outside of the developer’s control, such as source data from other systems, then those concepts should not be considered in this exercise.

#3 – When Change Begets Unrelated Change

This is one of the most helpful indicators of bad software design partly because it is easy for the layman to identify. While adding new features or requirements to the software, if changes in unrelated places of the software becomes necessary to complete the task, then this is a huge indicator that it suffers from bad architecture and low-quality code.

One of the guiding architectural principles, and in my opinion the most important architectural principle, is called the Single Responsibility Principle. It means a component should be responsible for one and only one thing. Many times, a feature will impact many components each of which have their own respective responsibilities and that is okay. But when a change becomes necessary in a component that is quite unrelated to the feature, then it is a sign that the Single Responsibility Principle has been violated. Make no mistake, when this principle is violated, very bad things happen.

I worked at a Fortune 500 company where it took five development teams nine months to change the header of their e-commerce website. That is no exaggeration. This happened because there was a lot of code that was triggered in the components that rendered the header, and each team had their own duplicate versions of the header. When the design of the header needed to be changed, it impacted components of code across all teams and all the way down the stack to the data. How did this happen? Well, the company did not have a Software Architect empowered with oversight when the website was created.

#4 – Things Break Unexpectedly in Different Places

This red flag is related to #3 above. In the previous sign, we examined the recognition that things in unrelated places need to change in order to implement a requirement. That happens when developers successfully identify the things that need to change ahead of time. But these dependencies are not always identified, giving rise to the infamous “bug.” If a change to the software causes something to break in an unrelated part of the software, then this is a huge sign that the software was implemented with bad architecture and low- quality code.

This sign and the previous sign likely have the same root problem, which is that the Single Responsibility Principle (among other principles possibly) was violated. The difference is that in the previous sign, developers got ahead of it and were aware. In this sign, they didn’t catch it so the change causes something to break somewhere unrelated when the software is in use.

If developers aren’t aware of this, causing the bug to remain, it is usually caught in an environment higher than the development environment. In other words, it can be caught in the QA environment by a tester, or the User Acceptance Testing (UAT) environment by a user. The worst-case scenario is when the bug is produced in the Live Production environment, which is very possible because most times QA Analysts and Business Users don’t think they have to test unrelated parts of the software. Automated Regression Tests help mitigate this risk, but they are difficult and expensive to put in place.

The moral of this story is to look out for bugs popping up in unrelated places. It is a huge red flag.

#5 – Veterans Leave While Rookies Stay

If you are a practitioner of literally anything, then you understand first hand that the longer you work at something the better you get at it. It is no different in software engineering. Even though some people reach greater levels of mastery than others, on average developers that have been around for more years will be better than new developers. It’s not a given though. I have worked with software engineers that have been in their careers for over a decade and still wrote bad code. But most engineers that have been around fifteen-plus years are fairly above average in their skills.

Although the length of tenure in one’s career is not a direct indicator of skill, in the aggregate it cannot be true that all decade- plus veterans of software engineering are bad. Therefore, if you see a trend where veteran (decade-plus) software engineers tend to leave the company and the newer developers (under a decade) are the ones who stay, then this is a sign that the software they are working with suffers from bad architecture and low-quality code.

Why is this the case?

Software engineering languages, tools, frameworks, patterns, and overall technologies are constantly changing at an extremely rapid pace. The average person does not realize just how much we have to study, study, study throughout our careers to stay relevant. It only takes one job in a bad place over a year for an engineer to lose vital experience in the latest technologies. If a developer needs to get a job somewhere else without experience in the newer stuff, it becomes difficult to nail one even if you’ve been a software engineer for many years.

When working in a place that suffers from bad architecture and low-quality code, it becomes near impossible to transition or upgrade the systems to the new operating systems, browsers, or development frameworks. When this happens, it’s tantamount to sticking a dagger in a developer’s career. They become dinosaurs. Veteran software engineers know that this is extremely destructive to their careers, so part of maintaining their career entails leaving the company when their systems are bad enough to cause their skills to stagnate.

Furthermore, working with bad code is absolute misery. When good developers have to work with bad code, it is tedious, error-prone, complicated, and draining. It has a profoundly negative impact on their mental state every day. If a good developer feels that it is insurmountable to clean it up for whatever reason, then the better option is to just leave. Unfortunately for businesses, software engineers are in great demand so it is extremely easy to go out and get a new job. There just isn’t enough incentive to stay, suffer, or worse, ruin their careers. After that, the only one who truly suffers is the business and its bottom line.

#6 – Frequent Firefighting

If software being used in production requires frequent intervention by the developers of the code to get through problems, then this is a sign of bad architecture and low-quality code.

One of the joys of being a software engineer is that when it’s done right, the vast majority of the work is in development, not in production. This means that nobody’s using the things we’re working on. Because of that we get to work 9-to-5, take weekends and holidays off, and otherwise enjoy a reasonable pace of work even when compared to hectic deadlines.

It is a job that is unlike that of, for example, a Network Administrator. The things Network Admins work on are network devices and infrastructure that are constantly in use by the business throughout their day-to-day operations. This is why a Network Administrator must be accessible every day, even weekends, holidays, and vacation days. It’s not uncommon for them to carry laptops everywhere they go.

But what happens when software is delivered, in production, and in constant use as well?

In that case, if the software is well-designed, it should just do its thing. It should just work. The whole purpose of software is to provide tools that remove the dependence on software developers to do things. So, if the software in use frequently produces errors, bad data, goes down, performs dismally slow, etc. then developers have to stop working on new stuff and instead refocus their attention on “Production Issues.”

When this happens frequently, we call it “firefighting.” Something comes up, “a fire”, and you have to drop what you’re doing to put it out. In other words, the priority is always to resolve production issues immediately. This should not happen. The occasional bug or issue is to be expected, but not so much. When developers are frequently firefighting, it is a huge sign that the software suffers from bad architecture and low- quality code.

#7 – Estimates vs. Actuals Are Wildly Inconsistent and Inaccurate

As mentioned in the first article of this series, if estimates for the development of new features are consistently under a 20% margin of error relative to the actual time and cost of completion, then it is a good sign. On the other hand, if estimates are wildly inconsistent across the board, inaccurate, and the actual time and cost of completion is consistently over that 20% margin of error, then it is a sign that the software suffers from bad architecture and low-quality code.

Software development is near-impossible to predict accurately, which is going to be the subject of a future article. However, the smaller the feature or task, then the lower the error margin should be on average. The key word that I use for this sign is “consistently.” A few features that have taken too long isn’t enough to declare that the software is of low-quality since it is quite common for that to happen now and then. But if they never get the estimates right for anything (i.e., consistently out of whack), then that should give you pause.

This happens when even the best of engineers and architects cannot predict how long it will take to do something due to the fact that the software is riddled with spaghetti code. When software architecture principles are violated and there’s a lot of it, then the impact of changes can only fully be discerned when they actually get into the code, make changes, and test things. If developers don’t know what will happen until they code it, then the accuracy of estimates goes out the window, which is why it is a sign of bad architecture and low-quality code.

#8 – Prevalence of Tribal Knowledge

A good developer will code himself out of a job. Meaning, that the best job a software engineer can do, is to do it so well that the software does what it’s supposed to do, is reliable, is documented internally and externally, is well-designed, and can be understood by another sufficiently competent engineer simply by examining the artifacts of the software itself.

A good test of that is to consider what would happen if your key developer won the lottery and ceremoniously booked a one-way flight to Hawaii never to return. If the answer is that other people could pick up the work and figure things out quickly by looking at code and documentation, then that developer figuratively coded himself out of a job since the business is not dependent on him.

The opposite of this is when software is built in such a way that even the best engineers cannot reason about what is happening because it cannot be discovered by examining the artifacts of the software only. It requires knowledge of things that cannot be ascertained through an examination of the software itself.

This is what we call “Tribal Knowledge.”

Given enough time, money, and resources, software behavior and their dependencies can eventually be reverse-engineered to discover the necessary information. But when there are mechanics in the software that don’t have an obvious connection somewhere, it takes an extremely long time to figure out what is going on unless someone who possesses the tribal knowledge cuts you to the chase.

Those who know where these related components are and how they function are the team members with key knowledge that allows them to hold the company hostage in various ways. Some people use this to protect themselves from discipline for bad behavior (e.g., being late, bad attitude, etc.), to prevent others from being promoted over them, to get more money, and generally any other thing that protects their status and position. Not all of them do it for political purposes to be sure. Some end up acquiring tribal knowledge simply because they built bad software and they just happen to be the only ones who know how some things work. The effect is nearly the same. The company is beholden to the person with key knowledge.

When you see that experienced software engineers need to constantly ask a particular person questions about how something works because they can’t find it in the code, then it is a sign that a fair amount of tribal knowledge has accumulated. This in turn is a red flag that the software suffers from bad architecture and low-quality code.

Keep in mind that in the beginning, it could simply be knowledge transfer to get someone up to speed when the person is new to the team. Instead of burdening the new team member with reverse-engineering the code, an existing team member can just show them around to make them productive easily. You can tell the difference when you hear an experienced engineer that recently joined the team say something like, “Oh I would have never figured that out on my own.” This person knows that the existing team member didn’t just relieve them of figuring it out. It suggests that no matter what, the new engineer would not have figured it out on their own. Knowing where the disconnect lies then ushers that new person into the tribe. If you’re ever in doubt, you can simply ask the new person if there was some way they could’ve figured it out on their own in a reasonable amount of time. If the answer is no, then it is tribal knowledge.

Conclusion

Poorly-designed business systems can be crippling and just getting by every day doesn’t cut it if you want your business to thrive. Even if competitors struggle with the same challenges, then good software could be a game-changer over competitors in the market. Being merely on par with rivals in terms of mediocre systems represents a major loss by opportunity cost because otherwise, good software could be the difference between competing and dominating.

One great example of this is the rise of Walmart that brought K-Mart, the leader of its time, to its knees in the 90’s. In Sam Walton’s autobiography, “Sam Walton: Made in America” he explains how their tenacious commitment to high-quality technology gave them such immense operational excellence, that they were able to provide cheaper products to the extent that competitors would go bust had they tried to match. It wasn’t the only contributor to Walmart’s success, but doing things like being the first corporation to put a satellite in orbit to manage their fleet of trucks, and building 1.9 million square foot distribution centers with the highest-grade automation of its time, among many other high-quality systems, was certainly a huge factor.

You shouldn’t settle for software development that is going to leave your business riddled with problems and difficulties when you need to maneuver. If your business is big enough to employ your own internal software development team or even a single engineer, then it behooves you to know what you’re paying for. Even if you hire an independent software development shop to do the work, then you should do the same. You won’t be privy to some of the interactions and information that will reveal the signs in this series, but you should be savvy enough if you pay close enough attention.

After decades honing my skills in software architecture and building custom software for many different businesses, my advice to you is that if you see these signs of bad architecture and low-quality code, then for the sake of all that is good and holy, take the necessary steps to slow its spread and eventually stop it altogether. Your business will reward you for it, financially.

Contact Today for Free Consultation