Apologies in advance if there is a better place to ask this question, please let me know if there is:
I am wondering if someone can point me to any resources that discuss the architecture of the Github Desktop application, especially the approach to state management. I am currently working on a refactor of a v1.0 of an application I built using Electron/React (my first production React application) and I have been looking through the code here for ideas on structure and best practices. My app uses Reflux for managing state, with multiple stores, and the code has turned into spaghetti and could be more performant.
Looking at the code here I see it does not use a state library like Reflux, and seems to be a roll-you-own approach, so I am interested in getting better handle on it and the trade-offs and advantages versus Redux in particular.
Thx.
Hi @rkpatel33,
You're correct in noting that our way of dealing with state is a custom approach that we chose early on while building out the foundations of the project. While it has worked decently for us I'd say that it's also very specific to our needs and I'd advise against looking at it for anything more than inspiration. Libraries such as Flux/Redux have considered vastly more workflows and scenarios than we have and are also way better documented than our bespoke solution.
Speaking of documentation, there's not much available. We do document some larger concepts in https://github.com/desktop/desktop/tree/master/docs/technical but this particular area was one of the earliest things we added and documentation was just not top priority at that time.
I want to underline that we didn't pick this approach because we felt like it was superior to any other pre-built library, it just grew organically, starting with a need for some basic form of keeping track of state and not wanting to add abstractions early on before we had a good sense of what was needed. The reason we're still keeping it is twofold, first off it hasn't caused us any trouble and we haven't seen any performance degradation worth noting as a result of our solution. Second, as the app has grown the work needed to refactor this to some pre-built solution has also grown and we have plenty of areas of the code base which would yield bigger improvements both in performance and ease-of-use than replacing our home-grown state solution.
As for the basic layout we have one main Store, the AppStore. A Store in our case is a class with methods for performing actions on the state and a way of subscribing to updates of that store's state. State inside of stores is immutable and new state is constructed by merging previous state with a subset of properties that are to be updated. Whenever a store's state has been updates it publishes an event to let any subscribers (like the <App /> component) know that something has changed. These state updates are only published at most once per animation frame which means that multiple state updates can get coalesced into one single state update. This means that we don't have to worry about calling multiple store actions in series affecting performance.
For organization purposes we don't have just the one store but also 'sub-stores' which are owned by the AppStore. When a sub-store updates the app store will usually incorporate that store's state into its own.
Finally we have a Dispatcher which is simply a proxy into stores. An isolation boundary if you will. It's pretty boring, being mostly small methods which in turn invokes the corresponding method on the AppStore. The thought here was that we didn't want react components to have access to the stores directly.
I hope that helps give a little bit of an insight into the architecture. I'm going to close this issue out but if you have any specific questions about the implementation feel free to ask them here and we'll do our best to answer it.
Most helpful comment
Hi @rkpatel33,
You're correct in noting that our way of dealing with state is a custom approach that we chose early on while building out the foundations of the project. While it has worked decently for us I'd say that it's also very specific to our needs and I'd advise against looking at it for anything more than inspiration. Libraries such as Flux/Redux have considered vastly more workflows and scenarios than we have and are also way better documented than our bespoke solution.
Speaking of documentation, there's not much available. We do document some larger concepts in https://github.com/desktop/desktop/tree/master/docs/technical but this particular area was one of the earliest things we added and documentation was just not top priority at that time.
I want to underline that we didn't pick this approach because we felt like it was superior to any other pre-built library, it just grew organically, starting with a need for some basic form of keeping track of state and not wanting to add abstractions early on before we had a good sense of what was needed. The reason we're still keeping it is twofold, first off it hasn't caused us any trouble and we haven't seen any performance degradation worth noting as a result of our solution. Second, as the app has grown the work needed to refactor this to some pre-built solution has also grown and we have plenty of areas of the code base which would yield bigger improvements both in performance and ease-of-use than replacing our home-grown state solution.
As for the basic layout we have one main
Store, theAppStore. AStorein our case is a class with methods for performing actions on the state and a way of subscribing to updates of that store's state. State inside of stores is immutable and new state is constructed by merging previous state with a subset of properties that are to be updated. Whenever a store's state has been updates it publishes an event to let any subscribers (like the<App />component) know that something has changed. These state updates are only published at most once per animation frame which means that multiple state updates can get coalesced into one single state update. This means that we don't have to worry about calling multiple store actions in series affecting performance.For organization purposes we don't have just the one store but also 'sub-stores' which are owned by the
AppStore. When a sub-store updates the app store will usually incorporate that store's state into its own.Finally we have a
Dispatcherwhich is simply a proxy into stores. An isolation boundary if you will. It's pretty boring, being mostly small methods which in turn invokes the corresponding method on theAppStore. The thought here was that we didn't want react components to have access to the stores directly.I hope that helps give a little bit of an insight into the architecture. I'm going to close this issue out but if you have any specific questions about the implementation feel free to ask them here and we'll do our best to answer it.