Upgrade to PRO for Only $50/Year—Limited-Time Offer! 🔥

Angular at Scale | Web Developer Chemnitz

Angular at Scale | Web Developer Chemnitz

Gregor Woiwode

November 28, 2019
Tweet

More Decks by Gregor Woiwode

Other Decks in Programming

Transcript

  1. @GregOnNet Topics Common Pitfalls Why, How & What of State

    Management Redux Architecture NgRx platform
  2. function iDoToMuch(input: any) { if (input.hasPropertyA) { !/* !!... !*/

    if (input.hasAlsoPropertyA2) { !/* !!... !*/ } else if (input.hasAlsoPropertyA3) { input.propertyList.map(property !=> { !/* !!... !*/ }); } } if (input.hasPropertyB) { !/* !!... !*/ } input = updateInput(input); return input.fullFillsCondition ? changeInputTheOneWay(input) : changeInputTheOtherWay(input); } Nested Code Blocks Cyclometic Complexity of 10 Tests??? Complexity @GregOnNet
  3. Modal Wrapper Monoliths Modal Stepper Questionnaire Button Group No clear

    API Deeply nested Components Hard for others to understand Hard to maintain @GregOnNet
  4. Monoliths Reduce Component Nesting Think in APIs Put a smile

    on your colleagues’ face @GregOnNet
  5. Learnings Applying valuable patterns is hard. It is nearly impossible

    to know the whole Project you are working on. It is often ignored that requirements change over time. @GregOnNet
  6. @GregOnNet interface Action { type: string } Action type needs

    to be unique Represents an interaction with UI or Data Takes an optional payload or metadata
  7. Impure function @GregOnNet function iAmImpurePure(): string { const input =

    document.querySelector('input'); return `${input.value}1`; }
  8. Store @GregOnNet Reducer B Reducer A Reducer C const state

    = { featureA: { !/* !!... !*/ }, featureB: { !/* !!... !*/ }, featureC: { !/* !!... !*/ } } Store is an In-Memory data structure
  9. @GregOnNet @NgModule({ imports: [ StoreModule.forRoot(reducers, { runtimeChecks: { } })

    !/* !!... !*/ }) export class AppModule { } StoreModule
  10. @GregOnNet StoreModule @NgModule({ imports: [ StoreModule.forRoot(reducers, { runtimeChecks: { strictActionImmutability:

    true, strictActionSerializability: true, strictStateImmutability: true, strictStateSerializability: true } }) !/* !!... !*/ }) export class AppModule { }
  11. @GregOnNet StoreModule - reducers export const reducers: ActionReducerMap<State> = {

    counter: counterReducer, logger: loggerReducer } Reducers get combined feature name
  12. @GregOnNet createAction export const increment = createAction( '[Counter] Increment by

    one' ); !// createAction(); !// !// { !// type: '[Counter] Increment by one' !// }
  13. @GregOnNet createAction & payload export const add = createAction( '[Counter]

    Add value', props<{ payload: { value: number } }>() ); !// createAction({ payload: { value: 1 } }) !// !// { !// type:'[Counter] Add value', !// payload: { value: 1} !// }
  14. @GregOnNet Read from the store export class SimpleCounterComponent { count$:

    Observable<number>; constructor(private store: Store<State>) { this.count$ = this.store.pipe( select(state !=> state.counter.count) ); } }
  15. Redux - Side effects @GregOnNet @Injectable() export class CounterEffects {

    randomAdd = createEffect(() !=> this.actions.pipe( ofType(randomAdd) )); constructor(private actions: Actions) { } }
  16. Redux - Side effects @GregOnNet @Injectable() export class CounterEffects {

    randomAdd = createEffect(() !=> this.actions.pipe( ofType(randomAdd), switchMap((action !=> !/* e.g. call API !*/) )); constructor(private actions: Actions) { } }
  17. Redux - Side effects @GregOnNet @Injectable() export class CounterEffects {

    randomAdd = createEffect(() !=> this.actions.pipe( ofType(randomAdd), switchMap((action !=> !/* e.g. call API !*/), map((result !=> randomAddSuccess(result)) )); constructor(private actions: Actions) { } }
  18. Redux - Side effects @GregOnNet @Injectable() export class CounterEffects {

    randomAdd = createEffect(() !=> this.actions.pipe( ofType(randomAdd), switchMap((action !=> !/* e.g. call API !*/), ), { dispatch: true|false }); constructor(private actions: Actions) { } }
  19. Redux - Side effects @GregOnNet @Injectable() export class CounterEffects {

    randomAdd = createEffect(() !=> this.actions.pipe( ofType(randomAdd), switchMap((action !=> !/* call API !*/), map((result !=> randomAddSuccess(result)) ), { resubscribeOnError: true|false }); constructor(private actions: Actions) { } }
  20. Selectors @GregOnNet export const count = createSelector(featureCounter, s !=> s.count);

    Project data const featureCounter = createFeatureSelector<CounterState>('counter');
  21. Selectors @GregOnNet Combine selectors aggregating data export const infoWithCurrentCount =

    createSelector( infoMessage, count, (messages, total) !=> messages.map(message !=> `${message} (Total: ${total})` ) );
  22. What we have covered… Redux Architecture Actions & Reducers StoreDevtools

    Effects Selectors @ngrx/entity @ngrx/router-store @ngrx/data
  23. Closing thoughts On-Board your team patiently. Modeling application state has

    lots of overlaps
 with Requirements Engineering. Redux makes your App more predictive.