Try   HackMD

Ahau maintenance / complexity mentoring

Purpose: high level review of current app state,
leading to advice on what to focus on / research,
or gotchas/ code smells

Agenda

  • architecture overview
  • complexity
  • testing

architecture overview


  front-end
    - vue
    - vuex
    - vue-router
    - apollo ---+
                |
                |
-----           |
                |
  graphql API :                                 
  +===============================+
  | @ssb-graphql/whakapapa ---+   |      
  | @ssb-graphql/profile      |   |-------+
  |         |                 |   |       |
  +=========|=================|===+       |
            |                 |           |
  plugins: ssb-profile, ssb-whakapapa, ssb-ahau
                 | 
             --crut--
            /        \
  indexes: backlinks  query

  log: |||||||
  
  • database :

    • log: ssb-db,

    • indexes:

      • ssb-backlinks
      • ssb-query
    • record helpers: (using ssb-crut)

      • ssb-profile
      • ssb-artefact
      • ssb-whakapapa
    • general plugins

      • ssb-tribes (group encryption)

      • ssb-invites

      • ssb-friends

      • ssb-conn

      • ssb-replicate

      • ssb-blobs + ssb-serve-blobs

      • ssb-hyper-blobs

  • API :

    • ssb-ahau
      • graphql server (federated)
        • @ssb-graphql/main
        • @ssb-graphql/invite
        • @ssb-graphql/tribes
        • @ssb-graphql/profile
          • cache
        • @ssb-graphql/whakapapa
        • @ssb-graphq/story
        • @ssb-graphql/artefact
      • auto-private-profile
  • UI

    • Vue
    • Apollo (and vue integrations)
    • Vuex
    • D3
    • Vue router

current areas of complexity

  • state management

    • vuex
      • dialogs (modals)
      • notifications
      • selectedProfile in whakapapa tree
      • loading/ manipulating the whakapapa tree
    • apollo
      • query/ mutation mixins
      • cache
        • note there's client side cache + we have server side cache for some records
    • cache invalidation
  • dialog handlers / modals

    • controls which dialog to open
  • routes

    • /tribe/:tribeId/profile/:profileId
      • take params.profileId > apollo > getProfile(profileId) > profile record
  • graphql

    • meant to be standalone fragments
    • problems
      • @ssb-graphql/main is required core (dumping ground?)
      • some modules quite dependant now
      • where is that type coming from / who is mutating this type?
      • extending types in other modules

testing

UI/ integration testing

It's really easy for us to accidentally break a feature and not know D:

  • e.g. mix broke file uploading
  • e.g. somehow image loading on collections+whakapapa got broken

Questions

  • what are your shining golden examples of patterns you love

    • mixins
  • what are the anti-patterns that you'd like to remove

    • things doing raw apollo when there's already a mixin for that.

    • leave a NOTE about why you're doing raw apollo if you are going to?

    • gotcha: mixins sometimes have dependencies (functions they need. make sure to check for those)

  • is there anything in vuex that could better be stored in the route?

    • as these are both used for global state
    • which things really need to use vuex?
      • tree > vuex
      • selectedProfile > route? (depends if storing ID or whole profile)
  • dialogs

    • easy to design, hard to develop well

      • can have unintended consequences
        • how do you do routing
        • what happens we you go "back" or close a dialog
        • problem for mobile back
    • which things could be pages?

      • dialogs are pages without routing
        • they force you to re-write routing to make it work to flow between dialogs
        • if it greys out the rest of the page it's basically a new page
    • sidebars are cool

      • it's about NOT losing your place
      • if it's not obscuring the page, then it's extending context on current page
    • in our app, it means multiple different things

      • sidebar
      • modal which greys out the screen
        • e.g. confirm delete popup (over another one)
      • page thing
  • Mix: how do you hold position on page?

  • state management

    • i.e. database stuff

    • things are calling apollo at:

      • component

      • mixins
        • like:
          • consolidates common state logic in one place (maintenance)
          • this.
            route,this.
            apollo, has access to componenent state
          • can await responses (vuex would have to use some annoying listener)
      • vuex
    • mikey: what are mixins doing that vuex can't?

      • mix: awaiting mixins is easier
      • mikey: can you await a dispatched action? YES: https://vuex.vuejs.org/guide/actions.html#composing-actions
        • e.g. the addPerson method could be a chain of composed actions.
        • this is better than doing lots of state management in a view (which should just be doing presentation)
    • mikey opinions:

      • mixins as a general pattern require on a lot of monkey patching
        • depends on what that object has - implicit deps
          • accessing things via this.* can be tricksy
          • how do you write unit tests?
        • different than functions which import other function - explicit deps
          • explicit is easier/ more well defined
      • vuex should be where apollo happens
        • need a way to inject apollo in
          • there are different modules in the store that will need apollo
      • need one place where data manipulation is happening
      • could use stand along functions which are not mixins (don't have magical context)
      • need to figure out how to pass in apollo to vuex (so it's easier to do testing well)
      • maybe also look at vuex alternatives
      • code smells summary
        • not easy to test
        • deps implicit
        • state management too spread out
    • can await responses ()vuex would have to use some annoying listener

  • caching

    • mix describes where caching has been done, challenges
    • mikey: there's a react lib called "stale-while-revalidate"
      • https://github.com/vercel/swr
      • strategy:
        • return stale data
        • start a fetch (revalidate)
        • provide new data when it arrives
      • could have a promise which resolves with { cached, current: Promise }
  • Every project is different and whats important is that you have a pattern that works for you

  • I've got some feelings about the arrangement you currently you

  • Not a huge fan of mixins

  • Dialogs force you to write your own router

    • cant easily go back

Testing

Next Steps

  • Research

    • async/await dispatch
      • see if you can await things from the frontend
      • see if this returns anything?
    • how to store results ?? vuex state?
    • next:
      • try converting one mixin over to vuex
        • stories
      • write a policy/ guide for how we do apollo/ vuex/ component states
        • makes sure everything else conforms to pattern (or leave detailed notes why it doesn't)
  • Dialogs

    • review the dialogs
      • which can be converted to pages (with distinct routes)
        • can investigate vue-router scroll position stuff (see link)
      • which are sidebars
      • which are happily modals