-
-
Save mattknox/69bfd7fc1bcb668615e8b329b8e0cac7 to your computer and use it in GitHub Desktop.
Revisions
-
idibidiart revised this gist
Apr 3, 2017 . 1 changed file with 3 additions and 3 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -8,15 +8,15 @@ We use GraphQL to dynamically derive a UI-specific projection of app state from With this approach, the developer's job becomes a much more pleasant and simpler task of building the application-level GraphQL schema, building UI components and declaratively specifying the required queries and mutations. Client-centric architectures (like those based on client-side 'app state' stores) tend to compose "app state" on the client, and as such end up replicating business logic in the client. While those architectures enable things like 'optimistic UI' and 'offline first' apps they can exponentially complicate the work involved in maintaining and evolving the application.  ## Optimistic and Offline-First UI This principles presented here are for realtime, transactional apps (think: ordering & delivery and 'hard realtime' apps like Uber) In the context of realtime apps, what does it mean to tell the user that their order was successful or the driver is 2 minutess away then finding out from server that the order cannot be fulfilled or the driver is stuck in traffic? This is to say that offline-first UI and optimistic UI are at odds with 'realtime' apps and present extra overhead of replicating app state and business logic in the client. So then the question is wouldn't losing Optimistic UI hurt mobile performance? The fact is that GraphQL already does a lot to help mobile performance by allowing us to get exactly the data we need at any given instance as opposed to downloading more data than we need and putting it in the client side cache then having to keep all that data in sync with the server, which could be very challenging, especially if we compose app state on the client, which means that we have a lot of client derived state that depends on the cached data. ## Some Challenges and Considerations -
idibidiart revised this gist
Mar 24, 2017 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,4 +1,4 @@ ## Building a Maintainable, Agile Architecture for Realtime, Transactional Apps A maintainable application architecture requires that the UI only contain the rendering logic and execute queries and mutations against the underlying data model on the server. A maintainable architecture must not contain any logic for composing "app state" on the client as that would necessarily embed business logic in the client. App state should be persisted to the database and the client projection of it should be composed in the mid tier, and refreshed as mutations occur on the server (and after network interruption) for a highly interactive, realtime UX. -
idibidiart revised this gist
Mar 24, 2017 . 1 changed file with 2 additions and 2 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -52,12 +52,12 @@ Repo coming soon... Here is a section of the very long conversation that Dan started:  ###Update 3: My follow up conversation with Dan Abrahmov below  -
idibidiart revised this gist
Mar 24, 2017 . 1 changed file with 28 additions and 4 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,20 +1,44 @@ ## Building Maintainable, Agile Architecture for Realtime, Transactional Apps A maintainable application architecture requires that the UI only contain the rendering logic and execute queries and mutations against the underlying data model on the server. A maintainable architecture must not contain any logic for composing "app state" on the client as that would necessarily embed business logic in the client. App state should be persisted to the database and the client projection of it should be composed in the mid tier, and refreshed as mutations occur on the server (and after network interruption) for a highly interactive, realtime UX. With GraphQL we are able to define an easy-to-change application-level data schema on the server that captures the types and relationships in our data, and wiring it to data sources via resolvers that leverage our db's own query language (or data-oriented, uniform service APIs) to resolve client-specified "queries" and "mutations" against the schema. We use GraphQL to dynamically derive a UI-specific projection of app state from server-side data sources to client that can be updated in real time (with help of Feathers) With this approach, the developer's job becomes a much more pleasant and simpler task of building the application-level GraphQL schema, building UI components and declaratively specifying the required queries and mutations. Client-centric architectures (like those based on client-side 'app state' stores) tend to cache and most often compose "app state" on the client, and as such end up either replicating business logic in the client or managing cache invalidation at granular level. While those architectures enable things like 'optimistic UI' and 'offline first' apps they can exponentially complicate the work involved in maintaining and evolving the application.  ## Optimistic and Offline-First UI This meta-framework is designed for realtime, transactional apps (think: ordering & delivery and 'hard realtime' apps like Uber) In this context, what does it mean to tell the user that their order was successful or the driver is 2 mins away then finding out from server that the order cannot be fulfilled or the driver is stuck in traffic? This is to say that offline-first UI and optimistic UI are at odds with 'realtime' apps and present extra overhead of replicating app state and business logic in the client. So then the question is wouldn't losing Optimistic UI hurt mobile performance? The fact is that GraphQL already does a lot to help mobile performance by allowing us to get exactly the data we need at any given instance as opposed to dowloading more data than we need and putting it in the client side cache (aka client-side app state container) and complicating the app by having to manage app state on client and server instead of simply deriving it from server in real time. ## Some Challenges and Considerations 1. Avoid business logic in the client: “app state” should not be composed and/or cached on the client as that would put redundant business logic in the client which adds a lot of unneeded complexity to the app. The client needs to be just an I/O layer, fetching/re-fetching UI-component-bound query results and making mutations to data on the server. In this pure, functional client model, local component state (including local state of higher order components) is used for ephemeral, client-only state such as animation state. We avoid composing app state on the client because that necessitates the embedding of business logic in the client, which complicates app building and maintenance. Instead, we opt to simply refetch UI-component-bound query results based on certain events like (backend mutation events, navigation state change or after network interruption) and let UI components derive their own local state from server-side app state which is persisted to the database and composed and projected to the client via GraphQL. The business logic stays on the server and the UI developer's job becomes very simple. 2. The need for pre-mutation hooks: we need to be able to authorize the user before executing a mutation (and conditionally avoiding the mutation) so we can implement authorization on the server and leave business logic completely outside the client. 3. The need for post-mutation hooks to make calls to external APIs (e.g. send email) after a given mutation. 4. The need for live mutation events that perform well at scale: when something changes on the server, we need to know about it, either via polling or signaling. The latter has the advantage of being immediate. 5. Currently, GraphQL developers need to know many different querying syntaxes for the various resolvers in the schema (MySQL, MongoDB, different APIs, etc), or write their own API adapters for each data store to decouple their resolvers from the underlying data store. 6. We should be able to validate data based on our business logic, inside GraphQL resolvers 7. We should be able to implement secure authentication using OAuth and Email/Password. 8. We should be able to implement authorization independent of our database or network interface. 9. We should be able to implement validation generically at the UI component level for instant feedback as user types 10. We should be able to compose business logic in GraphQL resolver using microservices with a uniform data-oriented interface. ###References -
idibidiart revised this gist
Mar 11, 2017 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -8,7 +8,7 @@ We use GraphQL queries to dynamically derive a UI-specific mapping of app state With this approach, the developer's job becomes a much more pleasant and simpler task of building the application-level GraphQL schema, building UI components and declaratively specifying the required queries and mutations. Client-centric architectures (like those based on Redux, MobX, Reframe, Elm, et al) tend to derive and/or cache "app state" on the client, and as such end up either replicating business logic in the client or managing cache invalidation at granular level. While those architectures enable things like 'optimistic UI' and 'offline first' apps they can exponentially complicate the work involved in maintaining and evolving the application.  -
idibidiart revised this gist
Mar 11, 2017 . 1 changed file with 0 additions and 22 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -16,28 +16,6 @@ Client-centric architectures (like those based on Redux MobX, Reframe, Elm, et a This meta-framework is designed for realtime, transactional apps (think: ordering & delivery and 'hard realtime' apps Uber) In this context, what does it mean to tell the user that their order was successful or the driver is 2 mins away then finding out from server that the order cannot be fulfilled or the driver is stuck in traffic? So offline-first and optimistic updates are at odds with 'realtime' and present extra overhead in 'transactional' apps where things are changing all the time. It is said that cache invalidation (a cache, aka client-side app state container, is necessary for optimistic and offline-first UI) is one of the three hardest problems in computer science. So we definitely gain agility and simplicity by removing the requirement for offline-first and optimistic UI. So then the question is wouldn't thast hurt mobile performance? The fact is that GraphQL already does a lot to help mobile performance by allowing us to get exactly the data we need at any given instance as opposed to dowloading more data than we need and putting it in the client side cache (aka client-side app state container) and complicating the app by having to manage app state on client and server instead of simply deriving it from server in real time. ###References 1. [Building a GraphQL Server with Node.js and SQL] (https://www.reindex.io/blog/building-a-graphql-server-with-node-js-and-sql/) -
idibidiart revised this gist
Mar 8, 2017 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -8,7 +8,7 @@ We use GraphQL queries to dynamically derive a UI-specific mapping of app state With this approach, the developer's job becomes a much more pleasant and simpler task of building the application-level GraphQL schema, building UI components and declaratively specifying the required queries and mutations. Client-centric architectures (like those based on Redux MobX, Reframe, Elm, et al) tend to derive and/or cache "app state" on the client, and as such end up either replicating business logic in the client or managing cache invalidation at granular level. While those architectures enable things like 'optimistic UI' and 'offline first' apps they can exponentially complicate the work involved in maintaining and evolving the application.  -
idibidiart revised this gist
Mar 8, 2017 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,4 +1,4 @@ ## Building Maintainable, Agile Architecture for Realtime, Transactional Apps A maintainable application architecture requires that the UI only contain the rendering logic and execute queries and mutations against the underlying data model on the server. A maintainable architecture must not contain any logic for managing "app state" on the client (other than client-only state for generic input validation or animation which is encapsulated by individual UI components or HOCs), as either would necessarily embed business logic in the client and introduce cache invalidation challenges. App state should be derived directly from the server, and in realtime for highly interactive UX. -
idibidiart revised this gist
Mar 8, 2017 . 1 changed file with 2 additions and 2 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -18,7 +18,7 @@ This meta-framework is designed for realtime, transactional apps (think: orderi ## Some Challenges and Considerations 1. Avoid business logic in the client: “app state” should not be composed and/or cached on the client as that would put redundant business logic in the UI and/or lead to cache-invalidation challenges both of which add a lot of unneeded complexity to the app. The UI needs to be just an I/O layer, fetching/re-fetching UI-component-bound query results and making mutations to data on the server, leveraging an application-level, UI-agnostic schema on the server. In this state-free, functional UI model, local component state (including local state of higher order components) is used for ephemeral, client-only state such as animation state. We avoid caching and/or composing app state on the client because that ultimately leads to cache invalidation challenges, not to mention embedding business logic in the UI, both of which greatly complicate things. Instead, we opt to simply refetch UI-component-bound query results based on certain events like (backend mutation events, navigation state change or after network interruption) and let UI components derive their own state from the server based on bound query results. The business logic stays on the server and the UI developer's job becomes very simple. 2. The need for pre-mutation hooks: we need to be able to authorize the user before executing a mutation (and conditionally avoiding the mutation) so we can implement authorization on the server and leave business logic completely outside the client. @@ -36,7 +36,7 @@ This meta-framework is designed for realtime, transactional apps (think: orderi 9. We should be able to implement validation generically at the UI component level for instant feedback as user types 10. We should be able to compose business logic in GraphQL resolver using microservices with a uniform data-oriented interface. ###References -
idibidiart revised this gist
Mar 8, 2017 . 1 changed file with 1 addition and 3 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -8,10 +8,8 @@ We use GraphQL queries to dynamically derive a UI-specific mapping of app state With this approach, the developer's job becomes a much more pleasant and simpler task of building the application-level GraphQL schema, building UI components and declaratively specifying the required queries and mutations. Client-centric architectures (aka shallow architectures) tend to derive and/or cache "app state" on the client, and as such end up either replicating business logic in the client or managing cache invalidation at granular level. While those architectures enable things like 'optimistic UI' and 'offline first' apps they can exponentially complicate the work involved in maintaining and evolving the application.  ## Optimistic and Offline-First UI -
idibidiart revised this gist
Feb 19, 2017 . 1 changed file with 40 additions and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,3 +1,43 @@ ## Building a Maintainable, Agile Architecture for Realtime, Transactional Apps A maintainable application architecture requires that the UI only contain the rendering logic and execute queries and mutations against the underlying data model on the server. A maintainable architecture must not contain any logic for managing "app state" on the client (other than client-only state for generic input validation or animation which is encapsulated by individual UI components or HOCs), as either would necessarily embed business logic in the client and introduce cache invalidation challenges. App state should be derived directly from the server, and in realtime for highly interactive UX. With GraphQL we are able to define an easy-to-change application-level data schema on the server that captures the types and relationships in our data, and wiring it to data sources via resolvers that leverage our db's own query language (or data-oriented, uniform service APIs) to resolve client-specified "queries" and "mutations" against the schema. We use GraphQL queries to dynamically derive a UI-specific mapping of app state from server-side data stores to client that can be updated in real time (see FeathersJS below.) With this approach, the developer's job becomes a much more pleasant and simpler task of building the application-level GraphQL schema, building UI components and declaratively specifying the required queries and mutations. Client-based architectures (aka shallow architectures) like Redux, MobX, et al. manage "app state" on the client, and as such end up embedding business logic in the client. While those architectures enable things like 'optimistic UI' and 'offline first' apps they necessarily lead to the creation of fat clients and the dispersion and replication of business logic across UI and backend, which doubles (if not exponentially complicates) the work involved in maintaining and evolving the application. | |  ## Optimistic and Offline-First UI This meta-framework is designed for realtime, transactional apps (think: ordering & delivery and 'hard realtime' apps Uber) In this context, what does it mean to tell the user that their order was successful or the driver is 2 mins away then finding out from server that the order cannot be fulfilled or the driver is stuck in traffic? So offline-first and optimistic updates are at odds with 'realtime' and present extra overhead in 'transactional' apps where things are changing all the time. It is said that cache invalidation (a cache, aka client-side app state container, is necessary for optimistic and offline-first UI) is one of the three hardest problems in computer science. So we definitely gain agility and simplicity by removing the requirement for offline-first and optimistic UI. So then the question is wouldn't thast hurt mobile performance? The fact is that GraphQL already does a lot to help mobile performance by allowing us to get exactly the data we need at any given instance as opposed to dowloading more data than we need and putting it in the client side cache (aka client-side app state container) and complicating the app by having to manage app state on client and server instead of simply deriving it from server in real time. ## Some Challenges and Considerations 1. Avoid business logic in the client: “app state” should not be constructed on the client as that would put redundant business logic in the UI and lead to cache-invalidation challenges both of which add a lot of unneeded complexity to the app. The UI needs to be just an I/O layer, fetching/re-fetching UI-component-bound query results and making mutations to data on the server, leveraging an application-level, UI-agnostic schema on the server. In this state-free, functional UI model, local component state (including local state of higher order components) is used for ephemeral, client-only state such as animation state. We avoid deriving/constructing app state on the client because that ultimately leads to cache invalidation challenges, not to mention embedding business logic in the UI, both of which greatly complicate things. Instead, we opt to simply refetch UI-component-bound query results either via component-bound subscriptions or polling (with ability to force updates on immediate basis) and let UI components derive their own state from the server based on bound query results. We also refetch query results immediately (for all components that are mounted) when we mutate something on the server. The business logic stays on the server and the UI developer's job becomes very simple. 2. The need for pre-mutation hooks: we need to be able to authorize the user before executing a mutation (and conditionally avoiding the mutation) so we can implement authorization on the server and leave business logic completely outside the client. 3. The need for post-mutation hooks to make calls to external APIs (e.g. send email) after a given mutation. 4. The need for live data subscriptions that perform well at scale: when something changes on the server, we need to know about it, either via polling or subscriptions. The latter has the advantage of being immediate. 5. Currently, GraphQL developers need to know many different querying syntaxes for the various resolvers in the schema (MySQL, MongoDB, different APIs, etc), or write their own API adapters for each data store to decouple their resolvers from the underlying data store. 6. We should be able to validate data based on our business logic, inside GraphQL resolvers 7. We should be able to implement secure authentication using OAuth and Email/Password. 8. We should be able to implement authorization independent of our database or network interface. 9. We should be able to implement validation generically at the UI component level for instant feedback as user types 10. We should be able to compose business logic in GraphQL resolver using microservices with a uniform data-oriented interface. ###References -
idibidiart revised this gist
Feb 19, 2017 . 1 changed file with 1 addition and 36 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,39 +1,4 @@ 10. We should be able to compose business logic in GraphQL resolver using microservices with a uniform data-oriented interface. ###References -
idibidiart revised this gist
Feb 12, 2017 . 1 changed file with 19 additions and 13 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,39 +1,45 @@ # Building an Agile, Maintainable Architecture with GraphQL A maintainable application architecture requires that the UI only contain the rendering logic and execute queries and mutations against the underlying data model on the server. A maintainable architecture must not contain any logic for managing "app state" on the client (other than client-only state for generic input validation or animation which is encapsulated by individual UI components or HOCs), as either would necessarily embed business logic in the client and introduce cache invalidation challenges. App state should be derived directly from the server, and in realtime for highly interactive UX. With GraphQL we are able to define an easy-to-change application-level data schema on the server that captures the types and relationships in our data, and wiring it to data sources via resolvers that leverage our db's own query language (or data-oriented, uniform service APIs) to resolve client-specified "queries" and "mutations" against the schema. We use GraphQL queries to dynamically derive a UI-specific mapping of app state from server-side data stores to client that can be updated in real time (see FeathersJS below.) With this approach, the developer's job becomes a much more pleasant and simpler task of building the application-level GraphQL schema, building UI components and declaratively specifying the required queries and mutations. Client-based architectures (aka shallow architectures) like Redux, MobX, et al. manage "app state" on the client, and as such end up embedding business logic in the client. While those architectures enable things like 'optimistic UI' and 'offline first' apps they necessarily lead to the creation of fat clients and the dispersion and replication of business logic across UI and backend, which doubles (if not exponentially complicates) the work involved in maintaining and evolving the application.  ## Current Challenges and Considerations 1. Avoid business logic in the client: “app state” should not be derived/constructed on the client, as that leaks business logic into the UI and leads to cache-invalidation type challenges both of which add a lot of unneeded complexity to the app. The UI needs to be just an I/O layer, fetching/re-fetching UI-component-bound query results and making mutations to data on the server, leveraging an application-level, UI-agnostic schema on the server. In this state-free, functional UI model, local component state (including local state of higher order components) is used for ephemeral, client-only state such as animation state. We avoid deriving/constructing app state on the client because that ultimately leads to cache invalidation challenges, not to mention embedding business logic in the UI, both of which greatly complicate things. Instead, we opt to simply refetch UI-component-bound query results either via component-bound subscriptions or polling (with ability to force updates on immediate basis) and let UI components derive their own state from the server based on bound query results. We also refetch query results immediately (for all components that are mounted) when we mutate something on the server. The business logic stays on the server and the UI developer's job becomes very simple. 2. The need for pre-mutation hooks: we need to be able to authorize the user before executing a mutation (and conditionally avoiding the mutation) so we can implement authorization on the server and leave business logic completely outside the client. 3. The need for post-mutation hooks to make calls to external APIs (e.g. send email) after a given mutation. 4. The need for live data subscriptions that perform well at scale: when something changes on the server, we need to know about it, either via polling or subscriptions. The latter has the advantage of being immediate. 5. Currently, GraphQL developers need to know many different querying syntaxes for the various resolvers in the schema (MySQL, MongoDB, different APIs, etc), or write their own API adapters for each data store to decouple their resolvers from the underlying data store. 6. We should be able to validate data based on our business logic, inside GraphQL resolvers 7. We should be able to implement secure authentication using OAuth and Email/Password. 8. We should be able to implement authorization independent of our database or network interface. 9. We should be able to implement validation generically at the UI component level for instant feedback as user types 10. We should be able to break the business logic into a distributed microservices architecture when/as needed. ###References 1. [Building a GraphQL Server with Node.js and SQL] (https://www.reindex.io/blog/building-a-graphql-server-with-node-js-and-sql/) Repo coming soon... ###Update -
idibidiart revised this gist
Jan 27, 2017 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -15,7 +15,7 @@ Client-based architectures (aka shallow architectures) like Redux, MobX, et al m ## Current Challenges and Considerations 1. Avoid business logic in the client: “app state” should not be derived/constructed on the client, as that leaks business logic into the UI and leads to cache-invalidation type challenges both of which add a lot of unneeded complexity to the app. The UI needs to be just an I/O layer, fetching/re-fetching UI-component-bound query results and making mutations to data on the server, leveraging an application-level, UI-agnostic schema on the server. In this state-free, functional UI model, local component state (including local state of higher order components) is used for ephemeral client-only state like animation state. We avoid deriving/constructing app state on the client because that ultimately leads to cache invalidation challenges, not to mention embedding business logic in the UI, both of which greatly complicate things. Instead, we opt to simply refetch UI-component-bound query results either via component-bound subscriptions or polling (with ability to force updates on immediate basis) and let UI components derive their own state from the server based on bound query results. We also refetch query results immediately (for all components that are mounted) when we mutate something on the server. The business logic stays on the server and the UI developer's job becomes very simple. 2. The need for pre-mutation hooks: we need to be able to validate data before executing a mutation (and conditionally avoiding the mutation) so we can implement validation or sanitation on the server and leave business logic completely outside the client. We also need post-mutation hooks to make calls to APIs that must be called after a given mutation. -
idibidiart revised this gist
Jan 27, 2017 . 1 changed file with 3 additions and 3 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,14 +1,14 @@ # Building an Agile, Maintainable Architecture with GraphQL A maintainable application architecture requires that the UI only contain the rendering logic and execute queries and mutations against the underlying data model on the server. A maintainable architecture must not contain any logic for managing "app state" on the client, as either would necessarily embed business logic in the client and introduce cache invalidation challenges. App state should be derived directly from the server. With GraphQL we asre able to define an application-level, UI-agnostic schema on the server that captures the types and relationships in our data, and wiring it to data sources via resolvers that leverage our db's own query language (or data-oriented, uniform service APIs) to resolve client-defined "queries" and "mutations" against the schema. With each component in the UI component tree declaring its own data dependencies, GraphQL creates a projection of our data on the server that maps directly to the UI component tree. GraphQL allow us to have an application-level, UI-agnostic model of our data on the server, while at the same time giving us and UI-specific projection of the current app state on the client. Given the UI's data dependencies are specified declaratively, the front end developer's job becomes a much more pleasant task of building the application-level, UI-agnostic GraphQL schema, building UI components and declaratively specifying the required queries and mutations. Client-based architectures (aka shallow architectures) like Redux, MobX, et al manage "app state" on the client, and as such end up embedding business logic in the client. While those architectures enable things like 'optimistic UI' and 'offline first' apps they necessarily lead to the creation of fat clients and the dispersion and replication of business logic across UI and backend, which doubles (if not exponentially complicates) the work involved in maintaining and evolving the application.  -
idibidiart revised this gist
Jan 23, 2017 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,6 +1,6 @@ # Building an Agile, Maintainable Architecture with GraphQL A maintainable application architecture requires that the UI only contain the rendering logic and execute queries and mutations against the underlying data model on the server. A maintainable architecture must not contain any logic for deriving/constructing app state on the client, as either would necessarily embed business logic in the client and introduce cache invalidation challenges. App state should be derived directly from the server. GraphQL allows us to do that by defining an application-level, UI-agnostic schema on the server that captures the types and relationships in our data, and wiring it to data sources via resolvers that leverage our db's own query language or existing APIs to resolve client-defined "queries" and "mutations" against the schema. -
idibidiart revised this gist
Jan 23, 2017 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,6 +1,6 @@ # Building an Agile, Maintainable Architecture with GraphQL A maintainable application architecture requires that the UI only contain the rendering logic and execute queries and mutations against the underlying data model on the server. A maintainable architecture must not contain any client-side logic for deriving/constructing app state, as either would necessarily embed business logic in the client and introduce cache invalidation challenges. App state should be derived directly from the server. GraphQL allows us to do that by defining an application-level, UI-agnostic schema on the server that captures the types and relationships in our data, and wiring it to data sources via resolvers that leverage our db's own query language or existing APIs to resolve client-defined "queries" and "mutations" against the schema. -
idibidiart revised this gist
Jan 23, 2017 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -21,7 +21,7 @@ Client-based architectures (aka shallow architectures) like Redux, MobX, et al d 3. The need for live data subscription that perform well at scale: when something changes on the server, we need to know about it, either via polling or subscriptions. The latter has the advantage of being immediate. 4. Currently, GraphQL developers need to know many different querying syntaxes for the various resolvers in the schema (MySQL, MongoDB, different APIs, etc), or write their own API adapters for each data store to decouple their resolvers from the underlying data store. 5. We should be able to implement secure authentication using OAuth and Email/Password. -
idibidiart revised this gist
Jan 23, 2017 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -15,7 +15,7 @@ Client-based architectures (aka shallow architectures) like Redux, MobX, et al d ## Current Challenges and Considerations 1. Avoid business logic in the client: “app state” should not be derived/constructed on the client, as that leaks business logic into the UI and leads to cache-invalidation type challenges both of which add a lot of unneeded complexity to the app. The UI needs to be just an I/O layer, fetching/re-fetching UI-component-bound query results and making mutations to data on the server, leveraging an application-level, UI-agnostic schema on the server. In this state-free, functional UI model, local component state (including local state of higher order components) is used for ephemeral client-only state like animation state. We avoid deriving/constructing app state on the client because that ultimately leads to cache invalidation challenges, not to mention embedding business logic in the UI, both of which greatly complicate things. Instead, we opt to simply refetch UI-component-bound query results either via component-bound subscriptions or polling (with ability to force updates on immediate basis) and let UI components derive their own state from the server based on bound query results. We also refetch query results immediately (for all components that are mounted) when we mutate something on the server. The business logic stays on the server and the UI developer's job becomes ver simple. 2. The need for pre-mutation hooks: we need to be able to validate data before executing a mutation (and conditionally avoiding the mutation) so we can implement validation or sanitation on the server and leave business logic completely outside the client. We also need post-mutation hooks to make calls to APIs that must be called after a given mutation. -
idibidiart revised this gist
Jan 23, 2017 . 1 changed file with 2 additions and 15 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -10,6 +10,7 @@ Given the UI's data dependencies are specified declaratively, the front end deve Client-based architectures (aka shallow architectures) like Redux, MobX, et al derive/construct app state on the server, and as such end up embedding business logic in the client. While those architectures enable things like 'optimistic UI' and 'offline first' apps they necessarily lead to the creation of fat clients and the dispersion and replication of business logic across UI and backend, which doubles (if not exponentially complicates) the work involved in maintaining and evolving the application.  ## Current Challenges and Considerations @@ -34,21 +35,7 @@ Client-based architectures (aka shallow architectures) like Redux, MobX, et al d More coming soon... ###Update @gaearon (Dan Abramov), author of Redux, was gracious enough to tweet this, and I give him a lot of credit for doing so. -
idibidiart revised this gist
Jan 23, 2017 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -10,7 +10,7 @@ Given the UI's data dependencies are specified declaratively, the front end deve Client-based architectures (aka shallow architectures) like Redux, MobX, et al derive/construct app state on the server, and as such end up embedding business logic in the client. While those architectures enable things like 'optimistic UI' and 'offline first' apps they necessarily lead to the creation of fat clients and the dispersion and replication of business logic across UI and backend, which doubles (if not exponentially complicates) the work involved in maintaining and evolving the application.  ## Current Challenges and Considerations -
idibidiart revised this gist
Jan 23, 2017 . 1 changed file with 8 additions and 8 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -10,23 +10,23 @@ Given the UI's data dependencies are specified declaratively, the front end deve Client-based architectures (aka shallow architectures) like Redux, MobX, et al derive/construct app state on the server, and as such end up embedding business logic in the client. While those architectures enable things like 'optimistic UI' and 'offline first' apps they necessarily lead to the creation of fat clients and the dispersion and replication of business logic across UI and backend, which doubles (if not exponentially complicates) the work involved in maintaining and evolving the application.  ## Current Challenges and Considerations 1. Avoid business logic in the client: “app state” should not be derived/constructed on the client, as that leaks business logic into the UI and leads to cache-invalidation type challenges which add a lot of unneeded complexity to the app. The UI needs to be just an I/O layer, fetching/re-fetching UI-component-bound query results and making mutations to data on the server, leveraging an application-level, UI-agnostic schema on the server. In this state-free, functional UI model, local component state (including local state of higher order components) is used for ephemeral client-only state like animation state. We avoid deriving/constructing app state on the client because that ultimately leads to cache invalidation challenges, not to mention embedding business logic in the UI, both of which greatly complicate things. Instead, we opt to simply refetch UI-component-bound query results either via component-bound subscriptions or polling (with ability to force updates on immediate basis) and let UI components derive their own state from the server based on bound query results. We also refetch query results immediately (for all components that are mounted) when we mutate something on the server. The business logic stays on the server and the UI developer's job becomes ver simple. 2. The need for pre-mutation hooks: we need to be able to validate data before executing a mutation (and conditionally avoiding the mutation) so we can implement validation or sanitation on the server and leave business logic completely outside the client. We also need post-mutation hooks to make calls to APIs that must be called after a given mutation. 3. The need for live data subscription that perform well at scale: when something changes on the server, we need to know about it, either via polling or subscriptions. The latter has the advantage of being immediate. 4. Currently, GraphQL developers need to know many different querying syntaxes for the various resolvers in the schema (MySQL, MongoDB, different APIs, etc), or write their own API adapters for each data store to make their connectors consistent. This can be a lot of work and a number of thoughtful design choices must be made for this to work well. 5. We should be able to implement secure authentication using OAuth and Email/Password. 6. We should be able to implement permissions independent of our database or network interface. 7. We should be able to break the business logic into microservices when/as needed. ###References -
idibidiart revised this gist
Jan 23, 2017 . 2 changed files with 65 additions and 48 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,65 @@ # Building an Agile, Maintainable Architecture with GraphQL A maintainable application architecture requires that the UI only contain the rendering logic and execute queries and mutations against the underlying data model on the server. A maintainable architecture must not contain any client-side logic for deriving/constructing app state, as either would necessarily embed business logic in the client, and app state should be derived from the server. GraphQL allows us to do that by defining an application-level, UI-agnostic schema on the server that captures the types and relationships in our data, and wiring it to data sources via resolvers that leverage our db's own query language or existing APIs to resolve client-defined "queries" and "mutations" against the schema. With each component in the UI component tree declaring its own data dependencies, GraphQL creates a projection of our data on the server that maps directly to the UI component tree. GraphQL allow us to have an application-level, UI-agnostic model of our data on the server, while at the same time giving us and UI-specific projection of the current app state on the client. Given the UI's data dependencies are specified declaratively, the front end developer's job becomes a much more pleasant task of building the application-level, UI-agnostic GraphQL schema, building UI components and declaratively specifying the required queries and mutations. Client-based architectures (aka shallow architectures) like Redux, MobX, et al derive/construct app state on the server, and as such end up embedding business logic in the client. While those architectures enable things like 'optimistic UI' and 'offline first' apps they necessarily lead to the creation of fat clients and the dispersion and replication of business logic across UI and backend, which doubles (if not exponentially complicates) the work involved in maintaining and evolving the application. ![graphql] (http://imgur.com/a/ccpiF) ## Current Challenges and Considerations 1. Avoid business logic in the client: “app state” should not be derived/constructed on the client, as that leaks business logic into the UI and leads to cache-invalidation type challenges which add a lot of unneeded complexity to the app. The UI needs to be just an I/O layer, fetching/re-fetching UI-component-bound query results and making mutations to data on the server, leveraging an application-level, UI-agnostic schema on the server. In this state-free, functional UI model, local component state (including local state of higher order components) is used for ephemeral client-only state like animation state. We avoid deriving/constructing app state on the client because that ultimately leads to cache invalidation challenges, not to mention embedding business logic in the UI, both of which greatly complicate things. Instead, we opt to simply refetch UI-component-bound query results either via component-bound subscriptions or polling (with ability to force updates on immediate basis) and let UI components derive their own state from the server based on bound query results. We also refetch query results immediately (for all components that are mounted) when we mutate something on the server. The business logic stays on the server and the UI developer's job becomes ver simple. 2. The need for pre-mutation hooks: we need to be able to validate data before executing a mutation (and conditionally avoiding the mutation) so we can implement validation or sanitation on the server and leave business logic completely outside the client. We also need post-mutation hooks to make calls to APIs that must be called after a given mutation. 3. The need for live data subscription that perform well at scale: when something changes on the server, we need to know about it, either via polling or subscriptions. The latter has the advantage of being immediate. 4. Currently, GraphQL developers need to know many different querying syntaxes for the various resolvers in the schema (MySQL, MongoDB, different APIs, etc), or write their own API adapters for each data store to make their connectors consistent. This can be a lot of work and a number of thoughtful design choices must be made for this to work well. 5. We should be able to implement secure authentication using OAuth and Email/Password. 6. We should be able to implement permissions independent of our database or network interface. 7. We should be able to break the business logic into microservices when/as needed. ###References 1. [Building a GraphQL Server with Node.js and SQL] (https://www.reindex.io/blog/building-a-graphql-server-with-node-js-and-sql/) More coming soon... ###Updated 1: (after a Twitter chat with @en_JS (Joseph Savona), one of the GraphQL/Relay developers at Facebook) Any app state that is not sync'd to the db is not something that Relay encompasses right now, but there is an ongoing [discussion] (https://github.com/facebook/relay/issues/114) for handling scenarios like client-side form validation and state updates from sources other than the db (e.g. websocket) These important scenarios will be addressed according to the Relay Roadmap (https://github.com/facebook/relay/wiki/Roadmap): 1. API for resolving fields locally: #431. 2. Support querying & compiling client-only fields by extending the server schema, and a means for writing data for these fields into the cache: #114. ###Update 2: @gaearon (Dan Abramov), author of Redux, was gracious enough to tweet this, and I give him a lot of credit for doing so. Here is a section of the very long conversation that Dan started: ![twitter conversation] (http://i.imgur.com/BD2Wu5m.png) ###Update 3: My follow up conversation with Dan Abrahmov below ![twitter follow up] (http://i.imgur.com/43lsGJo.png) This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,48 +0,0 @@ -
idibidiart revised this gist
Jan 23, 2017 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,4 +1,4 @@ A maintainable application architecture requires that the UI only contain the rendering logic and execute queries and mutations against the underlying data model on the server. A maintainable architecture must not contain any client-side logic for deriving/constructing app state, as either would necessarily encode business logic in the client, and app state should be derived from the server. GraphQL allows us to do that by defining an application-level, UI-agnostic schema on the server that captures the types and relationships in our data, and wiring to data sources via resolvers that leverage our db's own query language or in-memory objects to resolve client-defined "queries" and "mutations" against the schema. -
idibidiart revised this gist
Jan 23, 2017 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,4 +1,4 @@ A maintainable application architecture requires that the UI only contain the rendering logic and execute queries and mutations against the underlying data layer on the server. A maintainable UI must not contain any logic for deriving user intent or any logic for deriving app state, as either would necessarily encode business logic in the client. GraphQL allows us to do that by defining an application-level, UI-agnostic schema on the server that captures the types and relationships in our data, and wiring to data sources via resolvers that leverage our db's own query language or in-memory objects to resolve client-defined "queries" and "mutations" against the schema. -
idibidiart revised this gist
Jan 14, 2017 . 1 changed file with 7 additions and 18 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,26 +1,15 @@ A maintainable UI architecture requires that our UI only contains the logic to render current app state and relay queries and mutations to the underlying data layer on the server (i.e. a maintainable UI must not contain any logic for deriving user intent or deriving app state, as either would necessarily encode business logic in the client.) GraphQL allows us to do that by defining an application-level, UI-agnostic schema on the server that captures the types and relationships in our data, and wiring to data sources via resolvers that leverage our db's own query language or in-memory objects to resolve client-defined "queries" and "mutations" against the schema. With each component in the UI component tree declaring its own data dependencies, GraphQL (with Relay or Apollo client in the browser) creates a projection of our data on the server that maps directly to the UI component tree. GraphQL + Relay|Apollo allow us to have an application-level, UI-agnostic model of our data on the server, while at the same time giving us and UI-specific projection of our app state in the client. Using Relay or Apollo the queries from our GraphQL client to the GraphQL server are composed in an efficient manner based on the aggregate data dependencies that are declared by each component in the UI component tree, thus eliminating redundant queries over the network. Relay (and Apollo client) also allow for mutation events from the UI to propagate to the server, while keeping the projected app state in the UI in sync with the data on the server. Relay|Apollo can also update the UI when an external mutation (from another process/user) takes place on the server, via GraphQL subscriptions. Given the UI's data dependencies are specified declaratively, the front end developer's job becomes a much more pleasant task of building the application-level, UI-agnostic GraphQL schema, building UI components and declaratively specifying their queries and mutations. With GraphQL + Relay|Apollo everyone, be them web, mobile or 3rd party developers, works with the same application-level, UI agnostic, server-side schema and declare their data dependencies at the UI component level, then have GraphQL in combination with Relay or Apollo et al take care of generating an efficient query, shaping the query result for consumption by the UI and keeping the projected app state in sync with the data on the server. GraphQL + Relay|Apollo eliminate a host of cost centers, conveniences and tools such as RESTful APIs, ORMs/ODMs (it should as it removes the need for manual denormalization/renormalization, unless you don't wish to use SQL/NoSQL query syntax directly) and imperatively sync'd client caches. Client-side-only solutions like Redux, MobX, et al (i.e. without GraphQL + Apollo|Relay) don't go deep enough, and as such end up putting app state and user intent derivation in the client, which means that business logic gets entangled in the client by design. A deep architecture like GraphQL + Relay|Apollo allow us to make radical changes to our UI without a lot of rework on client and server, which is something that cannot be done with a shallow, client-side-only architecture. ###References -
idibidiart revised this gist
Jan 13, 2017 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -27,7 +27,7 @@ A deep architecture like GraphQL/Relay (and Apollo) allow us to make radical cha 1. [Building a GraphQL Server with Node.js and SQL] (https://www.reindex.io/blog/building-a-graphql-server-with-node-js-and-sql/) More coming soon... ###Updated 1: (after a Twitter chat with @en_JS (Joseph Savona), one of the GraphQL/Relay developers at Facebook) -
idibidiart revised this gist
Jan 13, 2017 . 1 changed file with 14 additions and 54 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,35 +1,26 @@ A maintainable UI architecture requires that our UI only contains the logic to render current app state and relay queries and mutations to the underlying data layer on the server (i.e. a maintainable UI must not contain any logic for deriving user intent or deriving app state, as either would necessarily encode business logic in the client.) GraphQL allows us to do that by defining an application-level, UI-agnostic schema on the server that captures the types and relationships in our data, and wiring to data sources via resolvers that leverage our db's own query language or in-memory objects to resolve client-defined "queries" and "mutations" against the schema. With each component in the UI component tree declaring its own data dependencies, GraphQL (with Relay or Apollo client in the browser) creates a projection of the server-side data model that maps directly to the UI component tree, thus allowing us to have an application-level, UI-agnostic model of our data on the server, while at once giving us and UI-specific projection of our app's state. Using Relay or Apollo the queries from our GraphQL client to the GraphQL server are composed in an efficient manner based on the aggregate data dependencies that are declared by each component in the UI component tree, thus eliminating redundant queries over the network. Relay (and Apollo client) also allow for mutation events from the UI to propagate to the server, while keeping the projected app state in the UI in sync with the data on the server. Relay|Apollo can also update the UI when an external mutation (from another process/user) takes place on the server, via GraphQL subscriptions. Given the UI's data dependencies are specified declaratively, the front end developer's job becomes a much more pleasant task of building the application-level, UI-agnostic GraphQL schema, building UI components and declaratively specifying their queries and mutations. With GraphQL/Relay everyone, be them web, mobile or 3rd party developers, works with the same application-level, UI agnostic, server-side schema and declare their data dependencies at the UI component level, then have GraphQL in combination with Relay or Apollo et al take care of generating an efficient query, shaping the query result for consumption by the UI and keeping the projected app state in sync with the data on the server. In one fell swoop, GraphQL/Relay (or Apollo Stack) eliminate a host of cost centers, conveniences and tools such as RESTful APIs, ORMs/ODMs (it should as it removes the need for manual denormalization/renormalization, unless you don't wish to ue SQL/NoSQL query syntax directly) and imperatively sync'd client caches. Client-side-only solutions like Redux (without GraphQL/Apollo) don't go deep enough, and as such end up putting app state and user intent derivation in the client, which means that business logic gets entangled in the client by design. A deep architecture like GraphQL/Relay (and Apollo) allow us to make radical changes to our UI without a lot of rework on client and server, which is something that cannot be done with a shallow, client-side-only architecture. ###References @@ -61,39 +52,8 @@ Here is a section of the very long conversation that Dan started: ###Update 3: My follow up conversation with Dan Abrahmov below ![twitter follow up] (http://i.imgur.com/43lsGJo.png) -
idibidiart revised this gist
Jan 5, 2017 . 1 changed file with 3 additions and 4 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -22,11 +22,10 @@ comparison as they ultimately depend on a client-specified app state data struct be them web, mobile or 3rd party developers, works with the same server side graph schema and declare their data dependencies at the UI component level, then have GraphQL in combination with Relay take care of generating an efficient query, shaping the query result for consumption by the UI and keeping application state in sync across client and server. In one fell swoop, GraphQL/Relay (or Apollo Stack) eliminate a host of cost centers, conveniences and tools such as RESTful APIs, imperatively sync'd client/server caches, and client-side-only solutions like Redux (without GraphQL/Apollo) that don't go deep enough. A deep architecture like GraphQL/Relay (and Apollo) allow us to make radical changes to our UI without a lot of rework on client and server, which is something that cannot be done with a shallow, client-side-only architecture. ###Limitations -
idibidiart revised this gist
Jan 5, 2017 . 1 changed file with 4 additions and 5 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,13 +1,13 @@ GraphQL allows us to define a UI-agnostic data model on the server using a virtual graph schema that captures the types and relationships in the data. To wire the model to data sources, we define resolvers in the schema that leverage our db's own query language (or API calls for in-memory objects) to resolve client-defined "queries" against our data model. With each component in the UI component tree declaring its own data dependencies, GraphQL (with Relay or Apollo client in the browser) creates a projection of the server-side data model that maps directly to the UI component tree, thus allowing us to have a UI-agnostic data model on the server, while at once giving us and UI-specific projection of our app's data/state. The queries from GraphQL server to the database are composed in an efficient manner based on the aggregate data dependencies that are declared by each component in the UI component tree, thus eliminating redundant queries to the database. Relay (and Apollo client) also allow for mutation events from the UI to propagate to the server, while rendering the UI optimistically. It can also update the UI when an external mutation (from another process/user) takes place on the server. @@ -17,8 +17,7 @@ take care of the rest. Since we can only have parent-child composition in the DOM and that is true for React's DOM renderer, too. Thus, the UI as a data structure is a tree of components implementing various behavior that ultimately mutate the DOM. So whatever you can do in with React you'll be able to do with Relay. The Facebook Relay team is planning on providing time travel facility (time based app state inspection) for React/Relay apps (Apollo already uses Redux DevTools) making client-only architectures that rely on Redux only (or other client-side state management patterns) very brittle in comparison as they ultimately depend on a client-specified app state data structure that does not derive declaratively from the state of the server side model, which means lots of rework on both the client side and server side when we need to make deep changes to our app. With GraphQL/Relay everyone, be them web, mobile or 3rd party developers, works with the same server side graph schema and declare their data dependencies at the UI component level, then have GraphQL in combination with Relay take care of generating an efficient query, shaping the query result for consumption by the UI and keeping application state in sync across client and server.
NewerOlder