Navigating the Complexities of Software Development: My Personal Journey with Test-Driven and Behavior-Driven Development

Zakaria Rahioui
Norauto International
5 min readJan 23, 2023

Writing code is never easy, and only relying on intuition can make it even harder. While following your instincts can be beneficial when exploring new technology or prototyping ideas, it is not a sustainable approach for wider projects. To create clean, maintainable, and bug-free software, it is essential to have more than just intuition guiding you.

There is no single solution for creating good software. Software complexity is the reflection of the organization, the requirements, the architecture, the team, and even factors like your mood and the quality of coffee. Given this, it is unlikely that two applications with the same capabilities will have the same code. To navigate this complexity, developers dispose of a toolbox filled with feedback, experiences, and guidelines from those who have gone before us, to help us go through the minefield avoiding explosions more or less easily. So please don’t code in the dark and grab whatever you need from that toolbox.

In this article, I am going to highlight two tools that I have been using for a few years now. I will share my personal reflections on them and provide an overview of the benefits they bring. However, it’s important to note that this is not a tutorial or a step-by-step guide, but rather a general discussion of the topic. As the subject is vast, I won’t be going into too much detail.

toolbox

Test-Driven Development: Lessons Learned on the Way

At the beginning of my career as a developer, I discovered Test-Driven Development (TDD) and I have become immediately drawn to its approach. At the time, it was tough for me to structure my ideas while writing code. TDD have helped me, and still, organize my thoughts and approach to coding. However, as a beginner, I made many mistakes along the way. I found myself testing everything, the wheat and the Chaff, and writing tests became more of a goal than a tool.

But, looking back, I don’t regret these early mistakes because they have helped me to better understand and appreciate the power of TDD. Over time, my practice has improved, and I found that tackling problems has become easier. I approached the process incrementally, testing one piece at a time, and found that this made the development process smoother and less complex. My code has also become less coupled. I avoided mocking objects if I didn’t need to. This has made it easier to change code without altering the behavior.

As a result of using TDD, I have become more confident in my ability to change or refactor code and adding new functionality has become easier. I no longer felt stressed about pushing code, and pull requests were more about design, readability, and structure rather than finding bugs. TDD has led me to create simpler designs, which are more adaptable to future changes, and has helped me identify and address design issues early on, such as long setup phases, duplication, fragile tests, and slow test execution.

I should also mention that code coverage is a result of the practice, not a goal in itself. Pursuing a 100% code coverage can be counter-productive, as it can lead to writing unnecessary tests or testing insignificant parts of the code.

The most important thing about code coverage is the variation of that metric. A decrease in code coverage may be an indication of deeper problems.

From Skeptic to Convert: My Discovery of the Benefits of Behavior-Driven Development

As I previously mentioned, I was a strong believer in the power of Test-Driven Development (TDD) and was convinced that it was the best approach for software development. However, in 2015, things went wrong while I was working on a new project. We had been trying different approaches, but we were still struggling to meet our deadlines. It felt like we were stuck in the mud, not making any progress.

I was doing my part by writing code and testing it, but I wasn’t aware that I was becoming too focused on unit tests and not addressing the real problems. My manager, who had a decent technical background, was also looking for answers and came across Behavior-Driven Development (BDD). At first, I initially believed that he saw BDD as a fix-all solution for our issues. We had many discussions about how BDD was supposed to replace TDD and unit tests, and how tools like SpecFlow could generate steps and methods in seconds. But for some reason, I just couldn’t get on board with it.

In hindsight, I realize that some of what my manager was saying made sense. BDD, when correctly done, can help to focus on the behavior and expected outcomes of the software, rather than just testing individual units. Additionally, by writing scenarios in Gherkin and using a framework like Cucumber, it can be a powerful tool for collaboration and communication between developers, QA, and stakeholders. So, I decided to give it a try and started digging deeper into it.

BDD and TDD: A Match Made in Heaven

I struggled with choosing between BDD and TDD for a while, until a consultant wrote BDD TDD with a space between them, and it suddenly made sense to me. It is not a competition between the two, but rather a complementary relationship, where they work well together. I had not seen it that way before.

That’s all well and good, but how are you going to do it? Let’s say we want to add a new feature, so a customer can search for tires on the Norauto.fr website.
With BDD, the team would first have a conversation with the stakeholders to understand the requirements for the search feature. They might come up with acceptance criteria such as:
- Users should be able to search for tires
- If no result, a message should be displayed
- Users can use “Summer” as a filter option.

With TDD, the developer would then start implementing the feature by writing unit tests for each scenario.
The developer would then write the minimum amount of code required to make the tests pass, and then repeat the process for each scenario.

Conclusion

By using BDD and TDD together, the team can ensure that the requirements are understood and that the implementation meets those requirements.

BDD ensures that the behavior of the application is understood from the end user’s standpoint, and TDD ensures that the implementation is correct and meets those expectations.

As the development progresses and the product evolves, the team may have to update the acceptance criteria, or add new scenarios and tests, so it’s an iterative process where BDD and TDD are working together.

Reviewed by : Jamal BOUNASSEH, Baptiste Lombard, Solène Méhaut 🙏🏽

--

--