What is the code interpretation of SAP Spartacus UI

Time:2021-12-8

For complex and rapidly evolving libraries, it can be challenging to improve existing functionality while maintaining backward compatibility. Code deprecation allows you to properly mark obsolete code and help users transition to better alternatives by warning them.

To mark a function, class, method, or property as deprecated, use the @ deprecated tag. Here is an example:

/**
* @deprecated since 1.0.2
* Use better alternative instead
*/

According to the actual deprecation policy, such code will become a candidate for deletion in one of the next major releases.

Marking Deprecated Logic

Generally, in order to adapt to backward compatibility, some indirectly related code needs to contain additional logic. When the related deprecated functions are deleted, these logic should be deleted. When it is unclear what additional logic should be removed, the best way to ensure that obsolete code is removed is to mark it with the correct todo comments, preferably linked to the GitHub issue with additional details. These tickets should be properly marked (for example, a label with deprecated-1. X) so that they can be more easily referenced as candidates for deletion in the future.

The following is an example of a todo comment:

// TODO(issue:3313) Deprecated since 1.1.1

Feature Flags

Each new minor release releases new features. Sometimes, new functionality is added to existing components that customers can already use, which makes these changes destructive because they are added to the DOM or because of different behavior. Spartacus uses the function flag in order to avoid damaging the customer’s code and flexibly improve the functions of existing components without releasing new major versions too frequently.

The function flag allows us to do the following:

  • The functions are distinguished according to the function level, corresponding to the small version number
  • Distinguishing features based on explicit feature markers

Note: explicit feature flags can be linked to a feature level, which means that they are enabled by default for that particular level.

Deciding If You Need a Feature Flag

If not, it is best to avoid creating new feature flags. This helps keep our configuration clean and makes final maintenance easier.

The following guidelines can help you decide which feature flags, if any, to use:

(1) If possible, try to avoid using function signs.

Instead, implement your functionality as a separate module that customers can choose to import.

(2) If your feature already has a separate configuration, please determine which of the following is more convenient:

a. Create a new option in the module configuration (making them switchable has practical value for general functions).
b. Use function flags (especially when the only reason for flags is backward compatibility).

If possible, try to avoid creating clear function signs. Instead, try to enable features at a specific feature level, such as minor versions.
If you want to create an explicit feature flag, make sure that the reason for doing so is reasonable (for example, the feature is very important and can be explicitly disabled or enabled).

Detecting the Feature Level

If your service or component has been injected with global configuration, you can use a simple utility function to check the functional level, as shown in the following example:

if (isFeatureLevel(this.config, '1.1')) {
  // code that is meant to be executed for feature level 1.1 and above
}

If your component or service does not have access to the global configuration, you can inject featureconfigservice and use it, as shown in the following example:

 constructor(
    // ...
    protected featureConfig: FeatureConfigService
  ) {}

  // set a feature flag based on the feature level
  readonly isSomeNewFeatureEnabled = this.featureConfig.isLevel('1.1');

If you want to conditionally display components in the template, you can use the cxfeaturelevel command, as shown in the following example:

<newComponent *cxFeatureLevel="'1.1'"></newComponent>

You can introduce explicit flags without additional configuration, but it is recommended that you include them in the type definition of the store configuration to expose them to customers. To do this, add your flag as a new attribute of boolean type to the featuretoggles interface in the feature-toggles.ts file. Here is an example:

export interface FeatureToggles {
  features?: {
    // ...

    /**
     * Sample feature description
     */
    consignmentTracking: boolean;
  };
}

In this way, you can also add a description to the flag and even a deprecation comment if necessary.

Linking the Feature Flag to the Feature Level

By linking your feature flag to a feature level, your flag is enabled by default for that feature level and all higher levels. To do this, provide the default value of the feature flag as a string representing the feature level. You can add this configuration to your module configuration, as shown in the following example:

ConfigModule.withConfig({
  // ...
  features: {
    consignmentTracking: '1.1',
  },
})

In this example, if the function level is set to at least “1.1”, the consignment tracking function is enabled by default.

Disabling a Feature for a Specific Feature Level

You can disable the function of a specific function level by including an exclamation point! Before version number. Here is an example:

<newComponent *cxFeatureLevel="'!1.1'"></newComponent>