儘管名為GraphQL,但它並不是一種簡單的查詢語言。這是一個全面解決現代應用與雲服務之間連接問題的方案。因此,它構成了現代應用程式開發堆棧中一個新的重要層的基礎:數據圖。這個新層將公司的所有應用程式數據和服務集中在一個地方,具有一致的、安全的、易用的介面,這樣任何人都可以在最小的摩擦下使用它。
在Apollo,我們從2015年就開始構建行業領先的數據圖技術,我們估計我們的軟體現在在超過90%的GraphQL實現中使用。多年來,我們與各種規模的公司中實現GraphQL的開發人員進行了數千次對話。我們希望分享我們所學到的知識,因此我們將他們的經驗提煉為一組創建、維護和操作數據圖的最佳實踐。我們在這裡將它們以10個GraphQL原則的形式呈現,分為三類,其格式受到了Twelve Factor應用程式的啟發。
完整性原則
確保圖定義良好、穩定且一致
1. 一個圖
您的公司應該有一個統一的圖表,而不是由每個團隊創建的多個圖表。
通過一個圖形,你可以最大化GraphQL的價值:
- 可以通過一個查詢訪問更多的數據和服務
- 代碼、查詢、技能和經驗可以跨團隊移植
- 所有圖形用戶都可以查看的所有可用數據的中心目錄
- 實現成本最小化,因為圖形實現工作不重複
- 圖的中央管理——例如,統一的訪問控制策略——成為可能
當團隊在沒有協調工作的情況下創建他們自己的圖表時,他們的圖表幾乎不可避免地會開始重疊,以不兼容的方式向圖表添加相同的數據。在最好的情況下,這是昂貴的返工;在最壞的情況下,它會造成混亂。在公司的數據圖採用過程中,應該儘可能早地遵循這一原則。
2. 聯合實施
儘管只有一個圖,但該圖的實現應該跨多個團隊聯合。
如果沒有高度專門化的基礎設施,單片架構很難擴展,數據圖也不例外。與在單個代碼庫中實現組織的整個數據圖層不同,定義和實現圖的責任應該劃分到多個團隊中。每個團隊都應該負責維護公開他們的數據和服務的模式部分,同時擁有獨立開發和在他們自己的發布周期上操作的靈活性。
這維護了圖的單一、統一視圖的價值,同時保持了整個公司的開發工作的分離。
3.跟蹤註冊表中的模式
應該有一個單一的事實來源來記錄和跟蹤圖表。
就像在版本控制系統中跟蹤原始碼很重要一樣,在模式註冊表中跟蹤圖形的定義也很重要。您的公司應該有一個模式註冊表,它是圖形的權威定義,而不是依賴於當前正在運行的進程或在開發人員的筆記本上檢入的任何代碼。像一個原始碼控制系統,註冊表的模式存儲修改圖,誰讓他們的歷史,它應該理解圖像的多個版本的概念(例如,登台和生產,或不同的開發分支)的方式相似的軟體開發過程。
模式註冊中心應該成為系統的中心,為開發人員工具、工作流或任何業務流程提供支持,這些業務流程將受益於對數據圖的感知,以及對數據圖的任何實際或建議的更改。
敏捷原則
快速展開圖形並不斷調整它以適應不斷變化的需求
4. 抽象的,需求模式法
模式應該作為一個抽象層,為使用者提供靈活性,同時隱藏服務實現細節。
GraphQL的很大一部分價值在於提供了服務和使用者之間的抽象,因此該模式不應該與特定的服務實現或特定的使用者緊密耦合,因為它們現在已經存在了。通過將實現細節排除在模式之外,應該可以重構實現圖的服務——例如,從一個整體轉換到微服務,或者改變服務實現的語言——而不影響該領域的應用程式。同樣,模式不應該與特定應用程式獲取數據的方式緊密耦合。如果新應用程式的功能與現有的應用程式類似,那麼應該可以編寫新應用程式,而對圖形的修改應該最小。
要實現這一點,可以使用面向需求的模式的標準:該模式側重於為應用程式開發人員提供良好的開發體驗,並根據現有圖構建新功能。以這個標準為目標將有助於防止圖與將來可能更改的服務實現耦合,並有助於增加添加到圖中的每個欄位的重用價值。
5. 使用敏捷方法進行模式開發
模式應該根據實際需求逐步構建,並隨著時間的推移平穩地演進。
提前定義組織所有數據的「完美模式」可能很有誘惑力。相反,真正使模式有價值的是它遵循實際用戶需求的程度,而這些需求從來都不是預先完全知道的,並且是不斷變化的。實現「完美模式」的真正途徑是使圖易於根據實際需要進行演化。
不應該推測性地將欄位添加到模式中。理想情況下,每個欄位應該只在響應消費者對附加功能的具體需求時添加,而設計的目的是最大限度地讓其他有類似需求的消費者重用。
更新圖形應該是一個連續的過程。與其每隔6個月或12個月發布一個新的圖形「版本」,不如在必要時每天多次更改圖形。可以隨時添加新欄位。要刪除欄位,首先要棄用它,然後在沒有使用者使用它時刪除它。模式註冊表支持圖形的這種敏捷演化,以及使每個人都知道可能影響他們的更改的流程和工具。這確保了只有完全審查過的變更才能投入生產。
6. 疊代地提高性能
性能管理應該是一個連續的、數據驅動的過程,能夠平穩地適應不斷變化的查詢負載和服務實現。
數據圖層是討論服務團隊和使用其服務的應用程式開發人員之間的性能和容量的最佳位置。這個對話應該是一個持續的過程,它使服務開發人員能夠持續地、主動地了解消費者打算用他們的服務做什麼。
與其優化圖形的每一種可能的用法,不如將重點放在支持生產中所需的實際查詢形狀上。工具應該提取提議的新查詢形狀,並在它們投入生產之前將它們呈現給所有受影響的服務團隊,這些團隊具有延遲需求和預計的查詢量。一旦查詢進入生產環境,就應該持續監視它的性能。如果遵循這一原則,那麼很容易將問題追溯到行為不符合預期的服務。
7. 使用圖形元數據來增強開發人員的能力
開發人員應該在整個開發過程中對圖形有豐富的認識。
GraphQL的主要價值在於它為開發人員提供了巨大的生產力提升。為了最大限度地提高性能,開發人員的工具應該讓他們對數據圖有普遍的認識,並貫穿於他們在整個開發生命周期中使用的所有工具。
每當開發人員進行與管理數據或連接到服務相關的工作時,他們的工具應該將關於圖的實時信息放在手邊。這些信息應該是最新的,工具應該是高度智能的,以有用和強大的方式將圖形感知應用到當前的情況。如果處理得當,不僅會提高開發人員的工作效率和幸福感,而且GraphQL還會成為連接前端和後端團隊的紐帶,在整個開發生命周期中實現無縫對話。
一些數據圖形感知工具的功能的實際例子包括:
- 開發人員可以在他們的編輯器中享受所有可用圖形數據和服務的實時文檔,而且總是最新的。
- 有關廢棄欄位的信息可以傳播到使用這些欄位的開發人員的編輯器中,並提供建議的替代方案
- 根據實時生產數據,在開發人員輸入查詢時,可以向他們顯示查詢的估計成本(以延遲或伺服器資源計算)。
- 運維團隊可以跟蹤後端服務的負載,將其追溯到特定的應用程式、版本、功能,甚至代碼行,從而全面了解開發人員如何使用其服務。
- 當服務開發人員對其模式進行更改時,可以作為持續集成過程的一部分自動確定更改的影響。如果更改會破壞現有的客戶機(根據重播最近的生產使用情況確定),那麼服務開發人員可以確定將受到影響的精確客戶機、版本和開發人員。
- 當應用程式開發人員構建特性時,可以從他們的代碼中提取支持這些特性的新查詢,並與操作團隊共享。有了這種認識,操作團隊就可以提前提供所需的能力,並在開發過程的早期介入,如果查詢不能在預期的範圍內得到批准的話。
- 當應用程式是用類型化語言(如TypeScript、Java或Swift)開發的時候,類型信息可以從服務類型聲明一直傳播到應用程式的每一行代碼,從而確保全堆棧類型的正確性和對錯誤的即時反饋。
操作原則
安全地將圖部署到大規模生產環境中
8. 存取和需求控制
在每個客戶端基礎上授予對圖形的訪問權,並管理客戶端可以訪問什麼以及如何訪問它。
數據圖中的授權具有兩個同樣重要的方面:訪問控制和需求控制,前者表示允許用戶訪問哪些對象和欄位,後者表示允許用戶如何(以及多少)訪問這些資源。雖然經常討論訪問控制,但也需要注意需求控制,因為它在GraphQL的任何生產部署中都是至關重要的。允許用戶不考慮成本執行任何可能的查詢是錯誤的,因為用戶沒有能力管理它對生產系統的影響。訪問和需求控制都必須在充分了解數據圖的語義和性能的情況下執行。在不分析實際發送的查詢的情況下,僅將用戶限制在每分鐘特定的查詢數量是不夠的,因為查詢可以訪問大量的服務,而且查詢的成本可以在多個數量級上變化。
驗證在數據圖也有兩個方面:請求操作的應用程式,並使用這個應用程式的人。雖然訪問控制中心的人使用應用程式,適當的需求控制至少取決於每個應用控制人均控制,應用程式的開發人員,而不是應用程式的用戶負責應用程式所使用的特定查詢的形狀做它的工作。
控制需求的最佳方法包括:
- 當不受信任的用戶訪問生產系統時,他們應該只發送由經過驗證的應用程式開發人員預先註冊的查詢,而不是允許他們使用應用程式的憑據發送任意查詢。對於只分發給可信用戶的內部應用程式來說,這有時並不嚴格。
- 對於預計將發送大量查詢的應用程式,團隊應該設計一個與更廣泛的軟體開發周期相一致的查詢審批工作流,以便在查詢進入生產之前對其進行審查。這可以確保它們不會獲取不必要的數據,並且伺服器的容量可以支持它們。
- 作為第二道防線,在執行查詢之前估計它的成本,並為每個用戶和每個應用程式制定查詢成本預算,可以防止過度使用預先註冊的操作,或者在無法進行預先註冊的操作的情況下。
- 開發人員應該能夠禁用特定應用程式在生產環境中發送特定查詢的能力,無論是作為緊急情況下的安全網,還是發現第三方應用程式以不可接受的方式使用數據圖。
9. 結構化的日誌
捕獲所有圖形操作的結構化日誌,並利用它們作為了解圖形用法的主要工具。
可以捕獲關於在圖上執行的每個操作(讀或寫)的大量信息:哪些用戶和應用程式執行了該操作、訪問了哪些欄位、實際執行操作的方式、如何執行操作,等等。這些資料非常寶貴,應當有系統地加以收集,供以後使用。它應該以結構化的、機器可讀的格式捕獲,而不是文本日誌,這樣就可以為儘可能多的目的利用它。
圖形操作的記錄稱為跟蹤。跟蹤應該召集所有相關信息關於一個操作在一個地方,包括業務信息(誰做了手術,訪問或改變,哪些功能的應用程式由哪些開發人員,是否成功,如何執行)和純技術信息(後端服務聯繫,每個服務如何導致延遲,是否使用緩存)。
因為跟蹤真正地捕獲了一個圖是如何被使用的,它們可以被用於廣泛的用途:
- 了解是否可以刪除廢棄欄位,或者是否可以刪除仍在訪問它的特定客戶端,以及它們的重要性
- 根據實時的生產數據,實時地預測一個查詢需要多長時間執行,因為開發人員正在他們的IDE中輸入查詢
- 自動檢測生產中的問題(如增加的延遲或錯誤率)並診斷其根本原因
- 提供權威的審計跟蹤,顯示哪些用戶訪問了特定的記錄
- 為商業智能查詢提供支持(當天氣炎熱時,人們會在自己所在的地方更頻繁地搜索冰激凌嗎?)
- 根據API使用情況為合作夥伴生成發票,可以根據訪問的特定欄位或消耗的資源創建詳細的成本模型
所有圖形操作的跟蹤應該集中在一個中心位置,這樣就有了一個權威的跟蹤流。然後,這個流可以通過管道進入其他可觀察性系統(可能在對不支持graphql的現有系統進行簡單轉換之後),或者存儲在一個或多個數據倉庫中供以後使用(根據預算、用例和規模的需要進行匯總和取樣)。
10. 將GraphQL層與服務層分離
採用分層架構,將數據圖功能分解為單獨的層,而不是整合到每個服務中。
在大多數API技術中,客戶機不直接與伺服器通信,除非在開發中。取而代之的是一種分層的方法,其中將一些問題(如負載平衡、緩存、服務位置或API密鑰管理)分解為單獨的一層。然後,可以將此層與後端服務分開設計、操作和伸縮。
GraphQL也不例外。與其將一個完整的數據圖系統所需的所有功能都放到每個服務中,不如將大多數數據圖功能分解成位於客戶端和服務之間的獨立層,讓每個服務專注於服務於實際的客戶端請求。這一層可以由多個進程組成,執行訪問和需求控制、聯合、跟蹤收集和潛在的緩存等功能。這一層的某些部分是特定於graphql的,需要深入了解數據圖,而負載平衡和客戶端身份驗證等其他功能可能由現有系統來執行。
即使在只有一個應用程式和一個服務的簡單場景中,這個單獨的層也是有價值的;否則,屬於中間層的功能必須在伺服器中實現。在複雜的應用程式中,這一層可能開始看起來像一個地理上分布的系統:通過多個入口點接收傳入的查詢,處理其中一些在網絡的邊緣邊緣緩存的好處,路由子組件查詢多個數據中心的公共雲,民營,或由合作夥伴,最後這些組件組裝成一個查詢結果,同時記錄跟蹤,這是紀念整個操作。
在某些情況下,此數據圖層將使用GraphQL與後端服務通信。但是,最常見的情況是,後端服務保持不變,並繼續被它們現有的api(如REST、SOAP、gRPC、Thrift甚至SQL)訪問,這些api與數據圖對象之間的映射由構成數據圖層一部分的伺服器完成。
原文:https://principledgraphql.com
本文:https://pub.intelligentx.net/application-architecture-principled-graphql
討論:請加入知識星球【首席架構師圈】或者飛聊小組【首席架構師智庫】