Pick any two. These three work in tension against each other on any project, whether code or otherwise. But let's talk code 🙂
The customer wants it yesterday. Well, it always feels like that. Even if they did say that they want it in 3 months, 3 months ago!
We want to put out a good product. We want it to work well, look good, be well-tested and easy to maintain -- because if it's a good product, chances are good the customer will want it to be extended, and hopefully the customer is paying us to do so!
Every customer wants their software for free (or at least peanuts). We can't really blame them, when anyone can download an entire operating system, jam-packed full of useful software, for free. We're talking about millions of lines of code, hundreds of thousands of people-hours making a finished product like Ubuntu. Think about that for a second -- and it's free!
Image discussion: examining the image, we can see the three constraints: getting the job done quickly (top), getting the job done with maximum quality (bottom right) and getting the job done cheaply (bottom left). The vertices explain what we get if we adhere strictly to two of the constraints:
- Cheap & Quick means we sacrifice Quality
- This is often what customers think they want, but we should try to steer them away from this, or at least make it clear that going this route will mean that the project will be difficult to extend. This may be OK for a proof-of-concept where it's accepted that, if the idea floats, a new version would be made from scratch and the learnings of the first version
- Cheap & High Quality means we sacrifice priority
- We can afford to do this on, for example, our own personal projects, where there's no-one clamoring to "get it done". However, we run the risk of simply never completing the work. This isn't a bad place to be if we can stick to one goal: keep it simple.
- Fast & good means expensive
- This is probably (in my opinion) the better place to be when working for clients: focused on getting out the product, but with a keep eye towards quality, never sacrificing quality to meet a deadline. If you want to get here, though, you're going to need buy-in from the customer. Most customers don't understand the cost of rushing and cutting corners in software because they're not software professionals -- that's why they came to you! It's our job to sit with them as often as possible to explain why we're spending the time on quality and to make it very clear when they request a short-cut that it will cost something later. We also need to record this technical debt, so that they can see that it grows with each decision to reduce quality in the name of cost or time, and so that when we are asked to work on that same area again, to extend it, we can bring up the technical debt and explain that the outstanding work must be done before we can safely extend that area.
So when we're working on a project, we have to get the customer involved as often as possible (invite them to your standups -- this worked really well on projects where I've experienced this) and ensure that we're staying in the best place for everyone within that triangle. In particular, if we care about our craft, we have to:
Make quality a requirements issue
This means bringing it up at client meetings, establishing the level of quality that the client wants and that we want and sometimes advocating for higher quality than the client thinks they want, leveraging our experience. For example, the client who says "I don't want to pay for time spent writing tests": explain to that client that there's a small initial fee, sure, but the result is that the solution can evolve much easier with the client's requirements: when there's a new requirement, TDD-ing out that requirement and then re-running all tests can help to prevent new features from breaking existing ones.
We also need to know when to stop -- when is this good enough for the requirements? Knowing that we can never make it perfect should also be freeing: when it feels good enough for now, then it is. No need to spend another hour polishing -- move on to another feature 🙂
There's probably no "one size fits all" answer to this discussion, but my advice is to try to tend towards the Quality point of the triangle, leveraging the time and cost points to find a comfortable space for the customer. Keep the requirements as simple as possible, iterate, and keep the client in the loop. If it takes too long to get out a bunch of features, you may find that those features don't meet the customer's requirements by the time they are available. Bring your customer in on the planning cycle: at your daily standups, allow the customer to re-prioritise the tasks on your board, even to bring in new tasks, with the proviso that bringing in a new task means that one already on the board must be removed. We're not super-human, and we're subject to the same constraints of time, cost and quality.
TDD can really assist here: if you're writing small tests, over small pieces of code, your test structure will help you to decide to decouple (eg use interfaces & mock them), and the flow of TDD lends itself towards a high-quality end-goal where we can control time vs cost by deciding on the simplicity of the desired result.
- Think about software you use: which would you prefer?
- complex software with bugs
- simple software with little or no bugs
- complex, quality software, delivered on long timelines
- Consider how decoupling & modularising your code can help with delivering simple quality
- Consider popular software with feature bloat:
- is it easy to use?
- how often are there bugs or vulnerabilities?
- are we making software like this?