Part of the discussion involved commenter Xixi asking if anyone had followed point #5, "Use many, many objects with many interfaces". It turns out, I've been following that model. I started to reply there, but I recognized a blog post after a bit.
Here's my general workflow, and I've found it to be quite effective.
The linked-to article refers to interfaces as "roles", and that's probably the easiest way to think of them.
If I have a few related items which need to be handled, I first create an interface for it:
IMessage
(I realize it isn't the java convention to prefix interfaces with "I", but I prefer it - especially with as many as I ended up with). Add in a few obvious functions, send
, recv
.Create the concrete class (the actual implementation):
FooMessage
. In this case, the messages would deal with "Foo". So, it has send
, recv
, and say count
. Gotta know how many Foos we have, right?Next up, the test class - but I'll get to it in a moment. This is where I write it in the overall workflow, but it doesn't make as much sense without talking about Mocks.
Last, I write the mock class for the concrete class. It also implements
IMessage
, but most of the implementation is empty - just accepts the parameter, and maybe spits back a default value.Which brings us back to the test class. Since I refer to everything via its interface, using those mocks is easy. In
FooMessageTest
, I use the concrete class FooMessage
, and a whole bunch of mocks. Generally, everything but the class being tested can use mocks, so testing ends up nicely isolated and repeatable. In practice, concrete classes implement several interfaces (
IFoo
, specifying count
, so you could have IBar
, which specifies weight
.)Okay, this was a lot of work up-front, and I'll be honest: I approached it with some concern that it wouldn't pay off.
Well, it has. Refactoring, with the assistance of NetBeans, has been a breeze. Adding in new, or modifying old functionality has been super-easy. Yes, there's a few hangups, but they tend to revolve around my lack of planning than the overall process. I don't feel as "free" as when I use Ruby, but I don't feel held up by the language or its environment.
The hardest part has been maintaining discipline. It is really easy to think that this particular class doesn't need an interface, or a mock, etc - but that is no different than any other methodology.
No comments:
Post a Comment