Principled GraphQL 筆記

杭孟澤
Visually Lab
Published in
8 min readDec 20, 2019

原文出處:https://principledgraphql.com/

最近在研究 GraphQL,也在 production 環境正式使用,過程中一部部部理解它的哲學,也因此更好奇到底怎麼樣才算是設計真正好的 GraphQL Schema 呢?剛好看到這篇文章,於是就做了一些中文筆記 😳

先講結論✌️:

  • 整合性: 一個公司只應該有一個 Graph,且每個 Team 應該共享那個統一的 Graph,但實作上還是各自負責
  • 敏捷:因為 Schema 是一個會不斷被迭代更新的抽象層,建議採用敏捷開發的準則來實作,根據實際需求的變化來增長或改變。
  • 行為:我們需要開始注意更多實際互動上的需求,資料存取權限、log、安全地部署、scalable…。

— 那麼以下開始介紹詳細 —

整合性

1. 一個 Graph 原則

Your company should have one unified graph, instead of multiple graphs created by each team.

一個公司只應該擁有一個 Graph,才可以最大化“data graph” 的價值

  • 因為永遠都只需要一個 query 就能拉到所有你需要的資料。
  • 各團隊之間能夠更好的去掌握彼此的 code, queries, skills
  • 因為只有一個資料視圖,比較不會有「重複打造輪子的狀況」出現
  • 中心化管理資料,對領導者來說可以更好的去檢視所有的資料種類與監控

2. 各個服務,共同架構

Though there is only one graph, the implementation of that graph should be federated across multiple teams.

我們都希望各團隊互相實作之間,能夠擁有良好的擴充性和高度相容性。而在 GraphQL 中思考 graph shape 事實上就是在幫助你思考每一個 model 的職責,盡可能地做到模組拆分化。這樣不同團隊只需要負責他們所專注的「部分資料」,並且專注維護與擴充其服務接口。

團隊領導也就能更清楚的去檢視整個資料視圖,專注真正重要的部分。

3. Single source of truth

There should be a single source of truth for registering and tracking the graph.

這裡是指 Graph schema 的 single source of truth 。我們需要一個統一的來源去管理 schema 版本 ,讓所有的開發者/產品皆以這個版本為準。同時我們也希望能夠像 git branch 一樣管理,分出不同的環境版本去做迭代更新。

通常各家套件都會有相關的工具可以搭配使用管理,像是 Apollo 的 Apollo Engine

敏捷

4. Demand-Oriented Schema

The schema should act as an abstraction layer that provides flexibility to consumers while hiding service implementation details.

GraphQL 一個很大的價值在於:一個介於伺服器端與應用層端的抽象層。

藉由良好的 Schema 我們可以清楚地看出這個服務大致的輪廓,並且藉由調整這個抽象層再讓前後端各自去實作細節。而這大大地減少前後開發端溝通的成本,因為讓兩邊對於「資料」與「行為」擁有了相同的畫面,才去做討論實作。

因此,一個好的 schema,同時也是實際去針對功能本身的行為去設計,會拆分的更清楚,在迭代開發新功能時也會帶來比較好的開發者體驗。

5. 漸進式開發,平滑迭代

The schema should be built incrementally based on actual requirements and evolve smoothly over time.

就像是 CI, CD 的過程。當 Schema 被獨立出來之後,我們也希望能夠做連續性的整合與無痛升級,也因為有了抽象化的 Graph 圖形,我們可以針對每次上版去做檢查與測試有無 break change。

6. 注意效能

Performance management should be a continuous, data-driven process, adapting smoothly to changing query loads and service implementations.

一個 Query 撈取所需的資料,這個便利性同時也會帶來效能的影響,現階段也有一些解法 ex: data loader。但作者建議一開始不是去優化使用的過程,而是去檢視所拿的資料是否是真正所需的。

Rather than optimizing every possible use of the graph, the focus should be on supporting the actual query shapes that are needed in production.

並且建議應該要觀察 production 中的每一個 query 效能,在有需要的時候再去優化它即可。

7. 善用 Graph 的每一個特性

Developers should be equipped with rich awareness of the graph throughout the entire development process.

Graph schema 有很多很好的特性幫助我們去確保服務的正確性。

  • 可描述性:你取得的都是你想要的資料,不多也不少
  • 使得資料有分级性
  • 強型別
  • 抽象化資料架構,更好檢視

像是我們可以藉由去比較每一次的改動去了解有沒有 break change 的 graph 或是 api。

以強型別為例,若前端使用 Typescript 開發應用,那麼最好的體驗就是自動產生 type,不用再去重複定義相同的 type。

因此若是我們的開發工具能夠善用語言的特性,會幫助我們得到更好的開發體驗。 → 詳細可以看此處

行為

8. 限制資料的存取

Grant access to the graph on a per-client basis, and manage what and how clients can access it.

因為 graph schema 的緣故,我們除了能夠針對 query 行為做權限限制以外,甚至小到每一個資料欄位來做管控。除了安全性外,權限掌控另外一層很重要的意義是讓伺服器減少不必要的負擔跟危險。

這裡建議四種管控的做法:

  • 針對 query 做出權限控管,讓不信任的 query 無法操作。
  • 如果你的 App 是允許一次性大量 query 操作的,當有一個需求很大量的 query 進來的時候可以設計一個 query approval workflow,在實際去執行之前先去優化它,確保他不會撈到不必要的資料。
  • 針對上述的第二項優化是,在實際執行之前先把他排進 queue ,估算此次 query 的成本與效能影響,並確保 server 可以執行此項操作才執行。
  • 最後是筆者建議開發者應該要設計一道機制,能夠讓開發者去手動關閉某些 app 的部分 queries 全縣。(有點像是限制流量的概念,在緊急時刻確保重要的部分可以被正確執行,而不重要的部分就先關閉它)

9. 有效的 log

Capture structured logs of all graph operations and leverage them as the primary tool for understanding graph usage.

在開發服務的時候,log 一直都是一個很重要的工具幫助我們去了解現在、過去、跟預測未來。

在 GraphQL 中這個行為叫做 trace (包括誰執行了這項操作、做了什麼改變、讀取了哪些欄位、使用哪個功能、在哪一個服務上使用、使否成功、效能如何等等)

思考 trace 與實作是一項很重要的設計,可以幫助你真正檢視你的資料行為是如何被使用:

  • 了解是否有不再使用的資料欄位,或者若還有服務在使用它,它的重要程度是如何
  • 預測每一個 query 的 performance, cost, time
  • 自動檢查本身問題(ex: latency or error rates…)
  • 藉由 trace 去強化大量使用的 query 性能

10. Separate the GraphQL Layer from the Service Layer

Adopt a layered architecture with data graph functionality broken into a separate tier rather than baked into every service.

在大多數的 production 環境中,client 實際上不會去直接地 touch 到真正的 server。一般中間都還會有好幾層 ex: proxy, load balancing, caching, service location, API key management 諸如此類不同的 layer 在中間。區分出 layer 的好處就是讓各個 layer 專注於自己的事情(視為單一環境),並且更好地 design, scalable,也能夠與真正的 server 分開執行不互相影響。

在 GraphQL 當中也是如此,把 GraphQL 拉出一個 layer(middleware)之類的概念有助於去拆解每一個 data graph functionality,讓它們只專注於跟所需的 service 互動。

延伸閱讀

  • M 大在 GraphQL Summit 2019 的 Keynote

最後,歡迎~~

👇掌聲給他用力拍下去,我們會很開心 ><

--

--