server/priv/docs/zh_Hant/guides/features/projects/tma-architecture.md
TMA 是構建 Apple OS 應用程式的架構方法,可實現可擴展性、優化建立和測試週期,並確保您的團隊有良好的實踐。其核心理念是透過建立獨立的功能來建立您的應用程式,而這些功能則透過清晰簡潔的 API 相互連結。
這些指導方針介紹架構的原則,協助您識別和組織不同層級的應用程式功能。如果您決定使用此架構,它也會介紹提示、工具和建議。
[!NOTE] Μfeatures
此架構之前稱為 µFeatures。我們將其重新命名為 The Modular Architecture (TMA),以更好地反映其目的及其背後的原則。
開發人員應該能夠**,獨立於主應用程式,快速建立、測試並嘗試** 其功能,同時確保 UI 預覽、程式碼完成和除錯等 Xcode 功能可靠運作。
模組代表應用程式功能,是下列五個目標的組合 (其中目標是指 Xcode 目標):
我們建議您遵循目標的命名慣例,由於 Tuist 的 DSL,您可以在專案中強制執行。
| 目標 | 依賴 | 內容 |
|---|---|---|
特點 | 功能介面 | 原始碼與資源 |
功能介面 | - | 公共介面與模型 |
功能測試 | 功能,功能測試 | 單元與整合測試 |
功能測試 | 功能介面 | 測試資料和模擬 |
功能範例 | 功能測試,功能 | 應用範例 |
[!TIP] Ui Previews
功能可以使用FeatureTesting作為開發資產,以允許 UI 預覽
[!WARNING] Compiler Directives Instead Of Testing Targets
另外,您也可以在編譯
Debug時,使用編譯器指令在Feature或FeatureInterface目標中包含測試資料和模組。您可以簡化圖形,但最終您會編譯出執行應用程式時不需要的程式碼。
當所有的應用程式原始碼都存放在相同的目標中時,很容易在程式碼中建立隱含的依賴關係,結果就是眾所皆知的意大利麵條程式碼。所有東西都是強連結的、狀態有時是不可預測的,而且引進新的變更會變成一場惡夢。當我們在獨立目標中定義功能時,我們需要設計公共 API 作為功能實作的一部分。我們需要決定什麼應該是公開的,我們的功能應該如何被使用,什麼應該保持私有。我們對於希望功能客戶端如何使用功能有更多的控制權,而且我們可以透過設計安全的 API 來強制執行良好的實作。
分而治之。以小模組的方式工作,可以讓您更專注,並獨立測試和嘗試功能。此外,由於我們的編譯更具選擇性,只編譯功能運作所需的元件,因此開發週期更快。只有在工作最後,需要將功能整合到應用程式時,才需要編譯整個應用程式。
我們鼓勵您使用框架或函式庫,在應用程式和其他產品(例如擴充套件)之間重複使用程式碼。透過建立模組來重複使用是相當直接的。我們只要結合現有的模組,並加入_(必要時)_ 平台特定的 UI 層,就能建立 iMessage 延伸、Today 延伸或 watchOS 應用程式。
當一個模組依賴於另一個模組時,它會宣告對其介面目標的依賴。這樣做有兩方面的好處。它可以防止一個模組的實作與另一個模組的實作耦合,而且可以加快簡潔的建置速度,因為他們只需要編譯我們功能的實作,以及直接和反式依賴的介面。這個方法的靈感來自 SwiftRock Reducing iOS Build Times by Using Interface Modules 的想法。
依賴介面需要應用程式在執行時建立實作圖形,並依賴注入到需要的模組中。雖然 TMA 對於如何做到這一點不持主見,但我們建議使用依賴注入解決方案或模式,或是不增加建置時間間接或使用非為此目的而設計的平台 API 的解決方案。
在建立模組時,您可以選擇函式庫和框架 ,以及靜態和動態連結 作為目標。如果沒有 Tuist,做出這個決定會比較複雜,因為您需要手動設定相依圖。不過,有了 Tuist Projects,這不再是問題。
我們建議在開發過程中使用動態函式庫或框架,使用 <LocalizedLink href="/guides/features/projects/synthesized-files#bundle-accessors">bundle accessors</LocalizedLink> 來將 bundle 存取邏輯與目標函式庫或框架的性質分離。這是快速編譯和確保 SwiftUI 預覽可靠運作的關鍵。而釋出版本建置的靜態函式庫或框架,則可確保應用程式快速啟動。您可以利用 <LocalizedLink href="/guides/features/projects/dynamic-configuration#configuration-through-environment-variables"> 動態配置</LocalizedLink>,在產生時變更產品類型:
# You'll have to read the value of the variable from the manifest {#youll-have-to-read-the-value-of-the-variable-from-the-manifest}
# and use it to change the linking type {#and-use-it-to-change-the-linking-type}
TUIST_PRODUCT_TYPE=static-library tuist generate
// You can place this in your manifest files or helpers
// and use the returned value when instantiating targets.
func productType() -> Product {
if case let .string(productType) = Environment.productType {
return productType == "static-library" ? .staticLibrary : .framework
} else {
return .framework
}
}
[!WARNING] Mergeable Libraries
Apple 嘗試透過引入 mergeable libraries 來減輕在靜態與動態函式庫之間切換的麻煩。然而,這會引進建立時的非決定性,使得您的建立不可重複,而且更難優化,因此我們不建議使用。
TMA 對於您模組的程式碼架構和模式不持任何意見。不過,我們想根據我們的經驗分享一些提示: