-
Notifications
You must be signed in to change notification settings - Fork 88
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
Cascading Locator #55
Comments
Hi @rizqidjamaluddin! The idea of a Composite or Chain locator has come up a few times already, so it's safe to say there's interest. I think the big question is should we add a If you're interested in doing the If we did add this, it doesn't have any deps so I agree with just shipping it in the core package as a regular ol' HandlerLocator, no Plugins namespace necessary. |
If you're not interested in doing the refactoring, btw, I can pick it up myself then swing back around to this but it'll be a couple of weeks probably. |
I think this needs a valid use case but I can't think of one. Not saying it's a bad idea, but my gut says that we don't need more than one |
@rosstuck - I think the exceptions-as-flow control is indeed the big question. One potential issue with using a try-catch I see is that a custom locator might be throwing a more advanced @rtuin - for me, I write large modular apps, often with legacy components or with modules being migrated over from another command bus. Sometimes certain parts of the application will have a different command-handler mapping scheme than others that isn't easily refactored (or refactoring on the spot isn't an option). Usually this means having the ability to explicitly set a handler with For that matter, would it make more sense to have the CascadingLocator allow more locators to be added in runtime? One could have a single global instance and then packages would implement their own locators for their classes. |
@rtuin I've heard of at least two other Tactician users doing something similar so there's apparently a demand for it. Both were in brownfield contexts, if you're in a pure greenfield situation it might be less common indeed. Regarding the @rizqidjamaluddin I'm okay with a minor BC break here, we're still pre-1.0 and can update the Symfony, Silex and League containers without much hassle so most users probably won't notice. The interface change is mainly additive. I do wonder about changing how the CommandNameExtractors work: right now we pass them directly to the CommandHandlerMiddleware but perhaps it's better to make them constructor dependencies for most HandlerLocators because I imagine the string produced by the CommandNameExtractor is likely quite unique to the HandlerLocator backend. That may not be an issue admittedly, it's just a thought. If you can give it a mental test against your scenarios and let me know what you think, I'd much appreciate it. |
I actually only just saw the Extractor classes. I don't think they're very relevant for me, but that's probably because I've always used FQCNs for command identities. I could see people running into the same issue as I'm having with Locators, though - different bits of code identifying commands in different ways. I think we need more information to decide on that. |
Indeed, I can see it as a real issue. Also, for folks who want a really hardcoded solution unique for them, they can skip the CommandNameExtractor part (if they choose) and go straight from Command->Handler in their mapping. Going to ping @sagikazarmark because he did all of the hard work on CommandNameExtractors, curious what he thinks. :) |
At the end of the day, I think the real goal is to allow a single command bus to serve a variety of commands/handlers and the relationships between them - e.g. a person who used laravel's self-handling commands wants to keep their old setup while moving to separated commands/handlers in the long run. Maybe we're approaching it inefficiently by looking at individual locators and extractors, when what we really want is a composite command handler? |
Let me correct one thing first:
This is false, it has been removed as it was a direct child of Bernard`s message interface. Actually, this is a great example why Commaind interface gone was a good decision. Regarding the catch/hasHandler issue: Both have pros and cons. Using try-catch blocks for something we expect is ugly. Also adds a small amount of overhead. hasHandler seems to be a better choice, although in some cases where handlers are not resolved from a static, but a dynamic map it might also add some unwanted behavior. Also adding something to the interface for the sake of one handler doesn't seem to be a good idea to me. As a solution we could add a ChainableHandler interface which contains this method. The core locators could implement this interface, but this way implementing it for custom ones is not necessary. As for the extraction thing: I think that is the hardest question of all. I agree that in some cases the extraction logic does not add any value (custom locators, etc). But I have two issues making some locators accepting a name extractor:
So I agree name extraction logic could be a dependency of locators, but I don't have an idea how it could be nicely done. |
Here is what I have come up with regarding name extraction:
(Following this way command name extraction can even go into a plugin) |
As an alternative, I've created an ugly POC about how we could pull this off, feedback is welcome: e8540a3 The POC adds cascading locators naturally, as well as a self-executing command setup as part of core. It also lets users just knock out their own hard-coded execution strategies if they want or reuse our bits through composition. A few points:
All in all, I'm not sure about this one, folks: it adds the missing features but we get an even more complicated setup phase. Not sure it's worth the tradeoffs here. :-/ Thoughts? |
Sorry, what? 😃 I am feeling this is the scenario of "Bringing a gun to a knife-fight". |
I think this is the only really "clean" way of implementing it. We can go a step further and remove the CommandHandlerMiddleware, making the execution strategy the final step of the callable chain always. That would make it a little more direct. We could also refactor to bring this stuff closer to the command bus, splitting MiddlewareChain out to its own object so the CommandBus can implement this stuff more freely. Either way, it seems like we just can't do this easily with the current Tactician setup so we may need to pass on this feature or implement the Exception based version. |
Actually, we are talking about two features, aren't we?
IMO rather the exception based thing than following such a "clean" way. |
If we don't move Extractors, I fear chained locators will be greatly handicapped since odds are two different containers won't use the same naming convention. @rizqidjamaluddin I'm open to taking the Exception based version, albeit with some design regrets. We'll just have to think harder about this scenario come Tactician 2.0, sorry. :) |
Why the release if we just wanted to move the extractors out of the handler middleware? Also, what do you think about the interface idea i mentioned earlier? |
Going to close this one now, will review all the 2.0 tagged stuff probably sometime next year. Thanks again to everyone for contributing to this thread with their ideas. 😻 |
Would there be interest in a locator that iteratively attempts to use a stack of other locators, continuing to the next when the first one fails? I've been using this a lot lately, generally to have the option of assigning explicit locators when necessary and a sensible default otherwise. Example snippet:
And thus usage would be wrapped:
A proper PR would, naturally, need tests, hence this just being an Issue for now. It's really just a utility class, so I'm not sure if it deserves its own separate repository.
The text was updated successfully, but these errors were encountered: