Agile People Still Don't Get It

Some Agreement

Calculating Risk

Stacks, Queues, Bowling, and FitNesse.

Tests are not Specs.

Anything not testable is useless.

But You CAN Test It.

Agile people Get It.

re: "the code is the design" and "to understand the code, read the tests", I can see Cedric's point to some extent. I've seen some tests that have been much more difficult to understand than just the code, and I've seen some cases where a new developer on a mid-size project adds behaviour that's already written into the application because it was not easy to find out how it was done already.



So if we're going to live by these mantras, we have a couple of responsibilities that we must honor:



1 - make the tests look like specs, not tests.

2 - as patterns appear within a codebase, document them. i.e. "If you want to do xyz, take a look at the Abc class". This sort of documentation is general and lightweight, making it easy enough to maintain while providing a powerful service.

Cedric: "Tests are (executable) specs.



First of all, tests are not specs. Not even close. Somebody in the audience was quick to give a counter-example to this absurd claim by using a numeric example ("how do you specify an exponentiation function with a test?")"...



That one is easy: f(x,n) = x * x * ... * x (n times)



But that is not a spec. What Cedric is calling "spec" is simply a requirement (or a user story to use XP terminology).



The spec must be something that is either achieved or it is not. If you hardcode the input data (like it is used in JUnit), then obviously it will test a very small portion of the solution space. But you can auomate the input to test different parts of the solution space, randomly.



"but my objection to this claim is much broader than that. Relying on tests as a design specification is lazy and unprofessional because you are only testing a very small portion of the solution space of your application (and of course, your tests can have bugs). Tests also fall extremely short of having the expressiveness needed to articulate the subtle shades that a real specification need to cover to be effective."



Again, Cedric is thinking that a requirment is a spec. You can't test a requirement, but you should test if you have achieved what the spec specifies.



"This claim is part of a broader and more disturbing general Agilist attitude that is usually articulated like "Your code is your spec", along with some of its ridiculous corollaries such as "Documentation gets out of date, code never does".



Anyone who claims this has never worked on a real-world project. And I'm setting the bar fairly low for such a project: more than five developers and more than 50,000 lines of code. Try to bring on board new developers on this project and see how fast they come up to speed if all they have to understand the code base is... well, just code. And tests.



I am currently getting acquainted with a brand new project that is not even very big, and while I understand Java fairly well, there is no doubt in my mind that for ten minutes I spend trying to understand how a certain part of the application works, a five-line comment would have given me this knowledge in ten seconds."



If you can read a 5 line comment, you can also read a 5 line method. If you need to read a 100 line method, maybe:



1. The name of the method is not good enough.

2. The method is too long.



Substandard code is substandard code no matter if you do XP or not.

It might be the answer, but it is a step in the right direction. I was on an agile team that started out smoothly, with TDD and Scrum, and our burndowns looked good. Then, we needed to interact with a non-agile company guru, and suddenly our project dragged to a halt. Even if Agile is not the answer, it is a better answer than what was done before. Until something better comes along, it is the choice for developers and testers that want to see their work progress in product, rather than in Project Milestones. The criticisms shown in Cedric's blog are of HOW it is being done, but not of the Agile process itself, and as Robert Martin points out, the criticism is valid when folks respond to a call for help with "you should have done it agile", even when the project they are working on started before Agile was born.







Who's is your point of view? Developer's?

But it is not a developer's decision to ship a product, is it? Product owners often have valid business reasons to ship buggy code, and they have the right to do so. As a developer I may feel shitty about them shipping crappy code. But if they don't, I don't get my pay cheque. And I don't have a place to come tomorrow to refactor what I did today.



>>A feature that crashes is much worse than a feature that doesn't exist.<<

"A client of 4 tier application sometimes crashes when you drag/drop xxx to the top-left corner of yyy window on Japanese version of Win2K



I love your arguments. Yet I feel that they are of the religious flavor with all these "completely unacceptable". I sympathize Cedric's "being situational".



Being situational, sometimes we take a hard stand and sound like you sound here to make a strong point. But other times we got to admit existence of imperfect reality, rather then alienate and irritate all species of programmers in a wild of the industry.



