Collateral Effort Revisited 19
One of the things I love about TDD is that it takes all the scaffolding and collateral effort for creating a class, all indications of bad coupling, and makes them entirely visible. This is also one thing that makes it very hard to start TDD in legacy system.
When you realize that it’s very hard to test a class out-of-context, the right answer is to start decoupling each class so it can be run out-of-context. When we are successful here, tests run very very fast and are easily self-verifying and isolated. It is a beautiful thing even if it follows many ugly hours of painstaking work.
The wrong answer, I’m convinced, is to build a mega-framework for testing that allows you to test in-context. This type of framework typically creates a totally realistic runtime environment (complete with database, configuration files, directories, etc). This approach allows you to think that you can ignore your dependency nightmare. You really can not Mega-test-frameworks take a such a long time to run that developers stop running all the tests all the time. This is a far worse problem than breaking dependencies because it breaks the whole process. Mega-frameworks don’t solve the problem, they only defer the solution until the problem gets worse.
When you are faced this kind of collateral effort, the answer is to work through it, not to sweep it under a rug. Working through it is work, indeed, but this is about doing the right thing not doing the easiest thing.
How To Misuse Ant 66
Professional software developers can and should maintain their own build system. We strive to deliver working software, not source code. However, if you want to shirk this responsibility, and you’re a Java programmer, and you use Ant, then there is a way out.
The first step is make your build so complex, brittle, and hard to use that nobody else can even build with it, much less maintain it. Here are some well-worn techniques:
Use Ant Like An Imperative Programming Language
Make heavy use of the if
and unless
attributes, and try to create lots of conditional properties. Chain them together if you can. Try to get it so that it’s impossible to get anything to work without setting at least a dozen different properties from the command line. When you find yourself needing a loop structure, you know you’re on the right track.
Create Useless Default Targets
Useful default targets make it too easy. Make sure you do something that will fail after a clean checkout. And don’t use the standard build.xml filename…otherwise people will be able to build simply by calling ant. Name your build file cibld.v2 or something obscure like that.
Make One Big Target That Does Everything
Just as decoupling and encapsulating your code makes it simpler, decoupling and encapsulating actions in your ant script makes it much easier to read and use…avoid this at all costs. Put everything into one big target that cleans, builds, makes JavaDoc, deploys, runs FindBugs, emails you that it’s done, prints the results to the office printer, and reboots the build machine just for luck.
Don’t Use Metatargets; Use the depends Keyword Instead
A corollary to the OneBigTarget rule is the avoidance of metatargets. By making lots of small targets that do one thing well, you introduce the possibility of chaining them together to do different operations. These “metatargets” allow people to use the build in ways you never anticipated. What horror! Things must be done the way you define them back when you originally wrote the script. Why would anyone have the arrogance to do it another way?
If you have to decouple into small targets, make sure you chain them all together using the depends
keyword. It’s almost as good as the OneBigTarget.
Avoid Self-Documentation
When creating a target, don’t give it a useful or informative name. Be sure not to use the description
annotation for your targets. This can be used with the -projecthelp
option in ant to print out a list of public targets and their uses! How will ever confuse people like that?
Never Refactor Your Scripts
Finally, if you do have to change something (although I can’t imagine why that would ever be necessary), make sure you leave all your old stuff in there. Granted…the source control system is probably tracking all of your changes, but you can never be too sure. It’s best to just leave all those old, crusty targets in there. It’ll confuse everyone else, and it makes it easier for your to find your old stuff without learning how to use subversion.
Once all of this complexity is in place, you’re ready for the big payoff. It was a lot of work up front, but it’s worth it, because now you can argue to your boss that build management is way too hard for you do to all by yourself. Point out that you’ve been spending 30 hours a week on the build and you should have no problem talking him into hiring a build guy to do it for you. Voila! No more build system headaches for you. Just don’t be surprised if, during the next round of layoffs, the build guy keeps his job (how could we manage without him?!?) while yours is shipped off to India.
Of course, if you DO want to maintain your own build system, you can start with a lot worse than my Nifty Thrifty Build Script
Are "else" blocks the root of all evil? 67
So, I’m pair programming C++ code with a client today and he makes an observation that makes me pause.
The well-structured, open-source code I’ve looked at typically has very few else
blocks. You might see a conditional test with a return statement if the conditional evaluates to true, but not many if/else
blocks.
(I’m quoting from memory…) Now, this may seem crazy at first, but one of the principles we teach at Object Mentor is the Single Responsibility Principle, which states that a class should have only one reason to change. This principle also applies to methods. More loosely defined, a class or method should do only one thing.
So, if a method has an if/else block, is it doing two (or more) things and therefore violating the SRP?
Okay, so this is a bit too restrictive (and the title was a bit of an attention grabber… ;). We’re not talking about something really evil, like premature optimization, after all!
However, look at your own if/else
blocks and ask yourself if maybe your code would express its intent better if you refactored it to eliminate some of those else
blocks.
So, is there something to this idea?
Accepting what you're given 10
- 6” turkey on Wheat
Sure it could have said something like “As an instructor, I want a sandwich I can eat so that I won’t pass out in the afternoon from either lack of eating or too many carbs.” He didn’t use the “right” form. On the other hand, he got the idea across. However, he wasn’t done just yet.
He added a few acceptance criterion (or as Mike Cohn is now saying, “Conditions of Satisfaction” [I Like that better]).- Extra tomatoes
- Extra jalapenos
- Nothing else – written but not recorded…
- 6”
- Turkey
- Wheat bread
I’d argue back, I satisfied the customer so bug off. And it really misses the point of a card as a placeholder for a conversation, which we had.
Even with all of these written details, the request could seem a bit ambiguous, right? Was this in addition to other stuff? Is there a “regular or default” amount of stuff to which we’re adding additional constraints? Since we had a conversation it was clear to the implementer at the time (me). And since I was able to implement the use story before I lost the context , nothing more was required.
So off I went. When I finally found the place I had some time to wait in line. I didn’t notice any jalapenos and I started to wonder what I should do. I then though, well wouldn’t he like some other stuff as well. I mean I like a lot of stuff on my sandwiches, doesn’t he? Shouldn’t every sandwich have ranch dressing? What could I substitute for the missing jalapenos? Maybe I could give him a call. Of course did I mention I’m in Houston? In the basement of a skyscraper ordering food? Much like in the North the buildings are connected to keep out the elements – cold in that case, so too are the buildings in downtown – it gets hot but more importantly sticky. Turns out I didn’t have cell service.
Anyway, what was I doing in line? I was gold-plating his lunch. The only time you should consume gold is when you’re drinking Goldschlager. When is that? ... seldom – maybe during college, .
What do you do in this situation? You might be the kind of person who, like me, likes to leave things open until well after it time to make a decision. My motto is “No matter how important it is today, it’ll be more important tomorrow. Until it isn’t.” You might be the kind of person who tends to prefer things be resolved. (If you’re familiar with the MBTI, that’s Perceiving versus Judging – but be careful of those words, their definitions in that context are idiosyncratic.)
Well given our conversation, the card which I held in my back pocket and the confirmation in the form of mostly written conditions of satisfaction, I just went with it. Besides, I was pretty sure they had jalipinos. I’m in Texas three things are required:- Cowboy hats
- Bolo ties
- jalapenos.
How often have you been tempted to add ranch dressing, oregano, black olives and bell peppers to your code?
Uncovered not always bad 37
- Using a code coverage tool such as Cobertura, Emma
- You are actually looking at the coverage of your tests (say you’re looking for stale code in our unit tests – [and you’re thinking gosh, I wish I had some unit tests so I could have some unused code in my unit tests])
- You are testing that unit under test generates an exception
@Test(expected=RuntimeException.class)
public void methodThatWeExpectAnException() {
throw new RuntimeException();
}
This test will pass. Yes it’s trivial, of course it would pass. (In reality the single line of code would instead send a message to some object that ultimately would need to generate a RuntimeException for a “real” test to pass.) Fine. That’s not the point.
So what’s the problem with this? Nothing, except that some coverage tools will report the last “line” (the close curly-brace) as not being covered since we did not exit the method cleanly.
Here’s a way to rewrite the above test so that you can assure coverage:@Test
public void methodThatWeExpectWillThrowAnException() {
boolean expectedThrown = false;
try {
throw new RuntimeException();
} catch (RuntimeException e) {
expectedThrown = true;
}
assertTrue(expectedThrown);
}
This version is a bit longer, isn’t it?
Here are some comments I’d like to hear from you:- Is it any better?
- Does is express our intent any better?
- Isn’t it just silly to run coverage tools on your test code?
- Is anybody having Pascal flashbacks? (If you don’t get this question…you poor &*$^@~).
What I've Learned from Master Chef Rino Baglio 76
If you want to learn Craftsmanship, you would be hard pressed to find a better mentor than Rino Baglio, the Executive Master Chef at Pazzaluna, in St. Paul, Minnesota. I had a chance to catch up with Rino this past weekend when I was in Minneapolis to teach a tutorial on Aspect-Oriented Design at ICSE 2007.
I have known Rino for over a decade, starting when Ann and I were loyal patrons of Il Bacio in Redmond, Washington, the restaurant he owned and operated with his wife Patsy until a few years ago. Through his cooking classes and many conversations about food and the restaurant business, I learned a lot about what it really means to be a chef and the long mentoring process that true chefs go through.
In the U.S., we think that passing a two-year culinary program qualifies you to be a chef. In Italy, an aspiring chef apprentices to a master at the age of 13 or so and spends the next 20-odd years mastering the craft before deserving the designation of “chef”. You can spend 7 years just working through the stations in a restaurant, cold dishes, salads, sauces, etc., just to become a “cook”.
Here are some of the characteristics of a true craftsman.
A craftsman is widely recognized by peers
Rino recently won an international competition in Italy, one of many times he’s been recognized nationally and internationally.A craftsman is passionate about the craft
Rino says that if you are passionate about food, you will work on the presentation of even humble dishes. Pasta, as well as lobster, deserves an attractive presentation.A craftsman delivers value to the customer while meeting business objectives
Rino keeps the kitchen lean and efficient. He keeps costs low by relying on high-quality ingredients, keeping waste to a minimum, and constantly improving the skills of his staff, all without ever compromising quality. In the year Rino has been at Pazzaluna, costs have dropped, while business and profits have increased.A craftsman knows that quality is the number one priority
Rino knows that cutting quality today means less business tomorrow. He keeps quality high by keeping morale high. Morale is high because his staff is constantly learning new and better recipes. Also, as you watch him interact with his staff, you can see that he treats all of them, from his sous chefs to the dishwashers, with dignity and respect, while always holding them to high standards.A craftsman never stops learning
You would think that he knows it all, by now. Yet, he has never forgotten a lesson his own mentor taught him, “you can learn something from even the worst cook, because he always knows something you don’t!” How many gurus do you know that think they have nothing left to learn?
What does all this have to do with software? Pretty much everything. Like cuisine, clean code is part art, part science. Clean code is created by passionate craftsman who are fanatical and fastidious about every detail. Clean code is the product of years of accumulated experience. The decisions a master makes moment-by-moment, whether test-driving the next feature or fighting a fire, reflect the wisdom and breadth of knowledge that produce high-quality results quickly and efficiently. Finally, a master leads by example, bringing the rest of the team up to his or her standards.
So, if you’re young and ambitious, latch onto the mentors around you. If you can’t find any, find another job. (Your organization is doomed anyway; so you might as well move on now.) If you’re older and wiser, seek out the promising junior people, teach them what you know, and learn from them as well! Oh, and if you want to taste real Italian food, make a pilgrimage to St. Paul. Tell Rino I sent you.
Apologies for Lost Comments 28
There was an accident earlier this week. Apparently a number of blog comments were deleted in a frenzy of spam-combatting deletions. Your clever and useful feedback was a casualty in the spam wars.
Rather than turn off all comments, we are going to work on ways to better combat the blasts of blog spam we’re getting these days.
I just though you might want to know it wasn’t censorship, and it wasn’t personal.
The Myth of Learning Compression 12
There is an odd idea that learning is compressible, that any training course of any length can be squeezed into a very small time box and delivered to any large number of people without significant loss.
As an educator and as a guy who has a pretty big learning load at any time, I know that this is a myth. I can cover any topic much better if I am working with a handful of individuals over the course of a week or two. If you double the number of attendees, then the interactivity is highly degraded, and discussions become time sinks. If you half the time, then interactivity is likewise degraded, and material that might have been covered must be skipped or skimmed.
I have a joke with my coworkers that the ideal environment for some large corporations would be a three-train roller coaster. The participants would buy a ticket, climb on board, sail past the materials at speeds in excess of 60 miles per hour, and would collect their certificate at the other end. As one train is unloading, another is loading, and another is in progress so that we could cover many hundreds or thousands of students per day. Of course, they would learn next to nothing and would not really participate at all.
But I respect my corporate customers, including the fact that they have much to do, and cannot easily afford a one-week work-stop for each dozen team members, all with consultant/trainer fees. Some large organizations would have us on-site for years in a row before all their developers would be trained in any technology. It’s just not reasonable, and they push for a more feasible schedule.
It’s a rock and a hard place, and people on both sides understand that it is so.
The good news is that compressibility is not a total myth. There are techniques and tools that can make the training more effective, so that less time is necessary in class. There is the idea of a jump-start, where a topic is introduced and discussed in a short time and students are given materials on which they can continue via self-training. The compressibility myth drives us to more dense and useful presentation. It is a valuable spur.
It also has the advantage of the time box. If you have only three days to teach someone how to TDD, you have to choose the three most important days-worth of material to teach. This kind of prioritization is the same thing that we demand of our product owners in a scrum, and is perfectly fair and reasonable.
Even though compressibility is a myth, it is a useful myth.
The only mythological part of the compression myth is the idea that it is lossless. It is lossy compression. But as is the case with audio and visual compression, compressed learning can be “good enough.” If that’s what we’re after, it’s all good.
The Hidiocy of XML Languages 37
I’ve been reading up on some of the newer aspects of SOA, and came across BPEL. It’s another language you are supposed to write in XML. Get ready for a rant.
I’ve had it. What is the matter with these people? How, after all the experience we’ve had with XSLT, Ant, WSDL, etc., etc., could they create YET ANOTHER XML language. Are they dolts? Are they idiots? What gives.
Look, writing in XML is hideous. It’s wordy, it’s error-prone, it’s arcane, it’s redundant, it’s redundant, it’s redundant, it’s… HIDEOUS! To make matters worse, we have been embedding OTHER languages INSIDE this horrible container. EGAD! YIKES! ZOUNDS! FORSOOTH! This is just plain nuts, stupid, idiotic, retarded, poo-poo-headed, silliness!
Haven’t these people heard of economy of expression? Haven’t they heard of YACC? Don’t they know that domain specific languages SHOULD BE LANGUAGES? Don’t they know that languages have specific GRAMMARS?
Besides, have they ever tried to write an interpreter or compiler that uses XML as it’s source? It’s not any easier than writing a YACC parser! Indeed, it’s a lot, lot, harder.
EMBEDDING THE GRAMMAR OF YOUR DSL IN XML IS STUPID!!! DON’T DO IT!!!!!#$#
$!!!
I hereby declare a revolt. From now on anyone who considers themselves to be a serious professional must refuse to write another line of XML. When asked, say NO. Instead, write a little YACC grammar that is nice, and small, and translates into that hideous XML. You’ll save yourself GOBS of time if you do! What’s more, if you sell your parser for $5 per download, you’ll probably be able to buy a new boat! Maybe a fleet!
100% Code Coverage? 34
Should you strive for 100% code coverage from your unit tests? It’s probably not mandatory and if your goal is 100% coverage, you’ll focus on that goal and not focus on writing the best tests for the behavior of your code.
That said, here are some thoughts on why I still like to get close to 100%.
- I’m anal retentive. I don’t like those little red bits in my coverage report. (Okay, that’s not a good reason…)
- Every time I run the coverage report, I have to inspect all the uninteresting cases to find the interesting cases I should cover.
- The tests are the specification and documentation of the code, so if something nontrivial but unexpected happens, there should still be a test to “document” the behavior, even if the test is hard to write.
- Maybe those places without coverage are telling me to fix the design.
I was thinking about this last point the other day when considering a bit of Java code that does a downcast (assume that’s a good idea, for the sake of argument…), wrapped in a try/catch block for the potential ClassCastException
:
public void handleEvent (Event event) throws ApplicationException { try { SpecialEvent specialEvent = (SpecialEvent) event; doSomethingSpecial (specialEvent); } catch (ClassCastException cce) { throw new ApplicationException(cce); } }
To get 100% coverage, you would have to write a test that inputs an object of a different subtype of Event
to trigger coverage of the catch block. As we all know, these sorts of error-handling code blocks are typically the hardest to cover and ones we’re most likely to ignore. (When was the last time you saw a ClassCastException
anyway?)
So my thought was this, we want 100% of the production code to be developed with TDD, so what if we made 100% coverage a similar goal? How would that change our designs? We might decide that since we have to write a test to cover this error-handling scenario, maybe we should rethink the scenario itself. Is it necessary? Could we eliminate the catch block with a better overall design, in this case, making sure that we test all callers and ensure that they obey the method’s ‘contract’? Should we just let the ClassCastException
fly out of the function and let a higher-level catch block handle it? After all, catching and rethrowing a different exception is slightly smelly and the code would be cleaner without the try/catch block. (For completeness, a good use of exception wrapping is to avoid namespace pollution. We might not want application layer A to know anything about layer C’s exception types, so we wrap a C exception in an A exception, which gets passed through layer B…)
100% coverage is often impossible or impractical, because of language or tool oddities. Still, if you give in early, you’re overlooking some potential benefits.