Skip to content
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

Consolidate all Plugin.createComponents arguments into a single accessor class #101305

Merged
merged 3 commits into from
Oct 26, 2023

Conversation

thecoop
Copy link
Member

@thecoop thecoop commented Oct 25, 2023

Create a createComponents overload that only takes a single services argument, allowing new services to be added without breaking API compatibility as much.

Keep the old method for compatibility with existing plugins

@thecoop thecoop added :Core/Infra/Plugins Plugin API and infrastructure >refactoring labels Oct 25, 2023
@elasticsearchmachine elasticsearchmachine added Team:Core/Infra Meta label for core/infra team v8.12.0 labels Oct 25, 2023
@elasticsearchmachine
Copy link
Collaborator

Pinging @elastic/es-core-infra (Team:Core/Infra)

*/
@Deprecated
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can just be left around for compatibility, but any new services would be added to PluginServices only

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't need to do this, or at least we can remove this once serverless is updated. There are no compatibility guarantees for non-stable plugins.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll migrate all the existing implementations as a separate PR

indicesService
)
).toList();
Plugin.PluginServices services = new Plugin.PluginServices() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is OK but a bit verbose; maybe a builder would be nicer to use

Plugin.ComponentsBuilder b = p.createComponents();
var componetns = b
   .withClient(client)
   .withClusterService(clusterService)
   ...
   .build();

or

var components = p.createComponents(b -> b.withClient(client).withClusterService(clusterService)...)

Just suggesting alternatives, it's OK either way

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A builder is good when you're building something up in stages, but this is all-or-nothing - you need all these things to have a PluginServices object, it makes no sense without them. It'll also add a lot of boilerplate to the builder implementation & verification.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 but in terms of boilerplate-reduction why not just use a record? Do we really need an interface and an anonymous class to implement it?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I considered that...an interface gives us a bit more flexibility for the future, and this is a formal public class contract so should be done more 'properly'

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A record seems more suitable to me. What flexibility to you envision an interface gives? What makes it a better formal contract?

Copy link
Member Author

@thecoop thecoop Oct 25, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would say an interface is more usual in an API like this. It can be mocked out easily, and it allows flexibility for any future changes we may wish to add, such as, off the top of my head:

  • Adding code to track which services are accessed by which plugins
  • Exceptions can be thrown if a service is not available in a particular context
  • Dynamically loading services into particular class contexts only when they are accessed
  • Test implementations can add restrictions on how services are accessed, or check they are only accessed in certain threads
  • We could migrate to a more listener/registration based API using this interface as a base, maybe moving some of the existing methods/plugin interfaces into here in the future
  • We could split this interface up into different sub-interfaces for different types of plugins

There's a whole load of future modifications we could do by using an interface. A record doesn't allow these. And there's nothing additional a record gives us here that an interface doesn't.

Copy link
Member Author

@thecoop thecoop Oct 25, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've changed the implementing class to a record, so it's a bit more succinct in the definition, and not anonymous

Copy link
Member

@rjernst rjernst left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@thecoop thecoop merged commit 1fe9aa9 into elastic:main Oct 26, 2023
12 checks passed
@thecoop thecoop deleted the plugin-create-components branch October 26, 2023 08:13
tvernum added a commit to tvernum/elasticsearch that referenced this pull request Oct 31, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
:Core/Infra/Plugins Plugin API and infrastructure >refactoring Team:Core/Infra Meta label for core/infra team v8.12.0
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants