Yes, TDD slows you down

Reading Time: 3 minutes

I recently had the opportunity to reflect about testing practices. In particular, the different layers of testing: unit testing, integration testing, acceptance testing.

The test pyramid suggests that each level has an associated cost. The cost of your tests translates then into the pace at which you can make changes to your system.

Quite frequently, early-stage organizations tend to focus less on unit tests and more on acceptance testing. This might be the case at the early days of a new product. There’s a high fluctuation in requirements and you might feel that unit tests will slow you down when it comes to making radical changes to the implementation.

By not investing in unit testing, though, you are giving up on the opportunity to do TDD. Yes, you will still be able to write acceptance tests before writing any code. But having so coarse-grained tests will not constrain you in the way you structure your code, your components and how they communicate with each other.

Your acceptance tests will guarantee that your system meets the requirements, now.

TDD is not just about testing

TDD is a software development methodology that strictly dictates the order you do things in. And it’s not dictating that order for the sake of it. Writing tests first and letting that drive the functional code you write after is going to impact the way you design and architect the system.

This is going to have numerous benefits: your code will be modular, loosely coupled and with high cohesion, as well as being clearly documented and easy to extend.

Unit testing is one aspect of TDD. It helps you at a fundamental level of your system. The implementation level, that is ultimately going to decide how agile you will be in the future at making changes.

If you develop a system without a TDD approach you won’t necessarily have a system without tests. But you will most likely have a system that is hard to extend and hard to understand.

This is the reason why I’m more and more convinced that you can’t really be that liberal about your testing layers. If you’re building new functionality and decide it is going to solely be tested through acceptance testing, you’re most likely going to miss out on the added benefits of TDD at your service layer.

When you mix TDD with non-TDD you’re not just compromising on the tests at certain layers of your test stack. You’re compromising on the architecture of your system.

Do you really need to go faster?

Of course you do! Who thinks that going slower is better?

Too bad the question should usually be rephrased to:

Do you really need to go faster now, and go slower later?

I think this way of phrasing it helps making the right decision. As I said at the beginning of this post, going faster now might actually be the right decision. TDD might be what slows you down now, and you might not be able to afford slowing down now. But my advice is not to stop asking that question as you keep making compromises.

When you defer the adoption of TDD you’re not just skipping on unit tests. You’re developing code unconstrained, increasing the opportunities of high coupling and low cohesion. This inevitably makes you slower as you go. And it will keep making you slower until you will inevitably incur in such a high cost of change that implementing even the most trivial feature will seem like an insurmountable challenge. Not to mention this will impact your team morale, as well as the confidence that the rest of the organization will have for your team.

Be conscious

As I said at the beginning of this post, giving up on unit tests might actually be the right thing to do for you, now. What’s important to realize, though, is that giving up on TDD at a certain layer doesn’t just mean giving up on tests. It means giving up on a framework that guides you through specific principles. If you are not going to do TDD, do you have an alternative set of principles to stick to? Do you have an alternative way that helps you structure your system effectively, to help you scale? Are you going to have the confidence to make changes? Are new team members going to be able to easily on-board themselves and make changes without requiring additional contextual knowledge?

If you enjoyed this post, chances are you’ll enjoy what I post on Twitter. Thank you for getting to the end of this article.

Business outcome language: an introduction for software engineers

Reading Time: 4 minutes

Using a business outcome language helps keeping the problem definition focused on the value that you should deliver to your customers. Let’s explore together how to make sure our language is not polluted by technical details.

As a technological leader at your company, you are the citizen of two worlds: the business world and the implementation world. Each world speaks its own language, so it’s vital that they communicate clearly and unambiguously.

Your first days in the implementation world

Software engineers typically start their career in the implementation world, with few contact opportunities with the business world.

As a software engineer what excites you is the challenge of solving a problem. You crave more problems and you feel more satisfied as you solve them. Your brain is triggered by the problem definition and it starts spitting out all of the possible ways you can achieve the expected result.

The problem definition at this stage is probably in an implementation-oriented language with little indication as to what business outcome the company is looking for. It’s likely that you don’t care about that though because you only care about the coding challenge.

Your language evolves around the how

In the implementation world you develop a language that is specific to the solution to the problems and the tools you have to solve them.

You communicate with your peers by focusing on how to achieve the solution. The discussions often develop around the technical details of the existing software.
The foreigners living outside of the implementation world look at you with surprise and curiosity: your words don’t really make much sense from the outside.

The first contact with the foreigners

There comes a point in your career when you have to interact with the people from the business world and work together.

Depending on the approach your company has for building product, this interaction can often be an opportunity for the two worlds to collaborate and find a sensible outcome to pursue.
The most effective way of doing this is by a common language: the business outcome language.

Certainly, this is often challenging for the implementation people because their native language is not well understood outside their world. Using the implementation language comes naturally for them. Explaining how something can or cannot be achieved through implementation details feels incredibly easy.

The trouble with the implementation language

Let’s see a few examples of why using the implementation language for every interaction can be counter-productive.

We can’t do that!

dilbert, technical debt, comic strip, business outcome language

“What you’re asking is impossible to do by that date. The amount of technical debt we have accumulated means that we need 3 months to refactor the service classes to be capable of supporting this new functionality. We also have to update to the latest version of the database in order to support that change…”

– An implementation world native

While those might all be valid reasons as to why the specific change in question is hard to achieve, they are contributing to setting the wrong tone for the conversation.

Raising very specific technical concerns is going to shift the conversation to an explicit technical negotiation.
The people from the business world will inevitably, and often subconsciously, try to petition the implementation people for a middle-ground solution. This achieves a similar outcome but overcomes some of the technical limitations that have been raised.

When the negotiation is successful it might feel like a WIN-WIN situation but in reality, it isn’t.

First of all, the business people might have just agreed to build functionality that is polluted by workarounds and has evolved around technical constraints instead of around the customer.
Similarly, the implementation people might have just accepted to build more technical debt into their world.

I speak your language too, I’ll tell you exactly what you have to do!

dilbert, feature creep, comic strip, business outcome language

“We need to add a new button to the page so that the users can export the data as PDF.”

– A business world native speaking the implementation language

The above example is outlining exactly which technical solution should be used without even specifying what the problem to be solved is.
Imagine the following problem definition, instead: the users want to share the insights data with their colleagues with minimum effort.

While an “Export as PDF” button might try and address the issue, it only partially solves for it. Exporting as PDF, saving it to your disk, finding it again to attach it into an e-mail doesn’t necessarily mean minimum effort.

Having clarified that the users want to share insights with minimum effort helps the engineers come up with a much more effective solution. One possibility is providing the users with a “Share” call to action that sends the insights to the desired recipients, without having to export anything.

Clarifying what the problem is instead of mandating a specific solution will let the engineers and the designers explore the best approach within the current constraints.

A technical language anchors down the thinking

The implementation language is a powerful way of describing solutions. It is very detailed and it helps engineers be unambiguous as to what has to be done.
Its power, though, makes it dangerous if used in the wrong context.

Bringing too many implementation details into the discussions anchors the thinking to the status quo, potentially preventing from identifying the right value for the users of your product. It is important to defer the implementation evaluation to the very end in order to let the thinking evolve and articulate in the space of the business outcome that the company wants to achieve.

Help free the language from the technical constraints

As a technological leader, you should be fluent in both languages. Take advantage of this and make sure the conversation stays away from implementation details by ensuring that all the people involved speak a business outcome language.

Understand the technical limitations and concerns raised by your compatriots and translate them into the appropriate language, weighing what is really worth including in the conversation.

Make sure not to preclude innovation and avoid constraining the thinking to the status-quo of the technical limitations. This exercise will help you evaluate many more implementation opportunities than before.

Cover photo by Headway on Unsplash