Wednesday, July 11, 2007

Get the ball rolling, part 1 (of 4, I guess)

A few weeks ago, I got a sad email from a reader. It was about some people around him bashing UML, and more generally, diagrammatic reasoning.
This is not big news: some people just don't like modeling (for various reasons), and in the last few years they've also found fertile ground in several "agile" precepts.
Indeed, his colleagues just sent him a link to Engineer Notebook: An Extreme Programming Episode, by Robert C. Martin and Robert S. Koss. Somewhere around the end, RCM says "We were bedevilled by the daemons of diagramatic overdesign. My God, three little boxes drawn on the back of a napkin, Game, Frame, and Throw, and it was still too complicated and just plain wrong." His colleagues sort of wanted this carved on his tombstone :-).

Now, I've been reading Robert Martin's works since the mid 90s. I've enjoyed several of his papers, and I've even published a couple of papers in C++ Report when he was the magazine editor. I must admit, however, that although I own the book from which that paper has been derived, I just skimmed through it. So, before saying anything, I did the right thing™ and read the paper carefully. Truth to be said, I found that paper laudable, because by providing a realistic example, Robert gives us an opportunity to tackle the same problem in a different way, and compare the results.

Of course, the problem is on a very small scale, so someone could complain that it's not the kind of setting where diagrammatic reasoning shines. That would be a lame excuse, so I won't say that.
I won't even question the fact that they both knew Bowling quite well, and that therefore the dynamics isn't really representative of what they can do in an unfamiliar domain (in fact, there is no user's involvement in the XP episode). Of course that's quite relevant, but what the hell, I can learn bowling rules in no time :-).
I won't even try to assess whether they were faithful to the XP principles or not; it seems to me that they did it just fine: they kept the emphasis on working code, did some refactoring, wrote tests first, applied pair programming... seems like they're doing it by the book.

Still, I do have issues with the quality of the results, and I do have issues with the conclusions. I'll save this stuff for my next posts. Meanwhile, I really urge you to read the paper. It may put you off a little if you don't know/play bowling (I don't :-), but it's a worthy exercise. Read the code, see if you like it. I'll see you in a few days :-).

Note: this is not going to be a theoretical, wishy-washy, hand-waving blurb. I can play theories, but in this case, it's much easier to play code. In fact, one year ago or so I posted a simple challenge for the TDD crowd. I basically got back theories, insults, and the like, but no one wrote any damn code (except in the end, when a good guy did). I'm an action guy :-))), so I'll just show you what I don't like, how I would model and implement the same thing, and compare the results. Actually, maybe you wanna give it a try too!

11 comments:

Anonymous said...

Carlo,
it's gonna be fun!
Giampaolo

Anonymous said...

Ho dato solo un'occhiata all'articolo, solo mi chiedo come mai arrivano a formulare correttamente le regole solo a più di metà articolo??? :)

Anonymous said...

La prima volta che ho giocato a bowling ho formulato correttamente le regole ben oltre la meta' della partita! :-)
Condivido la perplessita' di Fulvio (se non voleva solo fare una battuta): fa parte del loro stile passare subito alla pratica? "Fammi vedere del codice se no non capisco" mi ricorda il "dimmi la soluzione non voglio il ragionamento" degli scolari sbrigativi.

Anonymous said...

no, in effetti non era una battuta, se si leggevano wikipedia magari l'articolo era lungo la metà. Per il resto sono ansioso di leggere le altre 3 parti, i guess ;)

Carlo Pescio said...

Fulvio, Citrullo: in realta' mi pare che i due autori si siano comportati con onesta' intellettuale. Volendo mostrare un approccio XP, che in pieno stile agile ha tra i suoi valori "Working software over comprehensive documentation ", non hanno fatto affidamento su una base di conoscenza "documentale" esterna come wikipedia o altro.
La pecca, come dicevo, e' che in realta' loro conoscevano bene il problema (quindi di quella base documentale non hanno realmente avuto bisogno), mentre in un caso reale avrebbero dovuto interagire con un utente / committente per comprenderlo. Pero' "passare subito alla pratica", "progettando" attraverso la scrittura di test, rifattorizzare il codice, ecc ecc, e' parte integrante dell'approccio XP che vogliono mostrare. Non a caso questo esempio e' stato referenziato parecchio (google trova circa 240 reference).

Tartley said...

I did read Bob'n'Bob's post, but I haven't read Carlo's next three articles yet. I wanted to share one quick thought in defence of TDD.

Do you think it's meaningful to say that TDD "done right" might help relieve the programmer from some of the burden of ensuring that an implementation works correctly, thus freeing them, if they had the right mindset, to focus more on getting the design right.

So even so Bob'n'Bob's solution might not be ideal, that's less a problem with TDD per se, and more a symptom of them giving insufficient attention to the explicit "refactor and improve the design" step that is embedded in the TDD cycle.

Thanks for sharing your thoughts Carlo, I'm really enjoying it.

Carlo Pescio said...

[part 1]
In a sense, this post was largely a reaction to the idea that “three little boxes on the back of a napkin” would eventually lead to be “bedevilled by the daemons of diagramatic overdesign”.
I was also a bit annoyed by the well-chosen narrative strategy whereby you start with a trivial OO design, fail, claim that the culprit stands in trying to design without coding, then you start coding only to come up with a rather poor design that you never question. It was not my intention to prove that TDD doesn't work. I just wanted to show that models don't have to fail us.

You pose a very difficult question, and I honestly think that it can only be answered from within a system of values and beliefs. One can easily support your position, and just as easily support the rather opposite view that TDD anticipates that burden too soon, narrowing your decision space as soon as you delve into coding, and blinding you from seeing radically different structures when you later refactor your code. I would prefer not to venture into this kind of discussion.

Since the question is too hard :-), I'll get into a diversion instead.

Many people talk about "software craftsmanship", although I'm not sure how many of them actually even dabbled in some traditional craft like woodwork. If you do, you'll have to learn how to use and operate a variety of tools.

- You have small, sharp tools like a chisel. You can basically feel fibers when you work with a chisel. You’re working very close to your material, even from a merely physical point of view.

- You have coarser tools like a rasp or a saw; you still get a feeling of your material when you use those; working parallel or orthogonal to the fibers gives you a completely different feedback. You don't really feel fibers like with the chisel though. Still, you get some jobs done faster and [perhaps paradoxically] also more precisely.

- You can also use small power tools, like a drill or a circular saw; here you're even more removed from your material; maybe you can feel some hard knot inside the wood. You need to know your material beforehand; you need to predict some reactions. Wood can easily burn if you choose the wrong drill bit, or the wrong speed. However, you can get a more precise cut or hole, in a shorter time, etc. You can also cut away your finger :-), so you gotta be more careful.

- Then you have "big" tools like a turning lathe. Here most of the feeling about your material is lost, so you need to know more beforehand, to choose the right shaping tool, the right speed, etc. However, it's the most appropriate tool when you want to shape wood as a solid of revolution, it's fast, precise, repeatable, etc.

Now, move to the much more flexible and complex world of software design, and... we want to do everything using a single design technique. Irrespective of scale, shape, purpose, etc. This is not engineering, but also not craftsmanship. It's bigotry, and a few gurus have been pushing this down people throats for quite a while now.

So, I've got absolutely nothing against TDD. I've got everything against the idea that there is a single design technique that provides the best value, at every scale, for every problem, can lead me toward every shape, etc.

I see that you have left a comment on the yahtzee kata too. In that context, for instance, I'm skeptical about the idea that TDD + refactoring can eventually drive a procedural solution toward a DSL (unless you want to get there from the beginning - but that's the big design choice, the other design decisions are at a much smaller scale). That does not mean that the DSL is the best solution, or that my DSL is the best DSL, or anything like that. Just that the conversation embedded in the TDD + refactoring style is unlikely to suggest some shapes.

Carlo Pescio said...

[part 2]
Does that make them useless? Of course not. Just like a lathe is not making a chisel useless (or viceversa). A software designer needs to get acquainted with many different thinking tools, and grow his own style, which may eventually favor one approach over another, but always being aware of what he's trying to accomplish, so that he can pick the most appropriate tool to get there.

This is in the end why I choose "brain-driven design" as a tagline. The design I came up with for the bowling is mostly domain-inspired. I also did some upfront modeling. Overall, it's a decent design. It doesn't mean one has to be domain-driven all the time. Or do upfront design all the time.

For the yahtzee, I ventured into a reflective conversation with code to find out a satisfactory DSL. It's still not a universal approach. It worked fine there.

I used TDD with a few guys working on a banking project not long ago, because I saw the opportunity in the specific subsystem we were designing together. I may not blog much about it, but I use it when I see a good fit.

I rarely go the MDA way (in the sense of generating most of the code from models) but I can certainly recognize quite a few cases where that's the best approach.

Bottom line: use your brain; be flexible; to quote Bruce Lee, be like water :-) http://www.youtube.com/watch?v=46jO96bz_Fo

Tartley said...

Thank for the thoughts. I'm open to the idea that diving into coding too soon makes it harder to both understand the specification, and see potentially superior designs.

However, I need to see this for myself to truly believe it. (which, obviously, is tricky - it must be aggregated over a large number of exercises and real-world problems)

Maybe I have modified the definition of TDD to suite what I believe it should be, but I don't think TDD says "do no up-front analysis". It says "do just enough up-front analysis". Therefore, in my worldview, your flexible approach of using whatever technique works best is (very deliberately) folded into the explicit TDD process.

I think it's one of the strengths of TDD that the first test you write - your outermost system or functional test - is a purely domain-driven black-box test. This is to put the developer in the mindset of the customer, to understand their issues and domain, to understand the problem, analyse and minimize the scope of the solution, and to produce a system-level "is it working" test which is agnostic to all possible designs. All of this is very deliberately done before thinking about any design or coding issues.

Then comes a design step. You can't start writing unit tests until you know what implementation you're going to write, and you can't know that until you've produced a design.

Agile in general might say "don't design the whole system at this point, just design as little as makes sense", but I don't believe TDD forbids one from using any design technique at this point that you deem appropriate.

Thanks again.

Tartley said...

As regards the Yahtzee exercise. You say you're skeptical that TDD + refactoring could transform a procedural solution to a DSL. That makes me think two thoughts:

a) The thing you are skeptical about is, of course, exactly what I did. I acknowledge that I cheated, in that my refactoring steps were guided by your design input, rather than purely by my own thought. So I agree that my 'demonstration' doesn't count. But I can't help but wonder whether, if I was a better designer, or spent more time thinking instead of wanting to study the details of your article, I might have progressed through similar steps all on my own, thus showing that perhaps your skepticism is unwarranted.

b) Also: The transform from poor solution to better solution isn't necessarily required. I wonder whether, given an appropriate amount of experience and thought, my TDD process might not have yielded a good design straight away, without going through an intermediate procedural design. TDD doesn't prevent a good design - it just gives you the process to move from a bad design to a better one if that's the situation you find yourself in.

I feel silly disagreeing with you. It's clear you have given these issues more thought than I have. I'm just thinking out loud about what I yet understand and what I have yet to think about more deeply.

Carlo Pescio said...

Jonathan,
you’re doing the right thing: exploring your own design style.

Yes, I believe you’re stretching the definition of TDD quite a bit, but this is not really important (unless you get into a fight about the nature of TDD :-)

My view is that when I approach a problem with some specific technique, part of the dialogue between me and the problem is “embedded” in the technique. So a code-centric technique comes with some embedded dialogue, a model+domain-centric technique with another dialogue, etc. Piecemeal techniques come with their own embedded dialogue. “Grand design” techniques come with their own. Even within diagrammatic reasoning, approaching the problem with a sequence / activity diagram in mind, or with a class diagram in mind, is likely to make me focus on different things and get different results. There is a strong relationship with the psychology of problem solving, which has been deeply explored within Gestaltism (see for instance http://www.carlopescio.com/2006/01/functional-fixedness-and-einstellung.html for a few old reflections of mine on this stuff).

Of course, the embedded dialogue is only part of the equation. Your experience, sensibility, creativity, goals, discipline, etc etc come into play very soon as well. However, in my experience, one is better off choosing the approach with the embedded dialogue that best fits the problem at hand, or the results expected.

You’re right when you say that you have to see things with your own eyes. The trick, of course, is to keep your options open and avoid defaulting to a single approach every time :-)