Before the 2000s, software development was mostly done in a Waterfall approach. This meant that a software project would be shipped after going through a few long stages such as analysis, development and QA, just to name a few. This led to slow software development cycles and, consequently, improper decisions were made in the early stages of the lifecycle, leading to poor or unfit software.
Nowadays, most great projects are developed in an Agile fashion, using philosophies like SCRUM or Extreme Programming. These methodologies promote fast software development, usually by shortening the cycles and by shipping often.
Nevertheless, some industries still rely on Waterfall to deliver software, as it's still the best approach for their goal. Take Aerospace, for example. If you're going to launch a satellite with some onboard code, you won't be able to deploy an update to it if the onboard update software is broken.
This was also one of the reasons why Waterfall was so popular. Shipping software was more expensive compared to how it's done today, as it usually involved magnetizing a cassette, floppy disk or burning a CD before shipping the software worldwide to be installed on computers that would never get a connection during their lifetime.
I've participated in many projects and helped more teams shipping software than I would like to remember. I was lucky to work with companies shipping great software, and others struggling to keep the pace on quality, schedule and budget. I've noticed that the key to ship great, predictable software is not in the methodology that you use, as some did it well in Agile while others were mastering it in Waterfall. The key to success was on their development processes, and some didn't have a written one. Their product team was just following a set of tasks to deliver new things in a repetitive way, allowing them to control where things were working and improving the ones that were not.
These processes were different from team to team, and the number of steps for getting a feature done was usually not the same. But all these processes had common traits on how their teams approached the development cycle. This is what they didn't do.
It's easy to get excited with a new idea and everyone wants an immediate piece of the action. Resisting this temptation is difficult and often key to get things done faster. This is sometimes difficult to understand, especially if you are in the early years of your software development career.
If you think carefully, a feature that took half a day to define and a couple of days to design can easily take a week to implement. This follows the natural order of which things are easier said than done.
Great teams spend time analyzing a problem and defining an approach to reach a solution. There is a balance on how much you should spend in the thinking phase, and this might depend on the criticality of the product and the cost to ship a new version. But great teams always spend time designing a solution before starting to implement a new feature or fixing a bug.
We've all been there. The product owner says that a feature is not relevant anymore, you go through the code to remove it, and a few weeks later someone asks to add the feature back. We never know when the code that is useless now will be needed again, and commenting or leaving it there seems like a good idea. Dead or commented code can't hurt, right? Besides, if we leave the code there, we save time by removing the need for understanding if there are other dependencies from it.
Unfortunately old or commented code create what is often called technical debt. In the future, other developers will stumble on the dead code and it will slow them down. Files get bigger, code will be harder to read and chaos settles.
There is a better alternative to avoid eliminating a working feature without storing the code somewhere. With modern versioning control software (i.e. git) it's very easy to identify when and which changes were made, and retrieve the old code if necessary. There is a good reason why tools like git highlight how many lines of code were deleted in each commit. Removing code is as important as adding new one.
No one talks about this in college or university, and no one talks about it in the many software development courses out there. But people deploying to production regularly learn this as soon as they start working on their first project, and they often hear it the hard way...
When things go sour in production someone's phone is going to ring. And I bet that it's harder for that person to assemble the project team and fix everything during the weekend than on a weekday. Some people even like to get off the grid on weekends, and good luck reaching them.
It's easier to explain to a product owner why there are no deploys on Fridays or before holidays, than to fix a problem without a functional dev team when it happens. And believe me, it doesn't matter how many tests you do before shipping the code. If you deploy often, issues will hit the fan once the code is live.
I see a lot of teams neglecting test automation. Sometimes because there is manual QA, others because there's simply no schedule to develop tests.
Automated tests guarantee that things run OK when they are deployed, and also ensure that new features will not break old code. You can seem to get away without automated tests when the codebase is small. However, code doesn't age well, and Uncle Bob wrote an entire book to reinforce this sentence.
If you're not developing automated tests as you go, changes will be harder to make, people will have trouble joining your project as it grows, new features will be harder and harder to deploy and, in the end, there will be so many bugs in production that your bug report will grow faster than you can deploy patches.
Always make sure automated tests are being done from the early stages of the development effort. And if you ask "how much is enough", feel free to check my article about the topic.
A lot has happened since the initial approaches to Continuous Integration in the late 90s (see Kent Beck's famous Extreme Programming book, among other publications from that time). But there are still a lot of teams that don't adopt this approach from day one and end up having manual deployment processes.
The way for a feature or patch to go from a code repo to production should be a well-defined and automated process. Besides, obviously, avoiding human errors, it gives confidence to the team to deploy often, allowing product owners to have regular feedback about the direction in which the product is going, also improving its chances of success.
Part of this was already covered when we went through why automated tests are important, but that was only a minor part of the QA process. Automated tests per si just ensure that the code is tested up to a certain coverage and nothing more.
A good QA process ensures that the code was verified and is valid. These are often called as the verification and the validation stages of the QA procedure.
For this to be implemented the right way, we need to ensure that the person writing the code is not the one verifying or validating it. Doing it this way avoids the tunnel vision effect, that prevents people from spotting their own mistakes. Ideally, verification (e.g. code review) should be done by another developer and validation (e.g. feature demo) by the product owner.
One of the great breakthroughs of the Agile Manifesto was to put "People over Processes". This is in fact key to ensure that we get the full potential of each and every member of the development team. But putting people over processes doesn't mean there shouldn't be processes at all. Some people say that they don't have processes but after spending some time working together, they sure have a way of doing things. This is defined by combining personal experiences and evolves on every iteration until it stabilizes. It's the natural process of a group to compile a lot of knowledge about what works and what doesn't work for them.
When you pick up a process from another team, you are in fact taking a grasp over what they've learned. Processes exist because people identify which steps or tasks work best and in which order. For this reason, processes are knowledge. Plus all good processes evolve, and change as the needs change. But if you're going to design the development process of your team or project, the best way is to start by defining what you already do now, and then crosscheck with this list and see if you have all points covered.
Here, at Imaginary Cloud, we always have this in mind while building a web or mobile app for our clients. If you’re developing one of these digital products, we would be pleased to help you! Drop us a line here!
Found this article useful? You might like these ones too!
Previously published at https://www.imaginarycloud.com/blog/the-donts-of-software-engineering/