-
Notifications
You must be signed in to change notification settings - Fork 8.3k
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
[expressions] changes fork to use namespacing #125957
Conversation
d601f56
to
403411d
Compare
403411d
to
3b22d31
Compare
@elasticmachine merge upstream |
@elasticmachine merge upstream |
* Returns Kibana Platform *setup* life-cycle contract. Useful to return the | ||
* same contract on server-side and browser-side. | ||
*/ | ||
public setup(): ExpressionsServiceSetup { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using a decorator pattern here is a great idea. What do you think about breaking down the methods to make the class more straightforward?
I see the following points for this:
- If we make methods protected, we will be able to extend this class in the future if we have to diverge server or public implementation.
- Placing logic in separate methods should simplify readability and testability since we can test every method independently.
- In general, it's a good practice to make methods as straightforward as possible and have only one single responsibility. The
setup
andstart
are factory methods, so it's better to keep them only producing new instances.
export class ExpressionsServiceFork implements ExpressionServiceFork {
constructor(private namespace: string, private expressions: ExpressionsService) {
this.registerFunction = this.registerFunction.bind(this);
}
setup(): ExpressionsServiceSetup {
return {
...this.expressionsService,
registerFunction: this.registerFunction,
// ...
};
}
protected registerFunction(definition: /* ... */) {
if (typeof definition === 'function') {
definition = definition();
}
return this.expressionsService.registerFunction({
...definition,
namespace: this.namespace,
});
}
}
Some notes regarding the example above:
- We should define protected methods as methods and not as properties so they will end up in the prototype. In this case, we will be able to use
super
in the extended class. - We should bind methods in the constructor to prevent producing new boundaries on every start/setup call.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- I don't think this will be extended internally and it shouldn't be extended externally.
- we don't want to make the methods visible on the ExpressionServiceFork class, if we make them protected how can we test this from the outside then ?
- for me personally in this specific case readability is better as it is now, makes it obvious that the fork is just a wrapper around ExpressionsService and we don't need to do the binding
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this will be extended internally and it shouldn't be extended externally.
Well, we cannot predict that. That's not about the extension necessity but more about abstraction. Those methods seem to be like internal API and not an implementation detail. Even though we export only start
and setup
, they define the forked service.
we don't want to make the methods visible on the ExpressionServiceFork class, if we make them protected how can we test this from the outside then ?
That's possible to call them through an extended anonymous class. But in cases like that, we can just put related tests under the describe('method')
block since it is not a private method.
for me personally in this specific case readability is better as it is now, makes it obvious that the fork is just a wrapper around ExpressionsService and we don't need to do the binding
I think it's better if we can extract those into methods. It should not make it less straightforward, but it will be more consistent with the ExpressionsService
. The latter makes sense because we are actually forking that service.
If we do that, it will make the decorator pattern more visible so that it still should be clear that the class is a wrapper.
src/plugins/expressions/common/expression_functions/expression_function.ts
Show resolved
Hide resolved
Co-authored-by: Michael Dokolin <dokmic@gmail.com>
Co-authored-by: Michael Dokolin <dokmic@gmail.com>
@elasticmachine merge upstream |
7a20f50
to
aa1fa35
Compare
@elasticmachine merge upstream |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great job! LGTM 👍
💚 Build SucceededMetrics [docs]Module Count
Public APIs missing comments
Async chunks
Public APIs missing exports
Page load bundle
History
To update your PR or re-run it, just comment with: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Presentation changes LGTM 👍
Friendly reminder: Looks like this PR hasn’t been backported yet. |
Friendly reminder: Looks like this PR hasn’t been backported yet. |
Summary
resolves #113379, #126472
Expressions.fork was updated to do namespacing internally. APIs stay the same. As part of the process getFunctions() had to be cleaned up and should now perform better.
Checklist
Delete any items that are not applicable to this PR.
For maintainers