Türkçeye çevrilmiş halini buradan okuyabilirsiniz.
Today we are going to talk about a subject that I have been concentrating on for a long time and that I believe you also discuss with yourself from time to time. As the title suggests, instead of discussing the questions which we have read a lot such as “What is unit testing?”, “Why is unit testing important?”, “How to increase code coverage?” or “What kind of test approaches are there?”, we will be looking for the answers to “Why” questions by going deeper into the subject.
Let’s take a look at what these questions are before we go into detail.
- Why don’t we write tests?
- Why can’t we write tests?
- Why do we give up while writing tests?
- Why do we struggle to write tests?
- Why are we not happy with tests?
We can further increase the number of questions here. However, even if we produce more questions, we will realize that all the questions are related to each other and emphasize the same point.
Are the facts as we expect?
Although our daily work changes from time to time depending on the team and product we are assigned, at the end of the day, we continue the development on the production and solve product-related problems.
As software developers, we prefer a smooth sailing workday. Carry out the development, ship, and refactor where needed, deploying these developments to the production environment, and refactoring the system if required. However, things may not go well :)
Our system on the production may encounter failures unexpectedly and our customers may expose these incidents. In fact, when the volume of these incidents increases and users become more vocal about their experiences, emotional and financial repercussions may start taking their tolls on the responsible team. At this point, perhaps most of our day will be spent first finding and understanding the cause of errors and then solving them.
Fortunately, in this instance, we managed to detect the problem and solve the issue by deploying changes to the production. Just as we were taking a sigh of relief, the number of errors started to rise again. While we were wondering whether it was because of the change we made or if we were encountering a new error, we all realized that we are now lost in that dead-end labyrinth. Things are starting to get worse, right?
At this point, I seem to hear you say, “Well, if we had written tests, these wouldn’t have happened. It’s important to write tests. We already know that…” While you’re right, the important thing to note here is that although we wrote tests, we could still be going through this process (eg: wrong test design, abstraction errors, etc.). Since this is not our current focus, we will be discussing it again in a different article.
Deadline is coming!
If we start with a more familiar problem, deadline, the date specified for the completion of the development, it is like a hand grenade with the pin pulled between the product team and the software team, which will partially explain the importance of the situation.
When making any development about the product, we promise a date for the completion of the work and we try to fulfill this promise. However, in some cases, we may not make it to the specified time. There are countless reasons why things can’t keep up. The vital point here is that we forget about the concept of testing by focusing on the point “We need to get the job done”.
In the end-to-end completion of a job (eg: a new development, debugging, code refactoring, etc.), we need to internalize that testing is a part of this process, calculating timeframes by including the testing period and not excluding it for the sake of meeting deadlines
Nobody writes tests anyway!
This title, albeit rare (I hope so), can be interpreted as one of the problems we encounter. Here, the subject goes out of a technical point and evolves to a more intellectual and human point.
I would like to point out that it is not correct for me to question “No one else is writing a test anyway”. Because I think this is the same as “Nobody else is using interface anyway”. Just because someone else isn’t doing it doesn’t prevent you from doing it, or because you’re not doing it, it doesn’t prevent someone else from doing it.
The most important point we should mention under this title is the formation of a test culture within the team/company and the distribution of that culture inside. When such an environment is provided, contrary to what we have mentioned above, structures that will direct and support each other to test writing will be formed.
Code is overly complex and untouchable!
We come to the most important topic! I believe that what we will talk about under this title is the point that touches our “Why” questions the most, and information that we should always think about and never forget.
We have all come across projects that are difficult to manage, closed to development, and more often than not impossible to alter. Let alone testing, writing code, even developing, it is a dream. The thing that alienates us from testing or prevents us from writing tests even if we wanted to is to maintain the sustainability of such projects.
So why do we encounter such code structures or projects written this way? I’m sure there are various answers that we can all give to this question. But let’s change our perspective a little more and get to the core of the matter and ask Jack Revees master “What is Software Design?” Let’s draw attention to one part of the article.
“Coding is design, testing and debugging are part of design.” Jack W. Revees
“Coding is a design, testing and debugging is part of that design.” what does he mean? You know, there was a task ahead of us and we weren’t opening the project, doing CRUD on the database with Repositories, and then developing business through Managers? You might be asking where did this design concept come from?
Developing software is not just solving problems and coding to solve that problem. Problem-solving is only part of our job. The main problem is to consider how to solve this problem completely, to develop this solution. At this point, the answer to the question “How” will be “Design”. Designing is the job of planning. In other words, it is a method of problem-solving by using what you have in the right way, by planning correctly.
When we look at the concept of design in terms of software, our source code is our actual design and we will need a good design for a flexible, maintainable code that is open to development. To achieve this design, we need to review concepts such as abstraction, coupling, and cohesion.
Now we come to the best part. This design (i.e., our code) we are talking about cannot exist without testing and debugging. In other words, the design would not be complete without this duo. At this point, we can see that a bridge has been established between the code and the test.
Lastly, we talked about debugging. Of course, there will be errors in the codes we develop. The important point is to find and fix these errors quickly. Refactoring, therefore, acts as a bridge between coding and testing. It should not be forgotten that not only the codes we write but also the tests should be refactored when necessary and that the concept of refactoring touches both the code and the test.
Code and testing are together and cannot be separated! We must not forget that all problems started because of this. That is, we need to know that in order to eliminate code complexity and non-improvable code structures, we need a good and accurate design, and this design cannot be without testing.
So, how will we be happy?
No matter how much we know the importance of the concept of testing, we talked in detail about why we couldn’t write a test, what difficulties we encountered while writing it, and the things that turned us off. We can offer many ways to get us back to write tests, but arguably the most important one says Misko Hevery.
“The secret of testing is writing testable code.” Misko Hevery
If we summarize all these conversations, we need to keep the job tight from the beginning and develop testable structures so that we can write tests and be happy while writing tests. For this, the most important need is to have a good design, the design is our real source code, this design cannot be a whole without testing and debugging, the concept of refactoring will be in our lives not only once, but as long as the software development continues, and between the code and the test, there are both sides. We must not forget that it is in a touching position.
You can find a more detailed presentation I made at Farmazon on the subject here.
I would be very happy if you would indicate the points you find missing or wrong, or your experiences on the subject, in the comments section. Hope it was helpful :)