Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Quantum Facades: Why NgRx Facades are terrible or awesome depending on how you observe them (AngularConnect 2019)

Sam Julien
September 20, 2019

Quantum Facades: Why NgRx Facades are terrible or awesome depending on how you observe them (AngularConnect 2019)

NgRx facades are terrible! No wait, they're the best thing ever! What the heck is a facade, anyway? You may have heard recently about a topic whizzing around the Angular community: facades in NgRx. But are facades good or bad? Much like the age-old controversy of whether light is a particle or a wave, the answer depends on how you look at them. In this talk, you'll learn what facades are, why you should embrace them, why you should never, ever use them, and how to implement one without making Mike Ryan wake up in a cold sweat somewhere in Alabama.

Sam Julien

September 20, 2019
Tweet

More Decks by Sam Julien

Other Decks in Technology

Transcript

  1. Sam Julien @samjulien Developer Advocate Engineer at Auth0 GDE &

    Angular Collaborator UpgradingAngularJS.com @samjulien
  2. Sam Julien @samjulien Developer Advocate Engineer at Auth0 GDE &

    Angular Collaborator UpgradingAngularJS.com @samjulien Author at Thinkster.io
  3. @samjulien class Client { doSomething() { this.serviceA.getStuff(); this.serviceB.getStuff(); this.serviceD.getMore(); }⠀

    }⠀ class OtherClient { doSomething() { this.serviceA.getStuff(); this.serviceB.getStuff(); this.serviceD.getMore(); }⠀ }⠀
  4. @samjulien class Client { doSomething() { this.serviceA.getStuff(); this.serviceB.getStuff(); this.serviceD.getMore(); }⠀

    }⠀ class OtherClient { doSomething() { this.serviceA.getStuff(); this.serviceB.getStuff(); this.serviceD.getMore(); }⠀ }⠀
  5. @samjulien class Client { doSomething() { this.serviceA.getStuff(); this.serviceB.getStuff(); this.serviceE.update(); }

    } class OtherClient { doSomething() { this.serviceA.getStuff(); this.serviceB.getStuff(); this.serviceD.getMore(); } }
  6. @samjulien class Client { doSomething() { this.serviceA.getStuff(); this.serviceB.getStuff(); this.serviceE.update(); }

    } class OtherClient { doSomething() { this.serviceA.getStuff(); this.serviceB.getStuff(); this.serviceE.update(); } }
  7. @samjulien class Client { doSomething() { this.serviceA.getStuff(); this.serviceB.getStuff(); this.serviceE.update(); }⠀

    }⠀ class OtherClient { doSomething() { this.serviceA.getStuff(); this.serviceB.getStuff(); this.serviceE.update(); }⠀ }⠀
  8. @samjulien class Client { doSomething() { this.serviceA.getStuff(); this.serviceB.getStuff(); this.serviceE.update(); }⠀

    }⠀ class OtherClient { doSomething() { this.serviceA.getStuff(); this.serviceB.getStuff(); this.serviceE.update(); }⠀ }⠀ class OtherOtherClient { doSomething() { this.serviceA.getStuff(); this.serviceB.getStuff(); this.serviceE.update(); }⠀ }⠀
  9. @samjulien class Client { doSomething() { this.facade.getEverything(); }⠀ }⠀ class

    OtherClient { doSomething() { this.facade.getEverything(); }⠀ }⠀
  10. @samjulien [Magnets] Cool Magnets [Beam One] Start Beam One [Collider]

    Find Higgs Boson?? [Beam Two] Start Beam Two
  11. @samjulien [Magnets] Cool Magnets [Beam One] Start Beam One [Collider]

    Find Higgs Boson?? [Beam Two] Start Beam Two
  12. @samjulien @Component({...}) export class BeamOneComponent { beamOneStatus$: Observable<BeamStatus>; constructor(private store:

    Store<State>) { this.beamOneStatus$ = this.store.select(selectBeamOneStatus); } turnOn() { this.store.dispatch(BeamOneActionTypes.startBeamOne); } }
  13. @samjulien @Component({...}) export class BeamOneComponent { beamOneStatus$: Observable<BeamStatus>; constructor(private store:

    Store<State>) { this.beamOneStatus$ = this.store.select(selectBeamOneStatus); } turnOn() { this.store.dispatch(BeamOneActionTypes.startBeamOne); } }
  14. @samjulien @Component({...}) export class BeamOneComponent { beamOneStatus$: Observable<BeamStatus>; constructor(private store:

    Store<State>) { this.beamOneStatus$ = this.store.select(selectBeamOneStatus); } turnOn() { this.store.dispatch(BeamOneActionTypes.startBeamOne); } }
  15. @samjulien @Component({...}) export class BeamOneComponent { beamOneStatus$: Observable<BeamStatus>; constructor(private store:

    Store<State>) { this.beamOneStatus$ = this.store.select(selectBeamOneStatus); } turnOn() { this.store.dispatch(BeamOneActionTypes.startBeamOne); } }
  16. @samjulien @Component({...}) export class BeamOneComponent { beamOneStatus$: Observable<BeamStatus>; constructor(private store:

    Store<State>) { this.beamOneStatus$ = this.store.select(selectBeamOneStatus); } turnOn() { this.store.dispatch(BeamOneActionTypes.startBeamOne); } }
  17. @samjulien @Component({...}) export class BeamOneComponent { beamOneStatus$: Observable<BeamStatus>; constructor(private store:

    Store<State>) { this.beamOneStatus$ = this.store.select(selectBeamOneStatus); } turnOn() { this.store.dispatch(BeamOneActionTypes.startBeamOne); } }
  18. @samjulien @Component({...}) export class BeamOneComponent { beamOneStatus$: Observable<BeamStatus>; constructor(private store:

    Store<State>) { this.beamOneStatus$ = this.store.select(selectBeamOneStatus); } turnOn() { this.store.dispatch(BeamOneActionTypes.startBeamOne); } }
  19. @samjulien @Component({...}) export class BeamOneComponent { beamOneStatus$: Observable<BeamStatus>; constructor(private store:

    Store<State>) { this.beamOneStatus$ = this.store.select(selectBeamOneStatus); } turnOn() { this.store.dispatch(BeamOneActionTypes.startBeamOne); } } ☹
  20. @samjulien @Component({...}) export class BeamOneComponent { beamOneStatus$: Observable<BeamStatus>; constructor(private store:

    Store<State>) { this.beamOneStatus$ = this.store.select(selectBeamOneStatus); } turnOn() { this.store.dispatch(BeamOneActionTypes.startBeamOne); } }
  21. @samjulien @Injectable({...}) export class BeamOneFacade { beamOneStatus$: Observable<BeamStatus>; constructor(private store:

    Store<State>) { this.beamOneStatus$ = this.store.select(selectBeamOneStatus); } turnOn() { this.store.dispatch(BeamOneActionTypes.startBeamOne); } }
  22. @samjulien @Injectable({...}) export class BeamOneFacade { beamOneStatus$: Observable<BeamStatus>; constructor(private store:

    Store<State>) { this.beamOneStatus$ = this.store.select(selectBeamOneStatus); } turnOn() { this.store.dispatch(BeamOneActionTypes.startBeamOne); } }
  23. @samjulien @Injectable({...}) export class BeamOneFacade { beamOneStatus$: Observable<BeamStatus>; constructor(private store:

    Store<State>) { this.beamOneStatus$ = this.store.select(selectBeamOneStatus); } turnOn() { this.store.dispatch(BeamOneActionTypes.startBeamOne); } }
  24. @samjulien @Injectable({...}) export class BeamOneFacade { beamOneStatus$: Observable<BeamStatus>; constructor(private store:

    Store<State>) { this.beamOneStatus$ = this.store.select(selectBeamOneStatus); } turnOn() { this.store.dispatch(BeamOneActionTypes.startBeamOne); } }
  25. @samjulien @Injectable({...}) export class BeamOneFacade { beamOneStatus$: Observable<BeamStatus>; constructor(private store:

    Store<State>) { this.beamOneStatus$ = this.store.select(selectBeamOneStatus); } turnOn() { this.store.dispatch(BeamOneActionTypes.startBeamOne); } }
  26. @samjulien @Component({...}) export class BeamOneComponent { beamOneStatus$: Observable<BeamStatus>; constructor(private facade:

    BeamOneFacade) { this.beamOneStatus$ = this.facade.beamOneStatus$; } turnOn() { this.facade.turnOn(); } }
  27. @samjulien @Component({...}) export class BeamOneComponent { beamOneStatus$: Observable<BeamStatus>; constructor(private facade:

    BeamOneFacade) { this.beamOneStatus$ = this.facade.beamOneStatus$; } turnOn() { this.facade.turnOn(); } }
  28. @samjulien @Component({...}) export class BeamOneComponent { beamOneStatus$: Observable<BeamStatus>; constructor(private facade:

    BeamOneFacade) { this.beamOneStatus$ = this.facade.beamOneStatus$; } turnOn() { this.facade.turnOn(); } }
  29. @samjulien @Component({...}) export class BeamOneComponent { beamOneStatus$: Observable<BeamStatus>; constructor(private facade:

    BeamOneFacade) { this.beamOneStatus$ = this.facade.beamOneStatus$; } turnOn() { this.facade.turnOn(); } }
  30. @samjulien @Injectable({...}) export class BeamOneFacade { beamOneStatus$: Observable<BeamStatus>; constructor(private store:

    Store<State>) { this.beamOneStatus$ = this.store.select(selectBeamOneStatus); } turnOn() { this.store.dispatch(BeamOneActionTypes.startBeamOne); } }
  31. @samjulien @Injectable({...}) export class BeamOneFacade { beamOneStatus$: Observable<BeamStatus>; constructor(private store:

    Store<State>) { this.beamOneStatus$ = this.store.select(selectBeamOneStatus); } turnOn() { this.store.dispatch(BeamOneActionTypes.startBeamOneAndMagnet); } }
  32. @samjulien class Client { doSomething() { this.facade.getEverything(); }⠀ }⠀ class

    OtherClient { doSomething() { this.facade.getEverything(); }⠀ }⠀
  33. @samjulien [Magnets] Cool Magnets [Beam One] Start Beam One [Collider]

    Find Higgs Boson?? [Beam Two] Start Beam Two
  34. @samjulien [Magnets] Cool Magnets [Beam One] Start Beam One [Collider]

    Find Higgs Boson?? [Beam Two] Start Beam Two
  35. @samjulien [Magnets] Cool Magnets [Beam One] Start Beam One [Collider]

    Find Higgs Boson?? [Beam Two] Start Beam Two
  36. @samjulien @Component({...}) export class ColliderComponent { beamOneStatus$: Observable<BeamStatus>; beamTwoStatus$: Observable<BeamStatus>;

    constructor( private beamOneFacade: BeamOneFacade, private beamTwoFacade: BeamTwoFacade ) { this.beamOneStatus$ = this.beamOneFacade.beamOneStatus$; this.beamTwoStatus$ = this.beamTwoFacade.beamTwoStatus$; } }
  37. @samjulien @Component({...}) export class ColliderComponent { beamOneStatus$: Observable<BeamStatus>; beamTwoStatus$: Observable<BeamStatus>;

    constructor( private beamOneFacade: BeamOneFacade, private beamTwoFacade: BeamTwoFacade ) { this.beamOneStatus$ = this.beamOneFacade.beamOneStatus$; this.beamTwoStatus$ = this.beamTwoFacade.beamTwoStatus$; } }
  38. @samjulien @Component({...}) export class ColliderComponent { beamOneStatus$: Observable<BeamStatus>; beamTwoStatus$: Observable<BeamStatus>;

    constructor( private beamOneFacade: BeamOneFacade, private beamTwoFacade: BeamTwoFacade ) { this.beamOneStatus$ = this.beamOneFacade.beamOneStatus$; this.beamTwoStatus$ = this.beamTwoFacade.beamTwoStatus$; } }
  39. @samjulien @Component({...}) export class ColliderComponent { beamOneStatus$: Observable<BeamStatus>; beamTwoStatus$: Observable<BeamStatus>;

    constructor( private beamOneFacade: BeamOneFacade, private beamTwoFacade: BeamTwoFacade ) { this.beamOneStatus$ = this.beamOneFacade.beamOneStatus$; this.beamTwoStatus$ = this.beamTwoFacade.beamTwoStatus$; }⠀ }⠀
  40. @samjulien private beamTwoFacade: BeamTwoFacade ) { this.beamOneStatus$ = this.beamOneFacade this.beamTwoStatus$

    = this.beamTwoFacade }⠀ turnOnBeams() { this.beamOneFacade.turnOn(); this.beamTwoFacade.turnOn(); }⠀ }⠀
  41. @samjulien @Component({...}) export class ColliderComponent { beamOneStatus$: Observable<BeamStatus>; beamTwoStatus$: Observable<BeamStatus>;

    constructor( private beamOneFacade: BeamOneFacade, private beamTwoFacade: BeamTwoFacade ) { this.beamOneStatus$ = this.beamOneFacade.beamOneStatus$; this.beamTwoStatus$ = this.beamTwoFacade.beamTwoStatus$; }⠀ turnOnBeams() { this.beamOneFacade.turnOn(); this.beamTwoFacade.turnOn(); }⠀ }⠀
  42. @samjulien @Injectable({...}) export class BeamOneFacade { beamOneStatus$: Observable<BeamStatus>; constructor(private store:

    Store<State>) { this.beamOneStatus$ = this.store.select(selectBeamOneStatus); } turnOn() { this.store.dispatch(BeamOneActionTypes.startBeamOne); } }
  43. @samjulien @Injectable({...}) export class BeamOneFacade { beamOneStatus$: Observable<BeamStatus>; constructor(private store:

    Store<State>) { this.beamOneStatus$ = this.store.select(selectBeamOneStatus); } turnOn() { this.store.dispatch(BeamOneActionTypes.startBeamOne); } }
  44. @samjulien @Injectable({...}) export class BeamOneFacade { beamOneStatus$: Observable<BeamStatus>; constructor(private store:

    Store<State>) { this.beamOneStatus$ = this.store.select(selectBeamOneStatus); } dispatch(action: Action) { this.store.dispatch(action); } }
  45. @samjulien @Component({...}) export class ColliderComponent { beamOneStatus$: Observable<BeamStatus>; beamTwoStatus$: Observable<BeamStatus>;

    constructor( private beamOneFacade: BeamOneFacade, private beamTwoFacade: BeamTwoFacade ) { this.beamOneStatus$ = this.beamOneFacade.beamOneStatus$; this.beamTwoStatus$ = this.beamTwoFacade.beamOneStatus$; } }
  46. @samjulien @Component({...}) export class ColliderComponent { beamOneStatus$: Observable<BeamStatus>; beamTwoStatus$: Observable<BeamStatus>;

    constructor( private beamOneFacade: BeamOneFacade, private beamTwoFacade: BeamTwoFacade ) { this.beamOneStatus$ = this.beamOneFacade.beamOneStatus$; this.beamTwoStatus$ = this.beamTwoFacade.beamOneStatus$; } }
  47. @samjulien @Component({...}) export class ColliderComponent { beamOneStatus$: Observable<BeamStatus>; beamTwoStatus$: Observable<BeamStatus>;

    constructor( private beamOneFacade: BeamOneFacade, private beamTwoFacade: BeamTwoFacade ) { this.beamOneStatus$ = this.beamOneFacade.beamOneStatus$; this.beamTwoStatus$ = this.beamTwoFacade.beamOneStatus$; }⠀ }⠀
  48. @samjulien constructor( private beamOneFacade: BeamOneFacade, private beamTwoFacade: BeamTwoFacade ) {

    this.beamOneStatus$ = this.beamOneFacade.beamOneStatus$; this.beamTwoStatus$ = this.beamTwoFacade.beamOneStatus$; }⠀ ⠀
  49. @samjulien constructor( private beamOneFacade: BeamOneFacade, private beamTwoFacade: BeamTwoFacade ) {

    this.beamOneStatus$ = this.beamOneFacade.beamOneStatus$; this.beamTwoStatus$ = this.beamTwoFacade.beamOneStatus$; this.bothBeams$ = combineLatest( this.beamOneStatus$, this.beamTwoStatus$ ).pipe( map(([beamOne, beamTwo]) => beamOne && beamTwo) ); }
  50. @samjulien constructor( private beamOneFacade: BeamOneFacade, private beamTwoFacade: BeamTwoFacade ) {

    this.beamOneStatus$ = this.beamOneFacade.beamOneStatus$; this.beamTwoStatus$ = this.beamTwoFacade.beamOneStatus$; this.bothBeams$ = combineLatest( this.beamOneStatus$, this.beamTwoStatus$ ).pipe( map(([beamOne, beamTwo]) => beamOne && beamTwo) ); }
  51. @samjulien @Injectable({...}) export class ColliderFacade { combinedStatus$: Observable<CombinedStatus>; constructor(private store:

    Store<State>) { this.combinedStatus$ = this.store.select(selectCombinedStatus); }⠀ dispatch(action: Action) { this.store.dispatch(action); }⠀ }⠀
  52. @samjulien @Injectable({...}) export class ColliderFacade { combinedStatus$: Observable<CombinedStatus>; constructor(private store:

    Store<State>) { this.combinedStatus$ = this.store.select(selectCombinedStatus); }⠀ dispatch(action: Action) { this.store.dispatch(action); }⠀ }⠀
  53. @samjulien @Injectable({...}) export class ColliderFacade { combinedStatus$: Observable<CombinedStatus>; constructor(private store:

    Store<State>) { this.combinedStatus$ = this.store.select(selectCombinedStatus); }⠀ dispatch(action: Action) { this.store.dispatch(action); }⠀ }⠀
  54. @samjulien @Injectable({...}) export class ColliderFacade { combinedStatus$: Observable<CombinedStatus>; constructor(private store:

    Store<State>) { this.combinedStatus$ = this.store.select(selectCombinedStatus); }⠀ dispatch(action: Action) { this.store.dispatch(action); }⠀ }⠀
  55. @samjulien @Injectable({...}) export class ColliderFacade { combinedStatus$: Observable<CombinedStatus>; magnetStatus$: Observable<MagnetStatus>;

    constructor(private store: Store<State>) { this.combinedStatus$ = this.store.select(selectCombinedStatus); this.magnetStatus$ = this.store.select(selectMagnetStatus); }⠀ dispatch(action: Action) { this.store.dispatch(action); }⠀ }⠀
  56. @samjulien @Injectable({...}) export class ColliderFacade { combinedStatus$: Observable<CombinedStatus>; constructor(private store:

    Store<State>) { this.combinedStatus$ = this.store.select(selectCombinedStatus); }⠀ dispatch(action: Action) { this.store.dispatch(action); }⠀ }⠀
  57. @samjulien @Injectable({...}) export class ColliderFacade { combinedStatus$: Observable<CombinedStatus>; constructor(private store:

    Store<State>) { this.combinedStatus$ = this.store.select(selectCombinedStatus); }⠀ dispatch(action: Action) { this.store.dispatch(action); }⠀ }⠀
  58. @samjulien @Component({...}) export class ColliderComponent { combinedStatus$: Observable<CombinedStatus>; constructor(private colliderFacade:

    ColliderFacade) { this.combinedStatus$ = this.colliderFacade.combinedStatus$; } turnOnBeams() { this.colliderFacade.dispatch(ColliderActionTypes.turnBeamsOn); } }
  59. @samjulien @Component({...}) export class ColliderComponent { combinedStatus$: Observable<CombinedStatus>; constructor(private colliderFacade:

    ColliderFacade) { this.combinedStatus$ = this.colliderFacade.combinedStatus$; } turnOnBeams() { this.colliderFacade.dispatch(ColliderActionTypes.turnBeamsOn); } }
  60. @samjulien @Component({...}) export class ColliderComponent { combinedStatus$: Observable<CombinedStatus>; constructor(private colliderFacade:

    ColliderFacade) { this.combinedStatus$ = this.colliderFacade.combinedStatus$; } turnOnBeams() { this.colliderFacade.dispatch(ColliderActionTypes.turnBeamsOn); } }
  61. @samjulien @Component({...}) export class ColliderComponent { combinedStatus$: Observable<CombinedStatus>; constructor(private colliderFacade:

    ColliderFacade) { this.combinedStatus$ = this.colliderFacade.combinedStatus$; } turnOnBeams() { this.colliderFacade.dispatch(ColliderActionTypes.turnBeamsOn); } }