Test-Driven Development by Example
What it's all about: Test-driven development is about being able to take tiny little steps forward, test that the step took you in the right direction, and repeat. The "TDD Mantra" is red/green/refactor:
- Red: write a test which will exercise a feature, but which will fail (because you haven't yet written the code)
- Green: make the test succeed, doing whatever you need to do to get to "green" as quickly as possible -- don't worry about prettiness
- Refactor: now that you have code which passes the test, eliminate all the duplication
The book then shows 2 fairly detailed examples of a development project (or snippet of a project) which progress using this style of coding. The first example deals with the creation of multi-currency capabilities for an existing project. In the space of 17 chapters, the author walks you through the creation of 6 classes (1 test class, 5 functional classes), complete with the thought-processes behind them. The code is written in java, and is trivially easy to follow, because it gets introduced in tiny little chunks; most chapters are less than 6 pages in length.
The second example is the creation of a unit testing framework in Python. It is significantly more complex and real-world than the first example, but again proceeds in very small steps, and in small chapters.
The final part of the book contains patterns for test-driven development -- practical real-world advice on how to do this stuff for real. Nearly all the "patterns" are phrased as question/answer pairs, and they range from deeply technical design patterns to advice on the best way to arrange the furniture.
What's good about the book? Kent Beck is a very good writer -- his writing is clear, he is not afraid to leave out stuff he assumes you can guess for yourself, but when he does go into detail you feel it is necessary to get the big picture, rather than mere geek bravado. Even if you don't adopt Test-Driven Development, many of the ideas are well worth considering for your day-to-day coding situations.
What could have been better? The book stresses the importance of taking 'little steps,' and sometimes you feel impatient to move to more challenging tests before properly finishing the current chapter. I was also hoping for more of a discussion on the practicalities of unit testing database-driven systems, where you frequently have to test business entities which are closely coupled to the database.
Summary If you code for a living, or manage people who do, you should read this book -- it's a quick enough read -- and consider some of the assertions it makes. If you feel you're introducing more bugs than you expected, if you feel uneasy about how close your work matches the requirements, this book gives you some powerful ideas. You can purchase Test-Driven Development by Example from bn.com. Slashdot welcomes readers' book reviews -- to see your own review here, read the book review guidelines, then visit the submission page.
Does the reliance on incremental development and refactoring rather than a intricate, up-front design really work, or result in a big wad of band-aids?
Is pair programming OK, or do you sometimes get stuck with the nitpicker from hell who has to have every detail his own way?
Is close involvement with the customer good, or does it just give them daily opportunities for endless bright ideas that prevent convergence?
Just wondering...
I'd be the first to admit that XP offers a lot of risk-reduction -- for teams that are working on things that are easy to unit-test.
With a class that is supposed to take in a bond and output the yield curve, it's easy to write a unit test. But what about the next class, that renders the yield curve on the screen? What about the complex, distributed system of Excel objects and forms things that draw a network and things that flash green and go 'ping' to indicate a change, that are equally necessary but generally much harder to write and much more likely to go wrong?
Has anyone tried to apply test-first programming to complex guis? I can't say that any obvious way to do it has ever occurred to me. Worse yet, when I ask I generally find that people either
a) Are in the same position as me, or
b) Believe that a GUI is a little thing you spend a couple of days on after you finish the application
So, for now XP is something I read about rather than something I actually do.
Whence? Hence. Whither? Thither.
XP has worked in some small scale applications pretty well. It isn't for every project or every person, but in some cases it can be very effective, and in others (as you stated) it can be a disaster.
I think it's great that there are new ideas for ways to develop software, (although XP is actually fairly 'old' in computer science terms). There is no magic formula for producing quality software in a reasonable amount of time yet, but XP is another step in the right direction.
Note: While XP's entire methodology wasn't written down until about 1996, many of the ideas that it uses had been in circulation since the 70s.
What?
What? Is he going to write a book for every rule of XP?
Testing is important, but XP testing philosophy is a catch all for actually thinking about your product and the purpose of you product. XP is about making hack programmers look legit. XP has some good points, such as an emphasis on simplicity, testing, and customer satisfaction, but mostly it's about making bad habits look good, like no design and iterative feature hacking with ignorance to the bigger picture of the app.
Some design up front is important. Documentation is important. Code ownership is important to an extent. In a medium to large system, having everyone able to change any line of code is just stupid. People change shit and don't have a clue why the code looks the way it does. One of the arguments for no code ownership is that a lead architect can't keep it all in his head. Well, what about a team of that consist of many folks that aren't as capable as that lead architect? they are able to comprehend the whole system according to XP. And, they are allowed to change whatever they want, when they want. So, get a couple of average programmers with large egos, and you have a lot of problems.
XP is great for people who are happy doing bug fixes all day instead of avoiding the bugs to begin with. The assertion that XP results in less bugs is pure speculation and from my experience, a very misleading claim. Just because your test succeeds doesn't mean that your program is correct. And if the test is the only glue validating the success of your final solution, you're screwed.
I couldn't agree more.
I can't think of many jobs - at least for college/university educated people - that do not require soft skills like ability to work with your coworkers and communication (meetings, presentations, acting as a tour guide for VIPs, etc.).
I used to hate having to deal with other people any any way. In fact, that was one of the reasons why I decided to embark on a research scientists (Physics) career. As a scientist I wouldn't have to deal with people, give talks, socialize or - most imporant of all - end up in any kind of a manager/boss line of work. I would just sit, think and write papers. That's what I thought and boy how wrong I was.
Most science, and experimental physics in particular, is done in groups. There's no way around it. You can't run a lab alone so you need to have people around you. Even as a postdoc you have to be able to hire good PhD candidates and supervise them. You have to be able to interview them, understand what makes each of them tick at workplace and how to manage them to get the best out of them.
Then, unless your lab is established and extremely well funded, staffed and equipped, you often need collaboration from other groups. Making contacts with other scientists and establishing mutually beneficial collaboration requires publicity (talks!), diplomacy (socializing!) and patience.
A person who cannot work with other people simply does not fit into this environment. No matter how brilliant scientist he is, without the social skills he is very likely to turn out as nothing.
I still get slightly nervous when I have to a give a talk. I still don't like meetings. However, I have grown fond of managing people, because, as difficult as it sometimes can be, it's a wonderful feeling to see your highly motivated and skilled people working with you in harmony. The older I get the more I appreciate social skills over raw intelligence or mathematical/logical ability. If it all comes in one package, jolly good. However, if I had to choose between a budding physics genius with a highly abrasive personality and a slightly well performing person with good social skills, I'd choose the latter. No question about it.
The owls are not what they seem
So, write your tests first. But do your design before you code, not after you've put together a thousand lines of crap.
If you've written 1000 lines of code before you refactor, you're waiting way too long. I do little refactorings every few lines, and bigger ones whenever things don't look right.
Look at it this way: you can do your design before you code, while you're coding, or afterwards. The waterfall advocates about 80:20:0. But that assumes that you learn nothing, think of nothing when coding. That's stupid; instead, what people do is grumble and imagine what they'll do in the next version.
Now that I'm doing test-driven development, my ratio is about 20/30/50. I still do some design up front, and that's very valuable. But instead of having those raging arguments about what design might work best, we start building and find out, refactoring towards the best design as we go.
Waiting until you've cobbled something together that passes the test and then hoping that your boss will allow you to refactor is a loser.
If a boss is such a micromanager that he's telling you which lines of code to work on every 15 minutes, then it's time for a new job. The people I work for recognize that I'm a professional and trust me to tend to my business, especially given how willing I am to explain it to them.
When bosses ask about refactoring, I explain that we do it so we can go faster. If they think it's a net loss, then I am always glad to prove them wrong: if they want to measure productivity each month, we can see which way works better.
Think of it this way: not refactoring is like not exercising: you get slower and slower, everything gets creaky and unreliable, and you die sooner because your arteries are clogged. A little regular exercise keeps you healthy, limber, and active.
I'd already written an engineering requirements document which we reviewed with management and our partner company on the project. I've already put together an architecture document showing all the major components and who talks to whom (reviewed with the dev and QA teams). My manager even insisted that I write a design document on the specific module I was about to write, which included a schedule and unit tests.
After two months of documentation I was desperate for a chance to code. TDD? Why not. I gave it a try -- not in nearly the detail the book mentions, but I have a dozen tests each hitting a key requirement of the design. When I recompiled the code for the ARM hardware, it was gratifying to see that everything still worked on the target platform. Every time we make a change, we have the initial tests I wrote to make sure nothing is broken. It's nice.
I'd like to make the junior guy's do this -- at least then I can tell how far along they really are. "Oh, it's 80% there!!" Sure, show me the test cases that pass and how these relate to the requirements and design.
Don't ask me to pair program. I'd rather write docs and review them with the team and do code reviews.
BTW, I didn't like the book that much. But the method is good.
Especially with multi-processor systems, you need a solid design. Design errors here will kill you no matter how much testing you have. Generally, thinking of the tests will help you flush out your design. With a multi-threaded / processor situation, you have to know that you have no race conditions or deadlocks. Tests only say, "for this run, nothing went wrong" you need a design that says "for any run, it will always work". Review the design with others as these can be hard to spot. Once you have a good plan, you have better tests to help ensure you deliver on the plan.
Actually, if you look at the credentials of the original "inventors" of XP, and some of it's biggest champions (Robert Martin, Martin Fowler), you'll see that they are big champions of proper software design as well. They just realized that "big design up front" -- which they were preaching -- wasn't working out, and that most implementations of more iterative approaches weren't working out either. Hence a "reaction" in the form of XP.
As for discipline, proper implementation of the XP practices requires far more discipline than most highly structured approaches. What it minimizes is the creation of documentation for documenation's sake. What has happened is that people who hate design/discipline have decided that by saying "we're doing extreme programming", they are off the hook. But don't blame the inventors.
On one project, we had a bug that would always cause a segfault at shutdown. No one had ever been able to track it down -- it wasn't hurting anything as far as we could tell, but it was highly annoying. This was a very small shop and we were just starting XP (or any determinable development process, for that matter), so we hadn't been doing much in the way of pair programming anyway.
Myself and another developer tried pairing to find the bug. We talked it out briefly, and decided to do a binary search of the code with print statements (as the debugger couldn't find it). We'd start the program then exit it, trying to find where in the shutdown process the bug was.
We went over the logs together, and the first person to narrow down another potential location. I'd suggest a spot and add a print statement there, then he'd suggest one. We'd then run the program again, collect our logs, and start over. If I got stuck, he'd have an idea and vice versa.
It took us about ten minutes to track it down and figure out exactly what was going on. I'd spent a couple of hours on it alone without making any progress before, and I think he'd done the same. If we'd paired on that before, we'd have saved a bit of time and money.
I'm not sure where you get the idea that pair programming is having some slob sit behind you and breathe over your shoulder. In my experience, it's like having a conversation about code that produces working code. If you can give up the idea that you have to be right and that your way is the best way and, for goodness' sake, hand over the keyboard about half the time, you'll probably find it's a lot more productive and even more fun than working alone.
how to invest, a novice's guide