4 ms·
> The problem with this style of programming is of course that we have to pass the Env around everywhere So why not make it a singleton? Or even better, make i
by zubspace 7y ago
> The problem with this style of programming is of course that we have to pass the Env around everywhere
So why not make it a singleton? Or even better, make it a static class with some static properties?
Yes I know, I said something evil! But before you take out the pitchforks, bear with me:
public static class Master
{
public static ISupplyService Supply;
public static IBankService Bank;
public static IMailService Mailer;
}
This is C# and I actually LOVE this pattern. I have seen it referred to as Master-Pattern, but I don't know the correct term. It solves a lot of problems:
* You don't have to pass essential modules around anymore. You can initialize the Master once and access them everywhere without caring about their implementation.
* Code completion does wonders on this one. You simply type "Mast..." and it will show you ALL available modules. You don't have to remember anything. It's awesome for new team members.
* It is fast. In release builds you can even try to replace the interfaces with the actual classes implementing it for a straight method call.
It introduces a few problems:
* You increase coupling. Once you add a module, removing it or significantly changing the interface is tricky.
* You need to be careful to NOT couple modules to each other, and if you do, do it rarely. Otherwise you will have to instantiate the modules in a specific order which gets cumbersome.
In my opinion: If you are a small team and have sane teammates, give this one a try. It reduces boilerplate a lot and reduces the amount of arguments you need to pass around everywhere.
- bluejekyll 7y agoHow do you test? One of the things you get with dependency injection is a method to replace dependencies with other objects specifically to do thing like unit testing with mocks or integration testing with objects that provide specific failure modes. This is much harder to do when everything is a static. Edit: some typos.
- zubspace 7y agoAll fields in the Master class are interfaces. You simply assign Mock-Implementations in the testing scenario, once in a startup routine. Done.
- tmk1108 7y agoHow do you deal with parallel tests execution? Given that they are all static, you can't have multiple tests running at the same time setting up the mocks or they might overlap
- zubspace 7y agoYou can add a static "InitTest" method somewhere which initializes the modules. Use a double checked locking pattern [1] in there to make sure, that you instantiate and assign the modules used for testing exactly once. [1] https://en.wikipedia.org/wiki/Double-checked_locking https://en.wikipedia.org/wiki/Double-checked_locking
- maaaats 7y ago> * It is fast. In release builds you can even try to replace the interfaces with the actual classes implementing it for a straight method call.* Isn't the interface mainly for the compiler, and in runtime it's just a straight method call anyways?
- zubspace 7y agoDepends on the language/compiler/platform. In C# there's a minuscule difference [1]. [1] https://stackoverflow.com/q/7225205/998987 https://stackoverflow.com/q/7225205/998987
- UK-Al05 7y agoThis is the service locator pattern. Biggist complaint is implicit dependencies, and it's hard to control lifetimes. So this has the advantages and disadvantages of that.
- hvidgaard 7y agoWe have that style of "Master-Pattern" and no matter how small a team you have it introduces problems. It's still a hidden dependency, so you don't know if you've forgotten to initialize it before you get an exception. At least for us we ran into the problem that we wanted to make some changes that meant it was no longer a singleton - but now we had to perform a major refactoring. So you could use a good DI framework such as SimpleInjector and get all the benefits without all the problems. You only have to initialize once, and then it's injected into constructors when needed, and you can inject different implementations depending on context.
- glun 7y agoThis also isn't thread safe, but that's not a problem if you don't run parallel tests in the same process. Using the same stateless test doubles in all tests also solves the problem. I often find myself wanting stateful test doubles though.