>>However, I disagree quite strongly with Cedric regarding "Calculated Risk". From my point of view it is completely unacceptable to release code that you aren't sure works. Either make sure it works, or don't ship it.< >A feature that crashes is much worse than a feature that doesn't exist.<[?] " != "Drag/drop support doesn't exist". US customers will be begging me for a ship, and even someone in Japan may say ".....(I don't speak Japanese but you get the drift)"I love your arguments. Yet I feel that they are of the religious flavor with all these "completely unacceptable". I sympathize Cedric's "being situational".Being situational, sometimes we take a hard stand and sound like you sound here to make a strong point. But other times we got to admit existence of imperfect reality, rather then alienate and irritate all species of programmers in a wild of the industry.

I agree that not doing TDD is irresponsible.



But then who wants really good code? Maybe in developed countries people think they need to write the tests first and then they need to be sure nothing breaks.



In south america first we code, then we test if we have time. And we do not write tests, we simply start the debugger. No code gets bigger than a 100 thousand lines without collapsing under its own weight. And that is after a lot of copying and pasting, so the actual number of individual and unique lines is not more than 3,000...



The project may go on and on for several months without making any real progress. In developed countries this happens too when they hire undeveloped workers like for example in Duke Nukem Forever...



So, if you want to have a real boost in productivity, you have to TDD and you have to pair developers and switch pairs on a daily basis. Moreover you have to hire the best. The top 2% of the people that applies to the job are the ones that are 10 times more productive than the average. The top 10% are the ones that are 4 times more productive. All the rest can be spared or hired as bean counters, nothing else.



Sometimes some of the people hired realize that they are working to make their own job irrelevant. Those are the people we want: The ones that look into what they have done and realize that their job is about to be fnished, so they say: "Look I'm about to finish this, what's next?", "What do you think about doing this and that?", "Did you realize we can improve what we are doing?", and so on.



The people we don't wat is the people who think they were hired to do X and they look for ways to make themselves important, and that means doing their job improperly and halfheartedly. If they find that their job is about to finish, they look for ways to extend it, so they can be paid for doing nothing or almost to nothing. We get rid of those persons as soon as we can, we put other people to learn what they are doing and then we move them somewhere else where they can do no harm.



Anyway, this is not the standard way to work in latin american countries. Most companies in this countries simply hire and hire people to do irrelevant stuff, and they never finish. They can't finish, because having no job in an underdeveloped country may mean starvation. There is no social security, so in the streets there are lots of people willing to work for pennies. Having a stable job is the ultimate goal for almost 99% of the population, so once they get hired they look for ways to remain in the position.



Using TDD and using CVS or SVN at work is considered a big step in wrong direction, because it means other people can look at my code and actually understand it. Where is job security then?



So from day zero we need to make sure people are not in the way. We need to pair them everyday and force them to use SVN, ant and TDD.

Jeff:



> Instead of making excuses about why it's too hard to test everything, we should be asking, why *can't* I test something?



Indeed; I work in video games and often hear that such-and-such code is inherently untestable. What you say? My assertion, that came from repeated utterances of the above, is to say that a programmer finding that a given operation is untestable is akin to saying that that programmer doesn't know what that operation is doing. It's not Rocket Science(tm). We're doing operations on databases for crying out loud.



So yeah, "if you don't know how to test it, you don't know how it works." Unfortunately, that's more than a little off-putting to someone who's not already a Xealot. :)

> I never said I didn't test, I only said that sometimes, I voluntarily didn't do TDD

I think it doesn't hurt when you sometimes implement first and write the test afterwards.

It just depens how much code you add before you follow with the tests.

The more untested code you add, the harder it will be to get it under test afterwards.

You don't have those problems when you test first. It just takes some time to get used to it.



> ...sometimes, coding the feature is more important than writing the test first.

You shouldn't seperate coding features and writing tests. It's one unseperable activity.



> Still, I have yet to find code that is 100% tested...

That's true but that doesn't mean that you shouldn't test at all.

It also depends heavily on your design how much tests are necessarry.

If you use techniques that keep your state space lean (e.g. the Single Responsibility Principle)

it's not too complicated to permanently have extremely high test coverage.



> ...and I think that requiring that every single line of your production code to be tested before

> your software gets shipped is a certain guarantee that you'll never ship.



If you do it the other way round, the software will need to be permanently fixed.

