Introduce new command DSL #1211
Open
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Below is a new, improved DSL that addresses #1127. You’ll find the usage of individual methods (all of them are listed) to make it easier to review everything clearly.
Important
Since command registration is the heart of Spring Shell, it's very important to carefully review the contracts of the introduced changes. Modifying this API in the future may be problematic, so we need to be sure that this structure is acceptable, as it may stay with us for a long time.
However, when I look at the resulting code — and the existing code in the codebase — I'm not entirely satisfied. The code feels quite clumsy. 😭
I have a few topics I'd like to bring up.
Is the naming of these objects good?
I see an analogy here to
BeanDefinitionandBeanDefinitionRegistry. Right now, we have the nameCommandRegistration. But what exactly is this mysteriousRegistration? I have the impression that it's not a good name. It’s not very descriptive and might be misleading.Maybe we should approach it similarly to the Spring Framework itself and have definitions and registries for commands?
In the definition, we could have a command object with all its metadata — such as names, aliases, and options.
Should we use interfaces?
I'm not sure what the benefit is of having
CommandRegistrationas an interface (and the rest of objects too). I don't really feel that this approach fits well.If we had multiple implementations (
1..n) of differentCommandRegistrations, then an interface might make sense. Here, it seems unnecessary.Another question, how should the objects that hold command definition information look?
Should we use the
Specobjects everywhere, or only during the build phase — where the result would be an object holder?For example:
OptionSpeccould create anOptionDefinitionobject (which could be a simple record).Aggressiveness of changes
I'm also not sure how far-reaching these changes should be. We're changing the baseline — but are the modifications I’ve introduced acceptable? Could we possibly discuss further, larger changes? Do we need to maintain backward compatibility?
Summary
Overall, this image perfectly captures how I feel when walking through the classes and trying to understand how commands are created.
Caution
Without good and clear manual command registration, it will be very difficult to build reliable automatic detection and registration later on.
I'd be happy 🙏 to continue driving this topic, but I need answers to the above questions so I don't go down a dead-end path — and to know how far I can go with the refactor.