Recently lots of people adopted DI in their projects (I am working with aspnet core). The problem I have is that DI turns my code towards procedural paradigm. For example in OOP way I would do:
class Something
{
Something(Other object, Dependency dep); // created manually or by factory obj
DoStuff();
}
However with DI I cannot create Something class directly, because I need to satisfy dependencies. Now my code generally looks like that:
class Something
{
Something(Dependency dep); // resolved from di container
DoStuff(Object obj); // executed manually
}
As a result my objects have no methods, they are just bags of properties that are processed by different services. On the other hand I would have to create giant objects with lots of dependencies just to execute simple task, that needs 1% of created object graph.
How to fix my design? This approach has obvious downsides, for instance I cannot pass Something class around, because it needs Object to DoStuff, so I have to pack it into some other class. There are many other problems, like functionality scattered across many files, difficulties in implementing security (because you can request "inner" service from DI) or encapsulation (Object must have all properties public because they are manipulated by external class.
Edit: Small example for better illustration:
Api I would write before DI:
class ShoppingCartFactory {
ShoppingCart Create(id);
}
// encapsulates cart logic
class ShoppingCart {
// internal dependencies passed to cart from factory
ShoppingCart(DeliveryLoader, ItemMetadataLaoder);
// methods encapsulation functionality
Modify(item, quantity);
Save();
Empty();
GetDeliveryOptions(); // loads possible transports from db
LoadItemMetadata(); // loads prices, availability etc. for items
// public properties
ImmutableList<CartItem> items; // immutable list of items
Delivery selectedDelivery; // transport selected by client
}
When client clicks shopping cart delivery options are displayed only once, and subsequent requests do not need them. Therefore with this approach I have to create ShoppingCartDeliveryCreator dependency for each request.
So instead I have to write something like that:
// instead of having properties on cart Object now I have 3 separate classes
// in previous example user of api had no idea how cart works inside
// now he needs to find all classes associated with cart
// also service class needs to take id in each method
// or needs some method like `Contextualize(id)`
class ShoppingCartService {
// executes logic on db
ShoppingCart Read(id);
ShoppingCart Modify(id, item, quenatity);
ShoppingCart Empty(id);
ShoppingCart Save(id, shoppingCart);
}
class ShoppingCartDeliveryCreator (...)
class ShoppingCartItemMetadataLoader (...)
// no logic
class ShoppingCart {
List<CartItem> items; // cannot be immutable, because Service needs to manipulate it
Delivery selectedDelivery; // same
}
You cannot do anything with ShoppingCart class, You always need one of the services. Also as Derek Elkins pointed out
One of the consequences of systematically using Dependency Injection is that your class hierarchy becomes completely flat.
I am not sure if this is good thing. I made lots of research and experiments, however I am not convinced to this style of programming. To get any idea of how something works You need to examine all that code, guess what it is doing and then you may have thin idea how it works. With old example you could just look on the class and You would see all the options, or You could check all classes that take ShoppingCart.
Somethings
would turn intoSomethingFactory
creatingSomething
. I think it is too much bloat, my coworkers already complain on too much bloat. There is no simpler way?