I am trying to write code that uses Dependency Injection, both to allow mocking and to have a cleaner, more explicit design.
I often find myself coming up against a particular problem that I would have thought was common, but I have not yet found anything on the net that has helped me overcome it.
The problem is where object A depends on B, B depends on C, C depends on D, and so on in a chain that could have many many links in it.
It seems that to practise depedency injection here, A would have to ask for a B, a C, a D, etc in its constructor (or a BFactory, CFactory etc. for objects that create the instances on which they depend). I am supposing for the sake of argument that the dependencies are not optional or resticted to particualar methods, making setter injection or method parameter injection unsuitable.
This suggests to me that long chains of dependent objects are an antipattern. In an abstract sense it has something in common with the arrowhead antipattern. Long chains of dependent objects form an arrowhead-shaped sequence diagram.
Perhaps, then, I should avoid this practise, and follow the advice in "Zen of Python" that "flat is better than nested". This suggests a design where the main program creates two or three objects, which collaborate and produce a result that is returned to the main program, which then creates another two or three to do the the next stage of the work, and so on.
I have the feeling that this sort of code would be easy to comprehend and to debug, as well as making dependency injection easy. But it seems to go against the Tell Don't Ask principle, and make the main program too fat. I like the idea of main being so small and so obvious that it does not need unit testing. And Tell Don't Ask says to me that if everything starts with A and ends with A, then it is A's responsibility. Suppose A is a customer being billed, and the customer owns the data that is needed to start off the billing process as well as the email address that the invoice needs to be sent to right at the end. Then it seems that A should do the work itself (main could just call Customer.billYourself()) rather than handing reponsibility back to main by giving main a bunch of invoices and an email address.
So, should I be avoiding chains of dependency, to make DI easier, or embracing them because of Tell Don't Ask?