On Jun 11, 2008, at 12:06 PM, Chuck Remes wrote:
I'm having trouble figuring out how to drive the design of a class.
I'm hoping I can get a hint or two from the more experienced BDDers
on this list.
I'm writing an adapter class that sits between a 3rd party library
and my business logic. I would like to extract some information from
objects available from the 3rd party lib and covert them into ruby
objects. My desire is to insulate my ruby business logic from
changes in the 3rd party library by putting all of this conversion
code into a single adapter class (and some related "event" classes).
Using BDD techniques I have created a pretty simple interface to
the adapter class. So far the adapter class has two main public
methods (plus a bunch of accessors to allow the dependency injection).
#discover_instruments
- this method calls into the 3rd party library and pulls out the
3rdPartyInstrument object and stores it off for further manipulation
#save_components
- this method permanently saves the 3rdPartyInstrument if it is a
FUTURE, or if it is a COMBINATION it iterates through each
sub-3rdPartyInstrument and saves it off
Using mocks and ruby's brain-dead simple support for dependency
injection I have been able to mock out and verify this behavior.
Now I need to add another public method which I will call
#generate_internal_instruments. What I would like this method to do
is iterate through my #components and create two related objects.
Object one will be my RubyInstrument class (called something else,
but this will suffice) and a second is a
RubyInstrumentCreationEvent. The intention is to pass the 3rdParty
component to RubyInstrumentCreationEvent.new(component) where it
will extract all salient details from the 3rdParty component (again,
this is for insulating the business logic from knowing this 3rd
Party lib). Then I will pass this RubyInstrumentCreationEvent to
RubyInstrument.new (or RubyInstrument.build) where it will finish
the construction of itself.
Ideally, all of these steps would be private to the Adapter class
and would expose a single public interface called #build. All of
these public methods exist solely so I can test these specific
behaviors.
Any suggestions on how to accomplish my goals? Is my difficulty
pointing at a code smell that I am not detecting?
Hey Chuck - sounds like you're trying to plan the whole process out up
front. TDD is about discovery. Here's what I'd recommend:
Start w/ a simple example of what you want the adapter to do - the
simplest think you can think of - when you send it the
#generate_internal_instruments message. Get that to pass. Now the next
simplest thing. Get that to pass. Refactor. Rinse. Repeat.
As you do this, the method might start to do too much and you'll see
opportunities to break it up into smaller private methods or perhaps
even methods on a brand new object you don't know about yet. That's
all good. Let the design emerge.
If/when you do choose to move things out to other classes, you may
want to introduce new mocks in the examples and move some of the
examples to the group describing the new object. That's all fine.
Don't anticipate code smells, but keep sniffing. When you *do* smell
them, deal with them immediately. Don't wait.
HTH,
David
_______________________________________________
rspec-users mailing list
[email protected]
http://rubyforge.org/mailman/listinfo/rspec-users