Clean code - Dependency injection
Asked Answered
W

2

7

I was wondering if there is a "cleaner" solution to using dependency injection with binding to classes with a lot of arguments, since according to Robert C.Martin's Clean Code, it's better not to use more than 3 arguments... Any other solutions, ideas (and examples?)

Woodrow answered 23/9, 2014 at 12:59 Comment(6)
Do you specifically mean constructor injection when a class has many dependencies?Splashboard
probably doesn't answer your question, but i think it's quite clean to pass an array as a single argument that actually contains lots of different pieces of information. I've seen this done a lot in javascript, with jQuery being a typical example. Not di, but it does clean up the issue of lots of arguments.Paleoclimatology
if you do seem to have lots of dependencies then I would ask if your design is too tightly coupled.Paleoclimatology
@Splashboard - Yes, I mean constructor injectionWoodrow
Many arguments in a constructor usually means the class does too many things. If not though, perhaps you need to encapsulate some of the related dependencies into a smaller class that can be passed in as a single argument. Can't really help without a sample though.Brottman
I would add that usually too many parameters is caused by lack of a DI framework like Ninject. You don't mentioned that in the question so I wanted to point that out.Rale
T
4

My take on.. Regardless of whether you use Constructor arguments or routine arguments, it is best to avoid lot of parameters passed as arguments.

Even Robert C.Martin's Clean Code, says it's better not to use more than 3, it is just a guideline. In reality this can be changeling as you may need to exceed this limit for number of reasons. For example, if you have multiple constructors, some do like parameters listed nicely so the API discoverable - that also means that the list of parameters would never change.

But this is not the case in most occasions that the parameters may change and re factoring and becomes harder if you have long parameters list. I use arrays, or contain objects, so the change would just that object.

So the preference is to use less parameters 3/4 max, but if you go overboard, create an object you can pass around. Whilst this would cater most cases, sometimes you may have to have the long parameter list IMO.

Terrenceterrene answered 24/9, 2014 at 7:48 Comment(3)
Is it possible to provide a small example how to set this into an object?Woodrow
What I did now is: I created a abstract class and in that constructor, I use the Kernel.Get<...> so I don't have to pass them inside my constructor. Is that a better solution? My other classes derive from the abstract classWoodrow
In that case you need contextual binding. In general IoC/DI frameworks assume 1 interface = 1 concrete class. Most frameworks allows polymorphic binding, but you don't need it since you can elengatly workaround. When you need multiple implementations at once using contextual binding may cause more bugs than finding an alternative solution. (by Polymorphic I mean different implementations coexisting within same interface)Rale
R
5
Dependency Injection != Lot of arguments

The number of arguments you are going to use depends on your personal code design, with DI you focus on dependencies you need to achieve something, you will of course need at least those dependencies even if you don't code a class in terms of "Dependency Injection/IoC pattern". If you have too many arguments you probably have to rethink in someway your design.

If you are in doubt think in terms of maintenability.

"If I have to change something, where it will be? And if I do that change, how many other places will be touched by the change?"

There are possible workarounds, just to say few:

  1. Wrap 2 or more dependencies as a new dependency (chances are high that when you need multiple dependencies you will not need the whole API of those dependencies and hence you can hide part of it behind a new interface.. )
  2. As Spock said you can create a "parameter" object (implementation left to you: parameter list or a struct of objects).

Depending also on your programming language you'll probably find more usefull certain solutions instead of others (option 1 may be more suitable with languages like C++ where each dependency can increase compile time heavily, while option 2 seems likely to be used with languages like PHP because requires less coding and effort by the user).

Rale answered 24/9, 2014 at 14:14 Comment(0)
T
4

My take on.. Regardless of whether you use Constructor arguments or routine arguments, it is best to avoid lot of parameters passed as arguments.

Even Robert C.Martin's Clean Code, says it's better not to use more than 3, it is just a guideline. In reality this can be changeling as you may need to exceed this limit for number of reasons. For example, if you have multiple constructors, some do like parameters listed nicely so the API discoverable - that also means that the list of parameters would never change.

But this is not the case in most occasions that the parameters may change and re factoring and becomes harder if you have long parameters list. I use arrays, or contain objects, so the change would just that object.

So the preference is to use less parameters 3/4 max, but if you go overboard, create an object you can pass around. Whilst this would cater most cases, sometimes you may have to have the long parameter list IMO.

Terrenceterrene answered 24/9, 2014 at 7:48 Comment(3)
Is it possible to provide a small example how to set this into an object?Woodrow
What I did now is: I created a abstract class and in that constructor, I use the Kernel.Get<...> so I don't have to pass them inside my constructor. Is that a better solution? My other classes derive from the abstract classWoodrow
In that case you need contextual binding. In general IoC/DI frameworks assume 1 interface = 1 concrete class. Most frameworks allows polymorphic binding, but you don't need it since you can elengatly workaround. When you need multiple implementations at once using contextual binding may cause more bugs than finding an alternative solution. (by Polymorphic I mean different implementations coexisting within same interface)Rale

© 2022 - 2024 — McMap. All rights reserved.