Discipline or tests. Choose one?
- Transfer
- Recovery mode
Luxoft Training has prepared for you a translation of the article by the famous Canadian software development consultant Joe Reinsberger “Discipline or Tests. One's Pick? » .
Joe Rainsberger is the author of many works on information technology. For his contribution to the development of flexible methodologies, he was awarded the highest award from the Agile community - the Gordon Pask Award in 2005 (in the first year of the creation of the award). He is the founder of XPDay (North America). Joe Reinsberger's book, JUnit Receipes: Practical Methods for Programmer Testing, has become world famous. Joe has been practicing agile methodologies since 2000, and during this time his articles on Agile development have been published in leading development magazines, including IBM DeveloperWorks and IEEE Software. In IEEE Software Magazine, Joe is the editor of the “Not Just Coding” column.
Recently, one of the clients asked me this question, and I'm not sure that I gave a reasonably good answer. I will try to do it here.
I see advantages in both cases, so, unfortunately, I can not briefly answer this question. On the one hand, a disciplined programmer will make reasonable decisions, even if he does not do the same thing that I would do. If I trusted the general discipline of the programmer, I would feel comfortable trusting him (her) to do quality work, by which I mean a constant stream of valuable working code. On the other hand, if I trust the discipline of a particular programmer or programmers, they will produce artifacts that I cannot easily consume, and when they disappear, my constant stream of valuable working code will also disappear. It becomes a problem of the number of trucks (Truck number, Bus factor).
Since I use a good set of tests to reduce the unpredictability of the marginal cost of functions (When we say that we care about design “for economic reasons”, I think that we mean exactly that. Note that “marginal cost” simply means “The cost of the next function”.) , Then it may make sense to require the programmers who supply these functions to me so that they also provide tests to maintain the ability to support the code base in a cost-effective way and without them.
So what would I prefer? I am going to find out in the process of writing this article. It really depends on a lot. Let me examine the issue, and perhaps, with enough associated factors, I can make a choice.
Suppose the programmers we are talking about have high discipline, but they do not write tests. What do I need from them (assuming that I can’t require tests) that would allow me to comfortably adopt their code base? I have some ideas.
It becomes very similar to following the Four Elements of simple design . And that leads me to another question.
It is funny that this question never arose. If the system is well designed in accordance with the Four Elements, then it seems to me relatively easy to add tests after development. This follows from the basic concept that the Four Elements encourage us to write testable code, and according to the definition of “testability”, I should not have any particular problems when testing the testable code.
I would rather not spend extra time adding these tests, but I would endure. This becomes a decision based on commercial considerations: if I pay $ 100,000 to add tests to your code, then you would be better off saving me more than those $ 100,000, compared to the best option involving writing tests . As long as you do it, what right do I have to complain?
Well ... I see one potential problem. The cost of adopting such a simple code base includes not only money, but also time, and if I can recover the money , then time will never . I need to consider the cost of delay to add tests to this hypothetical code base. Fortunately, I can amortize these costs over the life of projects that support this code base, making it probably the cheapest legacy code in history .
I think I would have survived this too.
So, suppose I have a simple code that saved me more money during the creation process than I would spend on adding tests after it was created. Am I missing something else important without getting tests along with the code?
Of course, I will need a one-page document describing the general design of the system - the five most important things - as well as which functions, according to programmers, have already been created and which will be created next.
Presumably as a client of this hypothetical product, I will understand quite well the product, subject area and functions that, in my opinion, have already been created. (It would not hurt to compare my perception of “what has already been done” with their perception.)
This leads me to the first version of the final list of things that I will need to trust the base of code written by “disciplined programmers” that do not write tests.
I think, having all these things, I can agree to adopt the code base from a group of programmers who do not write tests.
But what about the opposite situation? Suppose I have a strong test suite, but my programmers are not very disciplined. What risks will arise and how can I reduce or compensate them?
What do I expect from a “strong test suite”? I would like to have mainly microtests written in the style of joint and contract tests (I have a very voluminous opinion on the topic “Integrated tests are nonsense”, but I have not yet found the strength to write it down. Now I am doing it very slowly. When - maybe I’ll write this book, but for now, here is my last speech on this topic) , with a pinch of functional tests written in the style of the most caring behavior-driven development practitioners. These functional tests will help me understand the functions, and microtests will give me the confidence I need to make changes to the code.
This is the problem:the cost of understanding and maintaining these tests most likely corresponds to the cost of understanding and maintaining the final code. This makes sense, since most likely the same people wrote both. (I understand that I can not reasonably assume this, but, nevertheless, I will.)
Since the discussed programmers are not supposed to be as disciplined as I would like, we can expect that there will be problems in the final code. In general, where I find problems in the final code, I can expect to find a close connection between the tests and the implementation details of this final code. I can expect a lot of indirection without abstraction. In short, I can expect well-tested, well-covered legacy code. Theoretically, I can save this legacy code, but I will have to deal with the usual problems of inconsistency in the cost of saving the code.
I can probably find the best total cost of saving the code with the same inconsistency as with legacy code without tests. This seems intuitively obvious, given that in some cases the tests will be so closely related to the implementation details that I will have to drop the tests and start over (I assumed that the programmers did not write the final code that depends on the tests. I understand that this assumption is risky but I find the alternative too terrible to think about it). As the tests reveal the implementation during testing, they hide the pronounced details of the main aspects of the behavior, and in the end I will do archeology to discover the main aspects of the behavior myself, with or without tests.
I do not want to portray the situation completely terrible. Of course, having tests increases the likelihood that I will be able to change part (possibly large) of the code safely, although not confidently, at least in the beginning. Designing will probably be unpleasant for me, but changing the design will probably be simpler than with a typical base of legacy code. On the other hand, the need to write tests for legacy code gives me such an opportunity to understand the purpose of the code that a simple reading of overly detailed tests can never give.I have to prepare myself for the possibility that the need to write tests from scratch for legacy code is part of the process, not its defect.
Wow. I did not expect this. (Seriously)
It seems that I would prefer to have disciplined programmers who do not create tests to less disciplined programmers providing a strong test suite. No, this is not a trick. (“A simple project passes all the tests, but if there are no tests, then the project is obviously simple ...” No.) Yes, I would also like to have tests, but if someone can achieve good results without tests, then I have no right impose their methods on them. I have to admit that this surprises me, because in the past I probably wrote that I would prefer tests. Then it seemed like a good idea. I cannot explain the shift in my thinking.
Despite this, please write tests, no matter how disciplined you think you are. I believe that writing tests and accompanying refactoring helped me a lot to develop discipline, and I still insist that I will write tests. So if I hired you, I would demand the same from you.
My friend Michael Bolton told me that this article reminded him of the problem of implicit knowledge. In particular, tests (actually “checks”) can only display someone’s ideas about what the system should do, and thus, they will miss out on some of the information that, according to Murphy’s law, will become important for us Wrong moment. And at this moment we definitely want that we had access to the programmer, and not just to checks / tests.
Indeed, the checks seem to have encoded, at best, a relatively recent snapshot of the fact that, probably, a randomly selected version of us thought about the functioning of the product, being limited by our ability to formulate these thoughts (given our skills and energy at that moment). Expressed in this way, it seems obvious that I would rather choose disciplined people, rather than the checks themselves!
July 7 and 8, Joe Reinsberger conducts an online workshop on the theme “Value-based approach in software development”

Discipline or tests. Choose one?
Which would you prefer: to have a disciplined programmer or a strong test suite?
Recently, one of the clients asked me this question, and I'm not sure that I gave a reasonably good answer. I will try to do it here.
I see advantages in both cases, so, unfortunately, I can not briefly answer this question. On the one hand, a disciplined programmer will make reasonable decisions, even if he does not do the same thing that I would do. If I trusted the general discipline of the programmer, I would feel comfortable trusting him (her) to do quality work, by which I mean a constant stream of valuable working code. On the other hand, if I trust the discipline of a particular programmer or programmers, they will produce artifacts that I cannot easily consume, and when they disappear, my constant stream of valuable working code will also disappear. It becomes a problem of the number of trucks (Truck number, Bus factor).
Since I use a good set of tests to reduce the unpredictability of the marginal cost of functions (When we say that we care about design “for economic reasons”, I think that we mean exactly that. Note that “marginal cost” simply means “The cost of the next function”.) , Then it may make sense to require the programmers who supply these functions to me so that they also provide tests to maintain the ability to support the code base in a cost-effective way and without them.
So what would I prefer? I am going to find out in the process of writing this article. It really depends on a lot. Let me examine the issue, and perhaps, with enough associated factors, I can make a choice.
What does “disciplined” mean?
Suppose the programmers we are talking about have high discipline, but they do not write tests. What do I need from them (assuming that I can’t require tests) that would allow me to comfortably adopt their code base? I have some ideas.
- I need to know where in the code I look for what I need.
- After I find what I need, I need to know either (1) that I have found everything that I need, or (2) that I can understand where I should look further.
- I must be sure that if I change anything, it will not entail sudden changes in other places.
It becomes very similar to following the Four Elements of simple design . And that leads me to another question.
If programmers write simple code (such as in Four Elements) without tests, what else do I need that would allow me to comfortably adopt their work?
It is funny that this question never arose. If the system is well designed in accordance with the Four Elements, then it seems to me relatively easy to add tests after development. This follows from the basic concept that the Four Elements encourage us to write testable code, and according to the definition of “testability”, I should not have any particular problems when testing the testable code.
I would rather not spend extra time adding these tests, but I would endure. This becomes a decision based on commercial considerations: if I pay $ 100,000 to add tests to your code, then you would be better off saving me more than those $ 100,000, compared to the best option involving writing tests . As long as you do it, what right do I have to complain?
I don’t take into account that I doubt very much that I could ever hire programmers who can write simple code without tests, unless by chance. I remain open to this opportunity.
Time is not really equal to money
Well ... I see one potential problem. The cost of adopting such a simple code base includes not only money, but also time, and if I can recover the money , then time will never . I need to consider the cost of delay to add tests to this hypothetical code base. Fortunately, I can amortize these costs over the life of projects that support this code base, making it probably the cheapest legacy code in history .
I think I would have survived this too.
So, suppose I have a simple code that saved me more money during the creation process than I would spend on adding tests after it was created. Am I missing something else important without getting tests along with the code?
About the code base
Of course, I will need a one-page document describing the general design of the system - the five most important things - as well as which functions, according to programmers, have already been created and which will be created next.
Presumably as a client of this hypothetical product, I will understand quite well the product, subject area and functions that, in my opinion, have already been created. (It would not hurt to compare my perception of “what has already been done” with their perception.)
This leads me to the first version of the final list of things that I will need to trust the base of code written by “disciplined programmers” that do not write tests.
- A short document describing the overall design of the system, the functions that, according to programmers, have already been created, and the functions that programmers are going to create as follows.
- A code base that conclusively demonstrates that programmers have made this code simple according to the Four Elements of Simple Design.
- Constant speed of creating functions, which covers the time (relatively small) that I need to add tests, since I myself support the code base.
I think, having all these things, I can agree to adopt the code base from a group of programmers who do not write tests.
Of course, this does not mean that I advise you to put all your tests to the fire in order to see what happens.
But what about the opposite situation? Suppose I have a strong test suite, but my programmers are not very disciplined. What risks will arise and how can I reduce or compensate them?
What is this “strong test suite”?
What do I expect from a “strong test suite”? I would like to have mainly microtests written in the style of joint and contract tests (I have a very voluminous opinion on the topic “Integrated tests are nonsense”, but I have not yet found the strength to write it down. Now I am doing it very slowly. When - maybe I’ll write this book, but for now, here is my last speech on this topic) , with a pinch of functional tests written in the style of the most caring behavior-driven development practitioners. These functional tests will help me understand the functions, and microtests will give me the confidence I need to make changes to the code.
This is the problem:the cost of understanding and maintaining these tests most likely corresponds to the cost of understanding and maintaining the final code. This makes sense, since most likely the same people wrote both. (I understand that I can not reasonably assume this, but, nevertheless, I will.)
Since the discussed programmers are not supposed to be as disciplined as I would like, we can expect that there will be problems in the final code. In general, where I find problems in the final code, I can expect to find a close connection between the tests and the implementation details of this final code. I can expect a lot of indirection without abstraction. In short, I can expect well-tested, well-covered legacy code. Theoretically, I can save this legacy code, but I will have to deal with the usual problems of inconsistency in the cost of saving the code.
I can probably find the best total cost of saving the code with the same inconsistency as with legacy code without tests. This seems intuitively obvious, given that in some cases the tests will be so closely related to the implementation details that I will have to drop the tests and start over (I assumed that the programmers did not write the final code that depends on the tests. I understand that this assumption is risky but I find the alternative too terrible to think about it). As the tests reveal the implementation during testing, they hide the pronounced details of the main aspects of the behavior, and in the end I will do archeology to discover the main aspects of the behavior myself, with or without tests.
I do not want to portray the situation completely terrible. Of course, having tests increases the likelihood that I will be able to change part (possibly large) of the code safely, although not confidently, at least in the beginning. Designing will probably be unpleasant for me, but changing the design will probably be simpler than with a typical base of legacy code. On the other hand, the need to write tests for legacy code gives me such an opportunity to understand the purpose of the code that a simple reading of overly detailed tests can never give.I have to prepare myself for the possibility that the need to write tests from scratch for legacy code is part of the process, not its defect.
Wow. I did not expect this. (Seriously)
I think I would prefer disciplined programmers
It seems that I would prefer to have disciplined programmers who do not create tests to less disciplined programmers providing a strong test suite. No, this is not a trick. (“A simple project passes all the tests, but if there are no tests, then the project is obviously simple ...” No.) Yes, I would also like to have tests, but if someone can achieve good results without tests, then I have no right impose their methods on them. I have to admit that this surprises me, because in the past I probably wrote that I would prefer tests. Then it seemed like a good idea. I cannot explain the shift in my thinking.
Despite this, please write tests, no matter how disciplined you think you are. I believe that writing tests and accompanying refactoring helped me a lot to develop discipline, and I still insist that I will write tests. So if I hired you, I would demand the same from you.
Epilogue
My friend Michael Bolton told me that this article reminded him of the problem of implicit knowledge. In particular, tests (actually “checks”) can only display someone’s ideas about what the system should do, and thus, they will miss out on some of the information that, according to Murphy’s law, will become important for us Wrong moment. And at this moment we definitely want that we had access to the programmer, and not just to checks / tests.
Indeed, the checks seem to have encoded, at best, a relatively recent snapshot of the fact that, probably, a randomly selected version of us thought about the functioning of the product, being limited by our ability to formulate these thoughts (given our skills and energy at that moment). Expressed in this way, it seems obvious that I would rather choose disciplined people, rather than the checks themselves!
July 7 and 8, Joe Reinsberger conducts an online workshop on the theme “Value-based approach in software development”