There’s more than one way to skin a cat

May 10 2009

iterative and incremental development means delivering functionalities one at a time driven by some priority critera (e.g. business value). similar functionalities happen to be developed not all at the same time. so, design focus on supporting all the functionalities planned for a given iteration, and nothing more. key to succeed are simplicity, flexibility and a wide automatic test suite.

imagine a financial project where customer needs to process via nightly batch all monetary transactions received daily. he ask for supporting critical calculations first, and set at lower priority to automatic double check (it can be done manually in the meantime). in a plan of a few months, 3 or 4 different calculations are going to be developed.

but we start from the first one, and let the code (aka design) support the others later.

just after the first user story get signed, design consists of three main roles:

  • a BatchCommand that collects items and process calculations, and then updates state on items (e.g. date processed)
  • a Gateway to the database that knows criteria to filter items and knows how to select and save items from/to the database
  • a Connector in charge of handling connection to the database

here’s a brief recap using CRC cards:

CRC_original

next iteration starts, and customer select another calculation to be developed, which just differs in selection criteria. then, the team has to find out the simplest way to support this scenario. well, a few exists, of course. in this post, i’m focusing on some design strategy we can use, comparing them.

we need to change Gateway selection criteria. someone says go for inheritance, and override criteria in a subclass. someone else says use composition, and move responsibility to change into another object. you choose, me too: composition!

so, we change Gateway to delegate a collaborator to gather selection criteria: let’s say, a CriteriaBuilder, even better as an interface. with our favourite IDE we perform an “extract method” refactoring followed by “move method”, moving selection criteria to a criteria builder. then, we add another builder for current user story. finally, it’s just a matter of wiring two Gateways with two CriteriaBuilders. design ends up being like this:

CRC_inner

what’s wrong with this? well, nothing i would say, dependencies are well handled: low-level details (Gateway) depend on abstraction (CriteriaBuilder interface) and high-level policies (concrete CriteriaBuilders) don’t depend on anything, they provide that abstraction. in other words, we succesfully applied Dependency-Inversion Principle. so, again, what’s wrong?

we created two different gateways, that’s the matter, in my view. we stated Gateway is an infrastructure detail, it “knows how to select and save items from/to the database”. so, why do we need two different ones? has infrastructure changed? not at all.

in OO an object has an “outside” and an “inside”. GoF, in the Decorator pattern, to explain this simple rule used the metaphor of an object skin and guts:

“Changing the skin of an object versus changing its guts. We can think of a decorator as a skin over an object that changes its behavior. An alternative is to change the object’s guts. The Strategy pattern is a good example of a pattern for changing the guts.”

now, imagine we move selection criteria “outside” from Gateway, into another object which collaborates with the Gateway, but doesn’t hold a reference to it: it wll be sent as a parameter of the message “please, apply selection criteria on this gateway”. let’s say we name this new role a Selector. we end up having one Gateway and two Selectors, this way:

CRC_outer

that’s it.

to recap, my suggestion to you while doing design: whenever you find an opportunity to simplify object responsibilities, moving some of them away, ask yourself “is this a domain or an infrastructure issue?”. if possible, avoid mixing the two: leave objects cohesive, and apply DIP. then, all other things being equal, avoid having more instances of a given infrastructue class, unless you really need to set different infrastructures (in this example, a gateway to filesystem or an in-memory one).

as Beck says, “Design is beneficially relating elements”.

Leave a comment