Question

I have a process which must do 8 steps, in a particular order. One of the step involves sending an email, another one going on a distant FTP server, another one querying a database, and so on. Now to be able to unit test these 8 steps, each of them is a method in a distinct class. So far so good.

Now the problem I'm facing is that the 'parent' class that calls the steps now receives in its constructor 8 classes, which is clearly a code smell here. You could tell me: hey, just create one class with the first 4 steps, and another one with the 4 others, and the parent will simply receive two classes in it's constructor. In my mind, this also feels wrong - I have the impression that I'm adding complexity and not really solving the problem.

Is there a design pattern or another technique to use when many steps must be called by a class?

Was it helpful?

Solution

If the class is truly simplified to the point that it's just providing a controlled sequence to the operations, and the complexity of each operation is managed by the dependent classes, then I don't think there is a problem here to solve.

If the sequence of operations for this process is truly 8 steps, then the constructor with 8 dependencies adequately exposes the complexity of the process.

If anything should be considered for refactoring, it should be the process itself. Can it be simplified? Can it take fewer steps? If not, then it's as simple/complex as it needs to be and the coordinating class' constructor should reflect that.

Trying to hide the necessary complexity through arbitrary step-groupings would be a worse code smell than a large constructor.

OTHER TIPS

Further to Eric King's answer which is a good warning.

If you have to sequence over a series of operations, consider if they are similar enough that you could give them a common interface that could be invoked - such that you could treat them as a collection of abstract tasks.

Another thing to consider is if you might need to change or switch out any of the parts - when you want to change it - it might become more obvious how you would want to rearrange things.

Your solution is the same 'shape' as the problem which is often a good sign.

Is there any interaction between the 8 classes? If not, then one possibility would be for your 8 classes to all implement an interface with the single function doTheThing() (hilarious example function name, please don't use it in real code), then you could pass them within an IList instead of as eight separate parameters. Your "parent" class then just needs to iterate through this list, calling doTheThing() for each member.

The concept you are looking for here is 'dependency injection' and the related concept 'inversion of control'.

A good overview of the subject is here:

https://martinfowler.com/articles/injection.html

The thing that you are doing wrong is doing "steps" in the first place. That indicates that you did a procedural decomposition and packed "steps that need to be done" in some arbitrary classes. You know, Services, Managers, things like that.

The problem with procedural decomposition is that it is ill suited for abstractions. You can't really do much except group procedures together and you sooner or later arrive at the point you are now.

The cure for this is object-orientation, although admittedly this is not as easy as it sounds. Objects are supposed to be autonomous things (not a group of procedures) that "encapsulate" some logic and/or knowledge. Because they do that they can be used for creating suitable abstractions, which ultimately (as a side-effect) solves your dependency problem.

So in a nutshell you have to stop thinking in terms of "steps", and have to start thinking in terms of "things".

Licensed under: CC-BY-SA with attribution
scroll top