boostercloud / booster

Booster Framework
https://www.boosterframework.com
Apache License 2.0
409 stars 83 forks source link

Avoid redundant code on Entity reducers with a new `update` method that eases the interface for partial updates #1494

Open javiertoledo opened 8 months ago

javiertoledo commented 8 months ago

Description:

Summary:

This proposal aims to refine the entity updating mechanism in the Booster framework by introducing a method that simplifies updating entities, particularly when dealing with constructors that require numerous parameters.

Specific Challenge:

Currently, when updating entities in response to different events, developers often need to call entity constructors with a long list of parameters, even if only a single field needs to be updated. This results in redundant code where the same parameters are passed repeatedly in different reducers.

Proposed Solution:

We propose the introduction of an update method as part of the @Entity decorator functionality. This method would take a partial object of the entity (an object containing one or more fields from the entity) and the existing instance of the entity. The method would then create a new instance of the entity, copying all fields from the existing instance except those overridden by the partial, providing a more straightforward interface for returning new entity instances.

Implementation Options:

  1. Mandatory Custom Implementation: Users manually implement their update method, allowing for tailored behavior specific to their entities.
  2. Generic Static Method: The Booster framework provides a generic static update method, which can be imported and used in entities for standard cases.
  3. Both! Why have one method when you can have two for the price of two??

Example:

Current Approach:

@Reduces(SomeEvent)
public static handleSomeEvent(event: SomeEvent, current?: MyEntity): MyEntity {
  return new MyEntity(
    current.id,
    current.name,
    current.description,
    ...,
    'newStateForSomeEvent', // Only this field changes
    ...
  );
}

@Reduces(AnotherEvent)
public static handleAnotherEvent(event: AnotherEvent, current?: MyEntity): MyEntity {
  return new MyEntity(
    current.id,
    current.name,
    current.description,
    ...,
    'newStateForAnotherEvent', // Only this field changes
    ...
  );
}

Proposed Approach:

@Reduces(SomeEvent)
public static handleSomeEvent(event: SomeEvent, current?: MyEntity): MyEntity {
  return Reducer.update({ state: 'newStateForSomeEvent' }, current);
}

@Reduces(AnotherEvent)
public static handleAnotherEvent(event: AnotherEvent, current?: MyEntity): MyEntity {
  return Reducer.update({ state: 'newStateForAnotherEvent' }, current);
}

Benefits: