-
Notifications
You must be signed in to change notification settings - Fork 25
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Mediator and DI #30
Comments
Hi @KrishnaKollu, Whether or not the Do note, however, that this example application makes a few shortcuts from time to time. The goal is to demonstrate how command and query messages can be transported from client to server and back, in a maintainable way. To ensure you are following best practices, my book is probably the best resource for that. |
Thanks Steven! In this article you mentioned:
Do you have any recommendations for how to make it more clear what the consumer is using? i.e. would it make sense to do that via code comments? You also mentioned in one of your comments, "Single file holding multiple queries is a model I use to get a team get accustomed to this model". So that I understand, would that be something like this: class OrderRepository {
/* Queries */
class GetOrderByAddressQuery {
....
}
/* Query Results */
class OrderResults {
..
}
/* Handlers */
class GetOrderByAddressQuery implements IQueryHandler<GetOrderByAddressQuery, OrderResults>{
...
}
} Would this single file approach also make sense for commands? |
Adding code comments would IMO make no sense. Code comments only tend to drift apart from the code that actually compiles. I have no further recommendations. If this loss of clarity is a problem, simply refrain from using a mediator.
I would not recommend nesting these types, because it makes the consuming code more cumbersome, as they will have to append the wrapping type ( |
Thanks for explaining that. In your article, you also mentioned:
What do you think of the Command Bus pattern? Conceptually, I think it's the same thing - a mediator. Do you still advocate against an ICommandProcessor pattern? Here's an example of a Command Bus. Given this above comment, is this something you would advocate against? |
I skimmed over the article and they indeed seem identical. My opinion hasn't changed about its use. |
Thx for the responses Steven. I'm working in a programming language that doesn't support generics/parameterized interfaces, and am wrestling with how to correctly implement the command handler and query handler patterns there. The book says:
Can you help explain what this Mediator would look like here? I wish the language supported parameterized interfaces. Do you recommend any alternatives to the Mediator design pattern that would still let me still use a single interface |
Touché. The Mediator pattern I refer to in my book is the exact same pattern. The statement on my blog should be viewed in the context of .NET. Since you are not using a language that supports generics, the Mediator pattern is probably the best solution, both for handling queries and commands. |
Makes sense thank you. I’m not entirely clear on how the mediator solves for the LSP. I can still bind a command with the wrong handler when setting up the mediator? The client can also be passed a mediator that is missing a binding all together as well? Would it make sense to build a single mediator class that could handle both command mediation and query mediation, with two separate methods? I figure if I’m using a mediator I might as well use one mediator vs. two, as I can imagine there will be use cases where a client will need both the command dispatcher and query dispatcher functionality. This question assumes using a DI connector isn’t an option. I will be doing pure DI. |
A Mediator solves LSP from the perspective of the handler's client, as the Mediator's contract promises that it can dispatch any given message.
Yes, you can obviously break stuff inside the Mediator implementation, but that's a bug; not something the consumer concerns. Besides, in languages that have a type system and allow reflection, this problem can be easily prevented. A Mediator can be created in a resilient way, so that chances of making errors when need handlers are added are slim.
This is not something I can answer. This is something you have to verify by applying the Interface Segregation Principle to your application and asking whether there will be clients that only use one of the two methods, but not both. If that's the case, you are violating ISP and it would typically be better to split them. If all clients use both methods, that warrents keeping the methods together. |
Steven, Thanks for your responses. I've tried to take a stab at building a mediator implementation. I ran into a few challenges though, because the programming language that I am using, Salesforce Apex, has very limited reflection capabilities. It isn't for instance able to dynamically identify the type or name of the class of a given object (without hacky workarounds). It also isn't able to dynamically call methods on a class, like your Query Dispatcher implementation does. There are also no DI containers available for this programming language that support constructor injection, so I am using pure DI. What are your thoughts on the below?
|
I'm unfamiliar with Salesforce Apex and its constraints. This means I'm unable to give you any feedback on your code. |
Thank you @dotnetjunkie and @KrishnaKollu for this great conversation. I have read and love the DI Patterns, Principles, and Practices book. I feel that if it had the word "Architecture" in the title it would be even more of a hit. I also want to apply CQS / AOP and have noticed most apply it using the Mediator pattern, either using MediatR project or using a QueryProcessor (this sample project), QueryExecutor, etc. Is there a reason to not consume query handlers directly? Why does this project use an IQueryProcessor but not an ICommandProcessor? Basically, I was thinking to inject From what I understand, MediatR has pipelines and such for cross-cutting concerns, so someone can register their decorators (pipelines) with MediatR and let it do its magic. I was planning on using SimpleInjector to decorate my query and command handlers for cross-cutting concerns, so I don't see the need of a Mediator. Thanks! |
Just realized @dotnetjunkie you talk about drawbacks of injecting I like how you mentioned start without a Mediator. If the only advantage of using a Mediator is avoiding constructor over-injection and code verbosity, I'll leave it out for now. Thanks again for getting us on the SOLID path, practically. |
Hello @dotnetjunkie ,
I'm trying to better understand the DynamicQueryProcessor.cs implementation and the
IQueryProcessor
interface. I get how it's helpful in reducing dependencies.However, I'm trying to make sense of it in light of DI principles mentioned in your book, and I'm hoping you can help me with this:
The execute method in
DynamicQueryProcessor
is going to a DI container. My understanding is that any time you go to a DI container outside of the Composition Root, the Service Locator Pattern is effectively used. It also seems to be that usage ofIQueryProcessor
has some of the drawbacks of a Service Locator i.e. hidden dependencies. This makes unit testing more challenging.Is this mediator effectively a Service Locator, or am I missing something here? What are your thoughts?
The text was updated successfully, but these errors were encountered: