platform icon indicating copy to clipboard operation
platform copied to clipboard

Schematics: Improve schematics for more consistency and modern usage

Open brandonroberts opened this issue 2 years ago • 2 comments
trafficstars

Which @ngrx/* package(s) are relevant/related to the feature request?

schematics

Information

Our schematics are generally supposed to reflect the most recent patterns used in NgRx, but they have drifted along the way. This effort would improve the schematics for consistency and update them to modern NgRx patterns.

Such as

  • createActionGroup
  • createFeature with extraSelectors
  • Updating entity selectors to accept a singular input (user) instead of plural (users) so they generated code doesn't become loadUserss
  • Other improvements as needed

Describe any alternatives/workarounds you're currently using

No response

I would be willing to submit a PR to fix this issue

  • [ ] Yes
  • [ ] No

brandonroberts avatar Aug 24 '23 12:08 brandonroberts

@tomastrajan has some suggestions to recommend here also.

brandonroberts avatar Aug 24 '23 12:08 brandonroberts

Preface

The Angular schematics (and NX generators as they can re-use them) are really great way to streamline development in large envs with many devs and teams, therefore we should pay extra attention to consistency of the generated code.

In general we want to achieve a state when generated code has predictable repeatable structure, naming which promotes using of best practices and is easy to compose (re-using selectors from other state features) and refactor (easy to extract part of the state feature to other state feature, for example when extracting part of state from lazy feature to new core state feature to be reused by multiple lazy features.

Without consistent base schematics provided by the library, people often reimplement them on per project basis (or extract in private library) to provide consistent experience in their environments.

eg https://github.com/angular-experts-io/nx-plugin/tree/main/libs/tooling/nx-plugin/generators/src/generators/lib/files/state/lib

Variables, files, APIs

  • consistent existence (eg their either always exist or never, not ad hoc based on provided flag when running schematics)
  • consistent naming (and pluralization)
  • consistent location (order of appearance)

Example

NgRx feature without (and with --entity flag)

Without

ng g @ngrx/schematics:feature features/example-basic/example

// previous code omitted for brevity
export const exampleFeature = createFeature({
  name: exampleFeatureKey,
  reducer,
});
  • example.selectors.ts will exist

With

ng g @ngrx/schematics:feature features/example-entity/example --entity

// previous code omitted for brevity
export const examplesFeature = createFeature({
  name: examplesFeatureKey, // <-- hardocded pluralization (probably makes sense because of entity collection but still
  reducer,
  extraSelectors: ({ selectExamplesState }) => ({
    ...adapter.getSelectors(selectExamplesState)
  }),
});

export const {
  selectIds,
  selectEntities,
  selectAll,
  selectTotal,
} = examplesFeature;
  • example.selectors.ts doesn't exists

Proposal

Come up with an ideal reducer (or maybe even <name>.feature.ts ), action (or maybe even <name>.events.ts ), ... file structure and once consensus was achieved, implement it as an updated consistent version of NgRx schematics.

Ideas

  • why preserving examplesFeatureKey if we could instead do createFeature({ name: 'actual-name' }) as currently the features can be registered directly with provideState(examplesFeature) (and StoreModule.forFeature(examplesFeature)

  • come up with a consistent easy to compose way to define selectors, eg always (or never) create <name>.selectors.ts file, so that when composing state, it is consistently recommended to use either feature (with extra selectors) or standalone selectors in dedicated file, but what was generated should be consistent

  • when using --entity flag, the generated reducer follows "command pattern" eg (add, update , ...) while consuming actions group created with createActionsGroup API which defines a object of events so it would be great if the generated code followed events naming instead, eg ExampleActions(or even ExampleEvents).loadExamplesSuccess (or examplesLoadedSuccess)

I hope this proposal can start some conversation and bring together various time tested best practices of folks who figured them out over time in their codebases so that we can provide great out of the box experience for anybody starting with NgRx and make it attractive to build on top of base NgRx schematics instead of from scratch when creating a custom solution for some specific environment!

tomastrajan avatar Aug 27 '23 10:08 tomastrajan