loading...
Cover image for How Bad Software Gets Made

How Bad Software Gets Made

yelluw profile image Pablo Rivera ・3 min read

I have worked in many different software projects. Some successful and some not. It turns out that bad software projects have similar traits. These are some I've been able to identify throughout the years:

Poor technical leadership

Chaos and poor decision making does not translate into quality. Good software does not happen by serendipity. It is the result of organization and decision making based on facts. Strong technical leadership also sets the habits for the rest of the team. People learn by example. Technical leaders have to set the example for others to follow.

Undefined responsibilities

People need to know what they have to do. What their basic responsibilities are. Otherwise, they will point fingers and accuse each other when things fail. Its important that we give people the opportunity to do great things. The way to achieve that is to give them opportunities that have a certain level of expectations.

No testing

There is a surprisingly big amount of software being written today without any sort of tests. No unit tests. No integration tests. Not even “does it work on your machine? tests. The code gets written (or copied from the web), compiled, and pushed out. I've seen companies fail due to abysmal product quality that is the result of no testing.

Unwillingness to train

We cannot expect everyone to know everything and to be up to speed on every single technology, so training is essential. A team of developers that does not get trained only grows at the rate of the least trained person. If you pay thousands of dollars a month for a developer, it is worth taking an hour or two a month and train them in some technical subject. Be it testing, coding, a new language, a new paradigm, anything at all.

I think environments that do not promote training comes from the corporate attitude of not investing in their people. They seem to fear that people will leave for better jobs once they acquire new skills. Which happens, but in my experience, is not as big of an issue as they make it seem. Not training someone out fear of them leaving is equal to not falling in love out of fear of being hurt. Open source projects should also train contributors, be it in the form of documentation, a video, or something else. If you train your contributors they will grow and produce better code. The scenario is win-win for both sides. I have only seen a small subset of open source projects that train people. Its no coincidence that these projects are also successful.

Toxic members

Some people are good at writing code but bad at dealing with people. Software is made by people for people. You have to make sure that toxic members are handled properly. Sometimes people become toxic because the leadership is poor (item #1). A lot of toxic people are just burned out. Dealing with toxic people is a complicated subject, but being able to identify a toxic member is enough to improve the conditions for those affected.

Focusing on the short term goals

Pushing code without tests in order to solve a “corner case sounds like a great idea at the moment, but developers must look at the bigger picture. You might have given the OK to others to do the same thing on a bigger scale. Have you ever worked on a project that had tests but now doesn't? Guess how it happened.

What if your project has one or more of these traits? Don't panic. It can be fixed. The important thing to understand is that bad software is a result of things within our control. Knowing and accepting that we can improve things is the first step towards turning around a project.

PS. Follow me on Twitter and Snapchat @pryelluw.

I'm available for Python,
Django, and Javascript projects.
Contact: pr@yelluw.com

Posted on by:

yelluw profile

Pablo Rivera

@yelluw

I build awesome stuff at Yelluw. My blog --> pablojuan.com

Discussion

pic
Editor guide
 

I think an an issue underlying all of this are some "too late now", or "sunk cost" fallacies. When the problems start mounting up, it's easy to just grit your teeth and not make changes. It's never too late to start adding tests around key paths and going back to the drawing board in terms of how a team communicates.

 

Either correct course or abandon ship. There should never be an in between decision.

 

One thing I've seen produce terrible software on a consistent basis is the idea that every single problem needs to be solved up-front. I've sat in meetings where discussions were dominated by calling out every hypothetical use-case that "needs" to be accommodated, with little time dedicated to discussing the primary use-case. "Good intentions" win every time. How can you disagree that shipping something that accommodates every possible need and desire is bad? Management loves it! Now let's start discussing a wildly optimistic timeline!

Something I can be heard saying often at work: "Perfect is the enemy of good."

Take your feature and have a well defined minimum viable product. Implement it, write good tests and ship it. Catalogue feature ideas. Prioritize them. Implement features atomically, A/B test them. Customer behavior often defies expectations, so it's important to see how they're using and interacting with your stuff before committing to something. You lose all this when you start with a pile of assumptions and usually end up with a pile of shit.

 

I agree 100%! one thing that I'd like to add, is that these ideas of keeping the scope narrow and not building more than you have to are concepts that apply at different scales.

It applies on a macro scale when talking through and defining requirements with product management, but also on a micro scale in individual pieces of code. I often comment in code reviews: why all this extra code to handle a special case? Is it something we need to support? Do we know that this is correct way to handle it, or are we just guessing?This can sometimes result in deleting code even though it was already implemented, and our code base is better off because od it...

 

Aggressive deadlines sold to customers / clients without consultation with the engineering team.

 

Lack of user involvement

Software developed without involving the users inevitably address the wrong needs. You need users, use-cases, and target audiences to figure out what to develop and how it should work. There is way too much software developed in isolation.

 

I could not agree more with that final clause. Always solving immediate issues without investing in long term problems is wrong in any part of managing a company, but when it comes to code it truly is the worst decision you can make. I was privileged to work on such projects and it was a nightmare.

 

Bad software gets made by incompetent people, usually with the best intentions. There are people that are incompetent because they lack experience (i.e. it is fixable) and there are people that simply aren't that good and will never be. But don't blame these people, blame the people that hired them instead. You get what you pay for generally. These problems always boil down to lack of leadership and vision. Incompetent people are the symptom, not the root cause. Everyone with a clue already left.

As an engineering manager you only have two options when faced with dysfunctional software teams: you fix it or you leave. This sounds simple but it is surprisingly hard to walk away from a comfortable salary even when you don't stand a chance in hell to make a difference. Quitting is scary.

Fixing broken projects is hard though and requires full support from whomever is financing the project. If that support is not there, quitting is your only option. If it isn't you might want to wake up to the fact that you are part of the problem, not the solution. If it is there, start by dealing with the incompetence. Coach, hire, & fire as needed. I've fixed projects by reducing team size. Small teams are much more agile and easier to manage. Sometimes all you need to do is focus around a few good people and then empowering them to do their thing. The next steps are introducing leadership and making tough calls on what to keep, what to fix, and what to decommission. That requires vision for what is needed. Often that was all that was missing.

 

This is a such a tough topic! I think you did a good job hitting the highlights, thanks for posting.

I want to throw my opinion out there and see what people think about it. I'm okay with sacrificing on code quality for the sake of speed if it means fulfilling some business need, AND there is a plan of action to rectify the technical debt. This becomes an issue when there isn't good project leadership on the product side or the development side. Trusting leadership is huge when it comes to this sort of approach.

Thoughts?

 

I don't believe that quality must be sacrificed in order to gain speed. It's a lie to cover bad code that is produced by forever hacker type people. As senior developers, the experience, problems faced, tools, patterns and practice should have given all you need to code fast and with good quality as opposed to junior people. Lack of quality comes from lack of knowledge, more than lack of time. This can be applied to anything, not just code.

 

"...the experience, problems faced, tools, patterns and practice should have given all you need to code fast..." is not true.

 

A similar issue to "toxic members" is "incompatible members". It's quite possible to have excellent programmers that simply don't mesh well enough to work together on a project. However, they're often forced together for various reasons (bad management being one) and the working relationship turns toxic, resulting in missed deadlines and worse.