Tuesday, July 28, 2009

I know I should know how to do this, but...

I'm convinced I have read about why not to do what I'm in the middle of doing. It even feels like a bad idea, but I'm having a brain failure. I'm refactoring. I have a bunch of methods which basically take a list of say 20 similar objects, and merge the similar objects together into new objects. Imagine having a list of 20 numbers. Any numbers within 1 of eachother are 'similar', and should be removed from the list, then their average should be added back to the list. After the process, you might end up with say 4 'representative' numbers.

Okay, now I'm not dealing with numbers, but with complex objects, but the principle is the same. Rather than having like 6 different methods doing basically the same thing, I thought I would implement just *one* mergeList method which would take a pairwise mergeMethod which would then get applied to each pair. Okay, great. So I did that, but now I've realised that I'm going to end up with like 6 different pairwise mergeMethods, when really most of *those* are still pretty similar. In fact, some of them are already in my codebase and are written such that they take a modal switch as an argument.

So now I'm in this situation where I have a generic merge process, but I need to pass modal arguments down to the pairwise merge method. Now for the evil bit.

So, there's this thing called **kwargs. I can write my generic merge process such that it will accept arbitrary keyword arguments, which it can then pass directly to the pairwise merge methods. I could then call my generic method with a pairwise mergeMethod and additional arguments to be passed to that mergeMethod.

Is that evil? Should I be using inheritance instead of modal arguments?

Also, in self-defence, a lot of the constraints here come from dealing with a mature codebase. I'm just trying to work out where I should decide to draw the line and get things Done.

Cheers,
-T

Friday, July 3, 2009

HELP: How do you do Test Driven Design and Prototyping?

Here's where I fall over with TDD. Let's imagine a standard day in my life...

I have some programming problem. I need to build a Thingy to do Stuff. I don't already have anything that does something similar, so I sit down and think about the problem. Along the way, I figure out some approaches to the problem. I don't really believe in BDUF, so mostly I'll just start coding. This kind of exploration is what helps me think, and so I'll build 2 or 3 partial programs before I start to converge on something approaching a solution. Let's dot-point the process so far:

* Problem. Solution?
* Analyse
* Maybe scrawl out a flowchart
* Write a program that for some simple input, generates something like the right output
* Gather up more input data sets, and pump them through the program, extending and fixing as I go
* Reach workable solution

Okay, now a few background points. This isn't how I'd approach a big, team project. But it's how I approach anything I have to solve by myself. I can't just navel-gaze and come up with a great program design, and if we're being honest, I'll bet you can't either. To reach a decent design, I basically need to build 2 or 3 mediocre attempts first.

Now, as far as I understand it, TDD goes hand in hand with unit testing, which is all about small, well-tested, re-usable components. Well, that's great if your fundemental starting point as a designer / developer is the component. But really, it's not. Your starting point is the problem, and the process is one of decomposition and analysis.

Some problems lend themselves to an easy decomposition. A problem which lends itself to a decomposition will immediately make you think "hey, I know how to solve this. If only I had a sorter, a comparison algorithm, some kind of message generator and an input parser this would be a cakewalk!". That kind of problem isn't so hard, and is made out of nice, well-defined objects whose role is well-understood.

Other problems make you think "uh-oh. This one's going to take some coffee, a whiteboard and a fair bit of muttering." Some part of me thinks that the better and more experienced you get, the more new problems should tend to fall into the first category, but in fact I just tend to get given harder and harder problems (or so I think!)

So this is a question to TDD experts. What is the design process that should be followed when confronted with a new problem?

Cheers,
-Tennessee