views:

354

answers:

6

Quick design question.

ClassA has a method called DoSomething(args)

In DoSomething(), before it can actually do something, it needs to do some preparatory work with args. I believe this should be encapsulated within ClassA, (as opposed to doing the prep work outside and passing it in) as nothing else needs to know that this prep work is required to DoSomething.

However, it's where the actual preparatory work code belongs that is making me think.

The preparatory work in my particular example is to create a list of items, which satisfy a certain condition, from args.

My hunch is that I should create a new class, ListOfStuff, which takes args in its constructor and put this preparatory work here.

From a TDD-perspective, I think this is the right choice. We can then unit test ListOfStuff til our heart is content. If we had put the preparatory work in a private method of ClassA, we'd have only been able to indirectly test it through testing DoSomething().

But is this overkill? Since adopting the TDD and DI approach, I've seen the number of classes that I write multiply - should I be worried?

Ta.

+4  A: 

What is the simplest thing that could possibly work? That's the TDD mantra. Don't try to think too far ahead. If the time comes to create the helper class, you'll know it because you'll be doing all sorts of related work in multiple methods in other classes. Until then, do the work in your method. If it makes the method too long or cumbersome to read, extract the work to its own method. This method can also be tested to your heart's content without the need for another class.

tvanfosson
I thought you only tested public methods though? Unit testing private methods, even through a hack exposed by the unit testing framework, has always seemed a little 'iffy' to me.
Duncan
It depends on your problem domain. My company's product is a class library - we *really* want the private or internal methods unit tested.
plinth
@Duncan - For unit testing, use the InternalsVisibleTo attribute.This is a very useful attribute. It allows a 'friend' assembly to see the internal methods/properties/members of another assembly.
Simon Hughes
I didn't say you had to test the method if it was private. I said that you could test it. Personally, I wouldn't because I'm not depending on it directly and testing it would make my tests brittle. Moving it to another class prematurely, I think is a mistake.
tvanfosson
Hmmm ok.This raises another question - whether to test private methods or not - but I'm sure there's plenty of material out there I can catch up on. My instinct is always NOT to test private methods, as they are tested indirectly. Otherwise you'd spend an unrealistic amount of time writing tests.
Duncan
+1  A: 

Your object model design should be considered on it's own, rather than in the context of your development strategy. If building ListOFStuff and passing to to DoSomething really is how the object model fits together best, do it, regardless of your development strategy.

I think you've answered your own question a little, however, since ListOfStuff makes it easier to unit test, that probably means it's also a cleaner design.

Hope that helps!

Zachary Yates
I'd have to say that ListOfStuff would be purely created as a helper for this, so wouldn't feature on any object model design. Hmmm. But I *do* like it for it's explicit interface for testing. Hmmm. Could be one of those 'no right or wrong answer' cases!
Duncan
+2  A: 

Definately put it in a new class. Its called separation of concerns. You don't want to overload a class and make it do all sorts of other stuff. This is because your class will not be able to be used anywhere else as its so specific to one thing.

Put it in class, then use that class elsewhere. Otherwise you'd have to write this again and again in the future.

To make it extensible, and be able to pass in all sorts of different algorithms, the design pattern your after here is the Strategy pattern. But that is for the future...

Simon Hughes
In general I agree IF the code is also used elsewhere. That wasn't presented as the case here. Here it's only used in this one method. Creating a new method, I can see that, but creating a new class at this point would be overkill.
tvanfosson
@tvanfosson - You're right, the code, at the moment, won't be used elsewhere. I'm familiar with the mantra of 'refactor if used more than once' - but I'm also seeing design in much more of a Separation of Concerns light these days. But I'm 'concerned' (!) I'm taking it too far!
Duncan
@Duncan, but the only method that's concerned with the calculation is the current one. You need to balance principles -- in this case SoC needs to balance with YAGNI (you aren't going to need it).
tvanfosson
+3  A: 

There are a couple of heuristics here.

  1. Is there state on this class that survives from invocation to invocation? Does this prep work get done every time you need to doSomething(), or is it done and saved? If so, that argues for the class.
  2. Does this computation need to happen in more than once place? If so, that argues for a class.
  3. Can the details of the implementation of the doSomething() method, or the preparation work for it, change without affecting the enclosing class? If so, that argues for a class.

Well, three heuristics. No one expects the Spanish Inquisition.

Charlie Martin
Duncan
No, it sounds to me like you're thinking right. You might have an argument for a private inner class; otherwise put the prep work in a private method.
Charlie Martin
+1  A: 

Since adopting the TDD and DI approach, I've seen the number of classes that I write multiply - should I be worried?

If your aim is procedural programming, yes. But since you're almost certainly wanting to work in an OO fashion, no.

Most people use too few types, spend too little time thinking about OO design.

Your questions about class responsibility reflect maturation of thinking (imho).

Jeffrey Fredrick
+1  A: 

SoC is valid only if the "concern" in question has nothing to do with the class, or you find classes sharing this "concern" (aka, violating DRY). In your case, it seems that the code is intrinsic to the class - so possibly a private function would be more apt.

As tvanfosson said above, you need to balance SoC with YAGNI. Personally - I think you might be mulling over this prematurely (I know! I do it too all the time).

imran.fanaswala
Yeah, I think if you were doing SoC as a purely academic exercise, or ListOfStuff did something REALLY complicated and I wanted to test it on it's own then I'd have a ListOfStuff class which would do this work. However, from a pragmatic perspective I'd just put all the work in ClassA. Compromise!
Duncan