TDD Still Compared to TLD - Expert Opinion
Specialists from several European universities - David Fucchi, Giuseppe Scaniello, Simone Romane, Martin Shepperd, Boise Sigveni, Fernando Uyaguari, Burak Turan, Natalia Juristo and Marco Oyivo - conducted another study on the effectiveness of software testing. They reviewed the Test Driven Development (TDD) and Test Last Development (TLD) methodologies.
Researchers compared them by two indicators - the total speed of product development and the quality of the source code. The first methodology (development through testing - TDD) again fell short of expectations: the previously popular post-development testing (TLD) test scheme was no less effective. So they did not find significant differences in the above indicators.
In this case, what explains the flash of interest in TDD when it first appeared? This methodology arose in the 2000s, so now the element of novelty can be safely discounted. However, it remains a matter of controversy.
The author of TDD Kent Beck identifies five main steps when using the methodology in practice:
• Write a new test case;
• Make sure that starting a new test will lead to a failure;
• Write a new one or modify the code so that the test is successful;
• Restart all other tests and confirm their successful completion;
• Make code refactoring, eliminating redundancy.
TDD and TLD have advantages and disadvantages. Moreover, the advantage of one methodology is often a disadvantage for another.
• Test development speed
In the case of TDD, engineers have to spend 16% more time than with TLD. This is due to the additional cost of switching developers between writing tests and core code.
• Entry threshold
TDD has a higher entry threshold, as it is not only a testing methodology, it is a different approach to software development. Therefore, the developer needs time to understand it and start using it in practice.
• Performance and maintenance
Thanks to TDD, the cost of maintaining a software product is reduced. Typically, using this methodology, the number of test cases is approximately 50% greater than with TLDs. This provides greater coverage and implies increased product reliability. Therefore, accompanying such software is easier. Due to its well-designed architecture, the performance of a system designed using TDD is usually higher.
• Code Size The
use of TLD can significantly reduce code size compared to TDD. In addition, TLD code often has a simpler structure.
With TDD, developers can usually be sure that changes will not cause unwanted effects. All necessary tests are run after each change. Thanks to development through testing, debugging software as a whole becomes more transparent and informed.
In any case, each project is individual, but general patterns exist - just as there are various trade-offs.
Both that, and another - extremes. It all depends on the situation. In general, tests are a very painful and holistic topic. The question is not yet closed about what tests should be written at all or not: unit, functional, or integration (or all).Here is an example of a possible dialogue between a manager and an architect.
A: - Do we want 100% coverage?It is widely believed that a medium-quality design will provide coverage of key pieces of code by 80-85%, and each subsequent 5% will take more and more resources (labor and time).
M: - Yes, of course.
A: - Excellent, only this will delay the development by half and complicate the maintenance of the test code by an order of magnitude.
Moreover, the author of TDD Kent Beck once expressed the idea that unnecessary tests can be deleted. He calls such tests delta coverage - additional coverage provided by a specific set of tests. If this additional coverage is 0, then the test can be safely removed.
Kent Beck is a software developer, creator of software development methodologies such as extreme programming (XP) and development through testing (TDD). Beck was one of the 17 professionals to sign up for Agile Manifesto in 2001.
Extra tests lead to additional maintenance costs. That is why, tests obtained in the early stages are usually too naive and can be removed. This is especially true for the TDD methodology.
Martin Fowler gave two simple rules of thumb that define the lower and upper limits of coverage: if you are not sure about your changes, and many of them lead to failures, but do not break the tests, then there are too few tests. If, with each change, too many tests break, then perhaps there are too many tests.
Martin Fowler is the author of several books and articles on software architecture, object-oriented analysis and development, the UML language, refactoring, extreme programming, and domain-specific programming languages.
When to use TDD?
The graph shows the speed of development of two projects. Blue sacrificed design and tests. Their goal is to realize the maximum amount of functionality as soon as possible. Reds, by contrast, pay great attention to the design of the system and its testing.
Obviously, the blue ones leave a lot of “technical debts” in the code, which dooms themselves to difficulties in expanding the system in the future and problems with its support.
But due to what are the Reds able to keep the system flexible and move at a stable speed? One reason is the use of TDD, writes Alexander Byndyu, an expert on Agile and Lean.
He cites several advantages of TDD in the Reds project:
1. The simplest thing is that in such a project there are more tests compared to the usual approach. On the one hand, the number of tests alone does not guarantee a higher quality project and no errors. On the other hand, it all depends on how well you can write these tests. Many good tests will save you a lot of time.
2. The code is getting better. This is due to the fact that unit testing implies a weak connection of various modules of the system, otherwise it will be very difficult to write these unit tests. Therefore, you have to apply, for example, the principles of designing SOLID classes:
The Single Responsibility PrincipleUltimately, this will give the entire system greater mobility and flexibility.
The Open Closed Principle
The Liskov Substitution Principle
The Interface Segregation Principle
The Dependency Inversion Principle
3. We can rebuild our project as much as we like, adapt it to new requirements and not be afraid that after the next refactoring we will lose some already working functionality. Why can we afford it? Because after refactoring, we’ll run all the tests and they will show us (with a green bar) that all business functions still work.
Therefore, according to Byndyu, TDD forces you to write better code that is more convenient to test. This means that we leave less technical debt in the code.
When does TDD begin to overtake? Then, when the blue and red lines intersect. At this time, the team of blue in full begins to pay for debts. Hence the conclusion about the limits of applicability of TDD:
You can write code without TDD if you are sure that it will not get to the dashed line. For example, you write a small project to automate the internal work, or create a business card site.You need to understand that TDD is not a guarantee of the quality of your code, but with it it is easier to keep the system in good shape, he concludes.
Not one but
David Hansson warns that a passion for testing and trying to test everything in complete isolation (when we test only the current class, without its dependencies or auxiliary low-level classes) leads to a heap of unnecessary layers of abstraction and an overcomplicated design.
David Heinemeyer Hansson is a Danish programmer, author of the Ruby on Rails web framework, founder of the Instiki wiki and racing driver, winner of the LMGTE Am (2014) class and silver medalist of the LMP2 (2013) World Endurance Championships, winner of the 24 hours of Le Mans 2014 years in the class LMGTE Am.
However, Martin Fowler has an important caveat in this regard:
When the system begins to grow, the problem is not in the number of levels of abstraction, but in the number of levels of isolation. That is, the very fact that class A calls the method of class B, which refers to class B, does not present a problem until an isolation level appears in the form of an interface between each of these classes.On the other hand, some users of Habr are looking at this topic. User
Opinion Volch :
You need to understand that the use of methodologies such as TDD suggests that developers write autotests, not testers. This is a programming and coding methodology, not a finished product development, which involves a lot of people from PMs and technical writers to admins and tech support. Developers often refer to the implementation of TDD-like as taking over the duties of testers.Opinion user Tagakov :
TDD is really not what testers should do. Their task is to write functional tests and, if they have enough qualifications, integration tests. TDD is not TDD, but developers have been testing for centuries, running their code and checking how it works, unit testing is more a formalization of this process.Opinion user Kunis :
If the test is written before and provided to the programmer as input, it becomes a “technical requirement”. Of course, the one who writes the test must write and program all the required mokeys in advance. Haha, I would not like to be the programmer whose job it is to program tests for others.
Well, can a programmer write tests for his code in advance? In my experience, no and no. Programmers (and I and the vast majority with whom I discussed this) just think in the opposite direction. Yes, at first people tried to honestly follow the methodology. But after some time, they started to write code first, and then add tests to it. And after some time, the tests lost their versatility and meticulousness. And then “shtob was” was written at all, since they ask.
But is it even necessary?
One of the apologists for development through testing, Alexander Lyulin, also expressed his opinion :
I do not use TDD in its classical sense. In general, it is unlikely that any of the professionals considers encyclopedic articles as a guide to action. We “suffered” our approach as part of the implementation of a successful project, so we have real experience, and not “stupid use of other people's ideas”.
Rather, we use a synthesis of TDD and our own ideas about how to develop software. Even if these “external ideas” come from very smart people, they should be critically evaluated and adapted to a real company, an existing team, and a development and quality assurance strategy.
Oleg Balbekov, CEO of Vexor:
In our opinion, it is rather difficult and not necessary to strictly divide these approaches. It so happened that in our team we usually combine the use of both approaches in one project, and even sometimes when developing one block of code.
Well, for example, when we write part of a project to work with services through the API, we write tests first and then code (TDD). However, after implementation it often happens that tests written well in advance are not enough and you have to add them, achieving 100% coverage (TLD).
Sometimes even for very simple controllers (a regular resource with basic CRUDs), simple tests are written first, and then code (TDD). This gives us confidence that nothing is forgotten in the initial implementation. Later, during the development of the project, in most cases, tests are written after writing code (TLD).
Often there are tasks of implementing the algorithm on known input / output data, here the TDD approach is also mainly used. If you have ready input and output data, then it is very easy to write a simple test on them, and only then implement this algorithm, being sure of the result.
Most often, the TLD approach is applied during refactoring. First, we cover the existing implementation with tests and only then rewrite it.
If we talk about the relationship between the use of TDD and TLD in projects, then TLD usually wins. Developers who simply write tests are always more than those who are able to "think with tests" and write tests in advance.