You'll arrive at a point where you are so bussy fixing that you don't haven time

to develop something new. Any change will increase the pain.

Shipping untested software is shipping something unfinished and your customers

will force you to finish it. The preassure will be higher at orders of magnitude

if you finish it AFTER you have shipped it!























Bob, I think you misunderstood me with:



<<

In his article, Cedric said: "But the truth is: at times, I don't do TDD because implementing a feature quickly is more important than a fuzzy feeling." This is what I find to be unacceptable.



Firstly, I won't accept the notion that testing is just for a "fuzzy feeling".

>>



I never said I didn't test, I only said that sometimes, I voluntarily didn't do TDD. I still test, but sometimes, coding the feature is more important than writing the test first.



Still, I have yet to find code that is 100% tested, and I think that requiring that every single line of your production code to be tested before your software gets shipped is a certain guarantee that you'll never ship.



--

Cedric





I realize that it's a someone radical position to take, but it has become my position that TDD is a necessary discipline for professional developers. I consider it rather like sterile procedure for doctors. It's simply what you have to do to write professional code. (At least it's what I have to do.)



And, yes, I do like these disputes. When we agree we only learn that we agree. When we disagree we learn together more than the two of us know separately.

The analogy that helps me in such discussion is the tradtional engineering analogy.

Car manufacturers are spending millions on computers for all kind of simulation.

The simple purpose of those simulations is TESTING. They are there to proove

that the engineer's decisions are right and the car meets the specification.

In mechanical engineering, there's no QA-Team around to fix the mess of an engineer.

They have too proove with thorough calculations that their designs work.



We are all happy that the cars, airplanes and other things are tested thoroughly before

they get into production and engineers have appropriate skills and tools in hands to actually know what their disigns

are doing, are we?

Why shouldn't we use the same care for our software?



Uncle Bob: Do you enjoy those disputes?

I really enjoy reading them!





I haven't talked with Cedric, but, I assume that when he says that he won't use TDD during the development of a feature, he actually does not mean he won't test it. I assume that what he means is that he will not do TDD.

Early I think almost all of us did this. Now I know better and I use TDD for production code, only in the case of Spikes or some legacy project I get involved that doesn't have unit tests infrastructure I actually don't use TDD. Nevertheless, I think it isn't required that a person does TDD to be considered a professional software developer!

Sometimes I say things that are provocative in order to get people to think in a direction opposite from the one they have thought in. When I presented the talk at Google, I said, "here are a couple of things that I use to help *me* think about what I want to do with TDD." On that slide, entitled "mindsets", was the contention that if it's not testable, it's useless.



Obviously it's impossible to automate tests against everything. That's not the idea. The idea is that until it is tested (and it doesn't have to be tested in a unit test, or even programmatically), you have no idea that the software does what it is supposed to do. At which point, you shouldn't be shipping it. This is what the majority of code is about in most systems.



Instead of making excuses about why it's too hard to test everything, we should be asking, why *can't* I test something?



No, TDD is not a panacea. No, tests are specs, or at least they are not a complete form of specification, but the more you try to get them to read as specification, the better your tests will be. No, perhaps untested code is not completely useless, but it's highly questionable. For people getting so upset at such assertions, I suggest looking at them with these thoughts in mind.

Perhaps I should have used a softer word than "sure". Perhaps. On the other hand, I reject the notion of shipping bad code because we didn't have time to make it right.



In his article, Cedric said: "But the truth is: at times, I don't do TDD because implementing a feature quickly is more important than a fuzzy feeling." This is what I find to be unacceptable.



Firstly, I won't accept the notion that testing is just for a "fuzzy feeling". Secondly, I won't accept the notion that speed is more important that accuracy. I will grant you that speed is important. However, it is even more important to be accurate. Therefore, in the time allotted, we should do only what we know we can get working, and tested.



Yes, there is a statistical limit to our "sureness". In finite time we can never be absolutely sure that our code works as planned. But we can have a high degree of confidence. So to restate my point: From my point of view it is completely unacceptable to release code that you have not tested to a degree to satisfy your project's standard of a high degree of confidence.

"From my point of view it is completely unacceptable to release code that you aren't sure works."



You can *never* be sure that any non-trivial system works 100%. You have to use statistical techniques to focus testing effort where the greatest risks are (as you said) and apply other practices (formal inspections, for example) that have been shown to reduce latent defects.



So, releasing code that you aren't sure works is not only acceptable but the only practical thing to do unless you are working on small systems.





A response to Cedric's post Cedric raises a number of good points. Particularly that if Agile evangelists use religious arguments, and don't connect with real developers with real problems, then they aren't going to get much further. The early adopters have adopted; and the next batch of folks are a bit more skeptical. To reach them we have to make much stronger arguments that are tied to the reality of development.However, I disagree quite strongly with Cedric regarding "Calculated Risk". From my point of view it is completely unacceptable to release code that you aren't sure works. Either make sure it works, or don't ship it. Period. There is enough risk in that scenario to go around.Besides, nobody actually calculates the risk. What they do instead is HOPE. They hope that their code will work well enough to keep customers and managers from getting angry. Frankly it is this hopeful attitude that makes software engineers look like fools. We optimistically offer our latest release, and cross our fingers behind our backs that the customer won't do those things we know will crash the system and corrupt the database.A feature that crashes is much worse than a feature that doesn't exist. A feature that doesn't exist will defer revenue for a release, and may give a competitor an advantage. But a feature that crashes makes enemies out of our customers. Our customers interpret features as promises. When we release a feature we are promising that it works. When it crashes we have broken that promise. If we break too many promises we lose trust.Cedric complains that all the examples of TDD are trivial little things like stacks, queues, and bowling games. It is reasonable to be skeptical of such simple examples. They aren't real. There is also a reason that such simple examples exist. They fit into the time and space allowed. This is an old problem and Cedrick isn't the first one to raise it. It was raised during the endless debates 35 years ago regarding structured programming.However, Cedric is wrong that no significant examples exist. I'd like to refer him to FitNesse . This is 30,000 lines of Java code, written test first, and with a code coverage in the 90%s. Studying FitNesse has a lot to recommend it, both for examples of what to do, and for examples of what not to do. FitNesse is a real application with real customers and real issues. It's a web driven application with a back-end database and some fairly complex business rules that involve separate processes, and multiple languages.Of course they are. A test is an unambiguous specification of behavior. I agree that tests cannot specify everything. The power-function example is a reasonable point. (Though I'd like to ask Cedric how he'd make sure that a power function worked.) You cannot specifywith tests. However youspecify a. Indeed, you can specify many of the most important behaviors of a system by writing tests for them.This is nothing new. Parnas-tables are an example of unambiguous specifications that are testable. Decision tables are yet anothers. Indeed, a great deal of a specification hadbe testable, otherwise system test will have no role.Cedric is right that you cannot depend entirely upon tests for the system specification. But he is wrong to case aspersions on the whole discipline of specifying through tests. There is hardly a better way to be unambiguous and current, than to specify tests and require that they always pass.Here's the thing. If you can't test it, you don't know that it works. If you don't know that it works, then it's useless. If you have a requirement and cannot prove that you have met it, then it is not a requirement.Any behavior of a computer is testable. And there are a finite (though very large) number of tests that will prove that any computer program running in finite memory works as specified. (Even the power function.) Therefore, the ultimate specification of a program is the exaustive list of tests that demonstrate it's behavior.Of course nobody can write that many tests. So we opt for statistical methods. We opt for code coverage rather than path coverage. We make sure that every line of code is executed in a test. We make sure that every decision is tested. And then we take a (in the case truly) calculated risk that if we have tested every line and every decision then the system will work as expected. We call this "due dilligence".When Cedric talks about "Calculated Risk", he may be referring to a more benign form than I referred to above. If a team of developers invests the appropriate level of test effort to cover lines and decisions up to a very high level, and they also decide that this level of coverage provides them with a low-enough defect density, then they can take the calculated risk because they have done due dilligence.However, this does not mean: "I ran it on my laptop last week, and it seemed to work OK."Actualy, Agile Peopleget it. We get it very well. And we have gone very far into helping the rest of the industry get it. There is hardly a big or small company that has not tried agile developent in one form or another, and there are many, many, that have invested significatnly and are enjoying the benefits.Agile is not a silver bullet. Agile is not THE ANSWER. But Agile techniques, and especially TDD, are very powerful techniques to get software written well, and to increase the level of professionalism in our industry.!commentForm -r