From 14d819249bc222b4d39b5a39187ce117142015e2 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Fri, 20 Jan 2023 17:18:44 +0100 Subject: [PATCH] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Fredrik Adelöw Signed-off-by: Patrik Oldsberg --- .../architecture/05-extension-points.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/backend-system/architecture/05-extension-points.md b/docs/backend-system/architecture/05-extension-points.md index 63d5163063..f82fde3561 100644 --- a/docs/backend-system/architecture/05-extension-points.md +++ b/docs/backend-system/architecture/05-extension-points.md @@ -6,9 +6,9 @@ sidebar_label: Extension Points description: Extension points of backend plugins --- -While plugins are able to accept options for lightweight forms of customization and extension, you quickly hit a limit where you need something more powerful to allow users to extend your plugin. For this purpose, the backend system provides a mechanism for plugins to expose extension points, which can be used to expose deeper customizations for your plugin. Extensions points are used by modules, which are installed in the backend adjacent to plugins. Modules are covered more in-depth in the [next section](./06-modules.md). +While plugins are able to accept options for lightweight forms of customization and extension, you quickly hit a limit where you need something more powerful to allow users to extend your plugin. For this purpose, the backend system provides a mechanism for plugins to provide extension points, which can be used to expose deeper customizations for your plugin. Extension points are used by modules, which are installed in the backend adjacent to plugins. Modules are covered more in-depth in the [next section](./06-modules.md). -Extension points are quite similar to services, they both encapsulate an interface in a reference object. The key difference is that extension points are registered and provided by plugins themselves, and do not have any factory associated with them. Extension points for a given plugin are also only accessible to modules that extend that same plugin. +Extension points are quite similar to services, in that they both encapsulate an interface in a reference object. The key difference is that extension points are registered and provided by plugins themselves, and do not have any factory associated with them. Extension points for a given plugin are also only accessible to modules that extend that same plugin. Extension points should always be exported from a plugin node library package, for example `@backstage/plugin-catalog-node`. This is to allow for modules to avoid a direct dependency on the plugin, and make it easier to evolve extension points over time. You can export as many different extension points as you want, just be mindful of the complexity of the API surface. It is however often better to export multiple extension points with few methods, rather than few extension points with many methods, as that tends to be easier to maintain. @@ -31,7 +31,7 @@ export const scaffolderActionsExtensionPoint = ## Registering an Extension Point -For modules to be able to use your extension point, and implementation of it must be registered by the plugin. This is done using the `registerExtensionPoint` method in the `register` callback of the plugin definition. +For modules to be able to use your extension point, an implementation of it must be registered by the plugin. This is done using the `registerExtensionPoint` method in the `register` callback of the plugin definition. ```ts class ActionsExtension implements ScaffolderActionsExtensionPoint { @@ -63,15 +63,15 @@ export const scaffolderPlugin = createBackendPlugin( ); ``` -There are a couple of things to note here. The first is that our `ActionsExtension` class both implements the `ScaffolderActionsExtensionPoint` interface, but also has additional public methods. These methods won't be available to the modules that use this extension, but we can use them here in the implementation of our plugin. +There are a couple of things to note here. The first is that our `ActionsExtension` class both implements the `ScaffolderActionsExtensionPoint` interface, but also has additional public methods. These methods won't be available to the modules that use this extension, but we can use them here in the implementation of our plugin. Note also that the `ActionsExtension` class is _not_ exported to the outside, since it's only for the internal use of this plugin during its setup phase. The second is that we create our `ActionsExtension` instance within the `register` method, and then access it directly in our `init` method. This is both safe to do and an intended convenience. All modules that extend our plugin will be completely initialized before our plugin gets initialized, which means that at the point where our `init` method is called, all actions have been added and can be accessed. ## Extension Point Design -Designing the extension point interface can be quite challenging. It is a public API surface that your plugin will need to maintain over time. Keep in mind that the installation of modules is an intentional action by the user, meaning you can always design an extension point interface for additions only. For example, there is no need for the `scaffolderActionsExtensionPoint` to support removal of actions, since the user can just uninstall the module that added the action. +Designing the extension point interface requires careful consideration. It is a public API surface that your plugin will need to maintain over time. Keep in mind that the installation of modules is an intentional action by the user, meaning you can always design an extension point interface for additions only. For example, there is no need for the `scaffolderActionsExtensionPoint` to support removal of actions, since the user can just uninstall the module that added the action. -Another pattern that can be used is a type of singleton pattern where the extension point is used add or override some default behavior. For example, let's say the scaffolder wants to expose a way to customize the execution of template tasks. It wouldn't really make sense to allow multiple modules each add their own task runners, so instead we use a setter to ensure that only one task runner is installed, throwing an error if any other module tries to install another task runner. +Another pattern that can be used is a type of singleton pattern where the extension point is used to add or override some default behavior. For example, let's say the scaffolder wants to expose a way to customize the execution of template tasks. It wouldn't really make sense to allow multiple modules to each add their own task runners, so instead we use a setter to ensure that only one task runner is installed, throwing an error if any other module tries to install another task runner. ```ts interface ScaffolderTaskRunnerExtensionPoint {