0

I'm currently working on a large application (a hundred libraries, several thousands classes) with several entry points (MVC website, webservices, some background running agents, job schedulers...).

Most of those entry points use a non negligible part of the core services (I'd say around 50% at least).

I know from credible sources that composition roots should not be reused.

As much as I agree with the whole idea, in my particular case, each composition root has a lot (and I mean it) of duplicated code, and that seems kind of bad, as I know for a fact that most of the interfaces/impl bindings will stay the same whatever the entry point for at least some more time.

I could decide not to care, but this situation means that each time I want to add a new binding for a new class, I have to change maybe nine different composition roots.

In the end, I provided preconfigured composition roots parts directly in the projects holding the implementations (at least that does not change anything when it comes to loose coupling), so I just have to call them from the global composition roots when I need them, but this does not look like a right approach.

Does anyone has a better alternative ?

3
  • According to the article you linked, a composition root refers to a single application, and your question is about a single application. Commented Oct 12, 2017 at 19:40
  • In any case, that article already describes in detail the relevant issues. I'm not sure what we can add to that discourse here, other than "the best practice is generally the one that most effectively meets your specific requirements." Commented Oct 12, 2017 at 19:42
  • @RobertHarvey That's the point. It's a single application with a lot of entry points, meaning a lot of nuances between each composition root, but also a lot of duplication. I have solutions, I'm just wondering if someone has some other interesting approaches to that problem, as I'm not really satisfied with what I came up with until now. Commented Oct 12, 2017 at 19:48

2 Answers 2

3

Ok Here's my take. It's not 'a single application with multiple entry points' its multiple applications that share code.

I would try and reduce the amount of code the applications are sharing. eg. Instead of having a web service and a job processor that both do the same task in different ways, have the job processor call the webservice and take out all the code it no longer needs.

If a function is only using 50% of the root composition, then split it up and remove the 50% its not using. Put that function in its own microservice and make everything else that uses that 50% call it and trim their own code down accordingly.

Alternatively, if you don't like the microservice approach, go the other way and have a single monolith webapi that does everything but is the only thing that has the complex composition root. Have everything else as a thin client which calls it.

1
  • Yeah, I guess this is the way to go. All this application (and its entry points) is legacy and the DI was just introduced recently. So the problem didn't jump at our faces until now. But now that you mention it, it seems kind of obvious... Thanks! Commented Oct 13, 2017 at 19:42
2

The general rule of thumb is, try to avoid re-using composition code. Because it will be all fine and dandy until you run into that one exceptional case for one specific graph that's just a little different than the others and now your composition code is on the way to becoming littered with ifs, ands, and buts.

However, that's not to say that this rule cannot be broken when it makes sense and if it makes sense for your scenario I would not worry about the rule too much; there are a couple of things you can do to ease the pain.

Use convention based wiring as much as possible

Most IoC libraries worth using will have conventional based assembly scanning that can wire your IFoo to the Foo implementation automatically. The more you can lean on this, the less code you have to maintain.

If for example you have hundreds of interfaces which each only have a single implementation then you can replace that with a single line of convention-based scanning.

Use Registries as much as possible

Again all IoC libraries will have some concept of a registry or somesuch which allows you to group related wirings together; typically these are in the form of a base class you specialise (Registry is the StructureMap one, for example.)

A nice thing about this is that it can be parameterised so even if you have special cases (e.g. all modules wire IFoo to Foo except this one which uses SpecialFoo) you can encapsulate that decision making into the registry; then "reusing" the composition code directly becomes less of a concern because what you are really doing is adding a set of Registry classes to the IoC container per module. This ends up being a lot less code to manage all at once and sounds similar to what you are currently doing, but you didn't mention if you were leaning directly on your IoC's registry facilities or just hand-rolling this.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.