How much is it going to cost me to implement these Unit Tests?
Is this refactor really necessary? Money doesn’t grow on the trees, you know…
As mobile devs we’ve heard similar questions more times than we care to remember. Whenever we brooch the subject of improving the quality of our code, the business usually becomes defensive. And you can’t really blame them. From the business perspective, any changes to the code that do not add value for the user, are essentially a wasted money.
Trying to minimize loss above all, the business wants to know precisely the cost of improving the quality of the codebase. Hence the question: what is the cost of quality? Sadly, this is an incorrect approach. Instead, the business should be asking:
What is the cost of LACK of quality (in our projects)?
In this blog post we’ll try to answer this question together. Strap in and let’s go!
Quality is not a cost!
Quality is an integral part of the Definition of Done (DOD) and one of the most important deliverables of every user story. Only full appreciation of this fact by an entire project team can guarantee sustainable development speed across the project timeline.
When we neglect quality in our projects, 3 things are guaranteed to happen:
- The business becomes a hostage to the codebase
Think about all the cool features your competition recently introduced. You wanted to release almost identical features 6 months ago, but you weren’t able to do so. Not due to the lack of time or resources, but because the codebase of your app simply did not allow that change at that moment. This is precisely what being a hostage to the badly written code feels like…
- Changes become more and more time-consuming
Do you remember times when features took only hours to implement? When was the last time you could just focus on… implementing a feature? Without fear of breaking something? You see, the software code is like a garden. Without regular pruning, de-weeding, etc., it quickly overgrows and starts to decay. As it happens, adding a new feature or changing an existing one takes progressively longer time to implement. Up to the point when it is no longer even possible…
- Less opportunities for feedback
Finally, not being able to quickly deploy new features robs the business of a critical tool necessary to run a healthy IT product – early feedback. When I started my career as a software developer, the industry was just starting with Agile practices. Those days a different project management methodology reigned – the Waterfall.
TLDR: Waterfall assumes that you should not release the application until it contains all the specified features. This approach led to truly heartbreaking situations, where a team worked for years on features the users didn’t need in the first place. If you want to go back to the pre-Agile days, just keep your codebase “dirty”. Releasing the app once a year would soon become your reality 😉
In all seriousness, however, if your project is to stand the test of time, its codebase must be kept to a standard. Without regular refactoring (e.g. by applying the Boyscout Rule) and a comprehensive set of Unit Tests for business logic and views, it’s hard to expect maintaining the same development speed as the project becomes more mature.
That wasted time, missed opportunities, and lost chances to get early feedback, are the true cost of lack of quality in our projects. Is the business in your project willing to pay it?
Quality is always expected
Can you remember a situation when you were asked by the business to just finish a given feature regardless of the quality? That it was critical to the continuation of the project? That you’ll have plenty of time to refactor later? That they took all responsibility should any regressions or bugs have occurred?
And how did these promises work out for you? In my case, I never got “time for refactoring later”, nor did the business ever take responsibility for any bugs introduced during rushed development. Why is it always this way?
You see, no matter what the business tells you, they’ll always expect the highest quality of your services as a developer. Furthermore, as people responsible for the project’s success, they want to push the speed of development as far as possible. As they don’t have technical knowledge, it’s difficult for them to foresee the mid to long term effects of their actions. They expect you to deliver your work ASAP, but also in quality.
Let’s take a real-life example: fixing a car in a hurry. Imagine you’re going away on a road trip. To make sure everything is fine with your car, you brought it for a checkup. Unfortunately, the mechanic says that the brakes are leaking… What do you do? Of course, you pressure the mechanic to finish the repair ASAP but you expect the fix to be done in quality! You don’t tell them to use duck tape and zip ties. That you don’t care if you crash 10 min after leaving their workshop, etc. And even if you do, any mechanic with an ounce of professional decency would simply refuse, knowing full well that a hack job on a critical system of a car can cost a client their life. Yet, in many IT projects we as developers do exactly that. We agree to implement features in substandard quality because the business tells us to do so. Regardless of the consequences.
Ok, but maybe the business is right? Maybe there are specific projects that really don’t need to be developed in proper quality? As it turns out… there are:
- Proof of Concepts (POC)
As the name suggests – simple projects that exist only to prove (or disapprove) a given concept. After completion, the code of such a project should be scrapped. We don’t want the team responsible for developing a production code to copy-paste the substandard solution, do we?
- Corporate R&D projects
TLDR: these projects exist only to burn the corporate R&D budget and showcase how innovative a given organisation is. No lasting results are expected of such projects. A nice report and a fancy presentation for the board members is more than enough.
Scammy projects are built for one purpose only – to help the team persuade gullible investors to part with their hard-earned money. When less technically-savvy people see incredible speed of development, they are more likely to believe the project is genuine. Sadly, the project stops as soon as the team acquires enough capital to retire in the tropics.
In any of these 3 cases, the developers can then be “forgiven” for not prioritizing quality over development speed. However, if your project does not belong with these categories, the quality of the code you produce will always be important.
But what shall I do when I just want to experiment? Implement a quick POC to prove some business assumption before committing more resources into the topic? Sure – you can do that. This is precisely what experimental branches are for. If you have your CI configured properly, you should be able to release such an experimental app with just a few clicks. The business then can assess if the experiment was a success or not.
Remember one thing though: experimental code can be treated as such as long as you have no intention of merging it into the production branch(es). The moment a PR is created, the change has to meet all the quality requirements defined for the production code: separation of concerns, Unit Tests coverage, public API documentation, etc.
What’s the cost of poor morale in the team?
So far, we’ve been discussing only financial risks associated with having poor quality of code in a project. Arguably, a messy codebase has more profound consequences than just wasted money. Enter the cost of poor morale in the team.
First thing you can expect is the best people leaving. It should come as no surprise – especially skilled developers have many options and will always be in high demand. With them leaving, a vital part of knowledge, experience and know-how also inevitably exits the project.
On the other hand, people who choose to stay develop a characteristic “I just work here” attitude. They no longer care about the app users, regressions or overall success or failure of the project. They just want to get through the day without a major fire to put down…
All these combined result in low empowerment. The team no longer believes they can change anything in the project. They become reluctant to improve the codebase, try new frameworks or libraries, etc. In short – nobody is willing to take any risks, fearing introducing regressions or delaying the app deployment. It must come as no surprise that such an environment does not stimulate learning and innovation. It is also almost completely devoid of passion. Naturally, I’m not taking into consideration the app users complaining about the quality of the latest release. These are sure to be passionate enough!
Delivering fast != delivering crappy code
If you want to deliver fast, you can’t be too picky about the quality of the code you create. We’ve heard that a lot, haven’t we? This statement is arguably one of the biggest misconceptions in software engineering.
In all honesty, It would have been true if we really had to provide 100% Unit Tests coverage, refactor all legacy views, etc. In short: treat every line of code we wrote equally. Naturally, lines of code, unlike people, are NOT equal. Some of these lines e.g. govern critical parts of the client’s business process, others e.g. tertiary user settings.
And as it happens, there isn’t much of that really important code to cover – approx. 20%. Where is this number coming from? If you haven’t heard of the Pareto Principle (a.k.a. 80/20 Rule), I sincerely recommend you read up on it. In short, it states that 80% of the outcome is an effect of 20% of the action. E.g. 20% of the biggest clients can bring up to 80% of company revenue, etc. This rule applies to software development as well. We can safely assume that 80% of the app functionality is handled by only 20% of the code. Our job is to identify this critical 20% and implement it the best way we can.
Ok, but how can we know which flows in the application are really crucial? By understanding the client’s business processes, of course!
Investing some time into discovering these processes and documenting them can yield amazing results. Both: in terms of improving the quality of the app, and building lasting relations with the client.
For the sake of argument, entertain the following situation. You have 2 UI bugs in the app: one in the Release Notes view, the other on the Checkout Confirmation screen. Which do you think is more concerning to the client? Which should be covered, e.g. with Snapshot Tests? Pick your battles wisely 😉
How can I incorporate quality into my daily work as an iOS Dev?
So far we’ve discussed the true cost of NOT having quality in our projects. Both financial, and in terms of poor team morale. We established that the high quality of work will always be expected of us as developers. We’ve also disproved one of the most common misconceptions is software development – that fast delivery must result in poor quality of the code.
That brings us all to the mother of all questions:
How can I persuade my manager to (graciously) allow me to produce quality code?
And the answer is… You DON’T!
Seriously, you shouldn’t need to ask for permission to produce good quality code! Always treat yourself as a highly trained professional: a doctor or an architect. People expect these specialists to solve their problems, but don’t dare tell them how to do their jobs. You wouldn’t come to a GP and tell them how to treat you, would you? Instead, you rely on their knowledge and experience, allow them to diagnose you and propose a treatment plan. How cool would it be to be treated like that in our line of work…
To help you get there, I’d recommend establishing a development standard. I know, it sounds mouthful, but it’s nothing more than just a set of promises you and your team agree to uphold. No matter what. These rules could be as simple as e.g. never deploy a manually built app to the App Store. Or never to introduce warnings with newly written code.
Once such a standard is set, make sure it’s known to everyone in the team and enforced through team practices: code review, retrospectives, etc. You see, team practices always reflect team values. If you value honest feedback, you’d insist on having regular retrospectives. If you value clean and readable code, you’d most likely establish a thorough code review.
Next great improvement would be to introduce automation to all the applicable practices. E.g. code review could be greatly enhanced (and sped up) when a PR is annotated with linter and formatter warnings, unit tests coverage for the modified files, etc. Even a simple script moving a ticket to the QA column once a PR is merged could be a great help.
One last bit of advice: remember about keeping the score. Only the measured parameters have any chance of improving. If you want to raise e.g. unit test coverage across the project, you would not succeed unless you ensure this value is accurately measured and easily available within the team. A great idea is to use xcov plugin for Danger to annotate your PRs with overall coverage level.
Disclaimer: All memes used in the post were made for fun and educational purposes only
They were not meant to offend anyone
All copyrights belong to their respective owners
The thumbnail was generated with text2image