SPMでモジュール・コンポーネントを表現
この記事では、Swift Package Manager(SPM)を使い、モジュール・コンポーネントとして表現することでメンテナンス性などを高める手法について説明します。
前の記事をさらに深掘りしました。
モジュール・コンポーネントの定義とSPMでの表現
モジュールとコンポーネントの定義は似ています。モジュールは機能として単体で完結しており単独で使用できるものとし、コンポーネントは単体で完結するが単独では使用しないと定義されています[1]。
SPMで使うために、定義を少し変えます。
- モジュールは機能の1まとまりで、単独で使用できるもの
- コンポーネントはモジュール内に複数あり、細かい機能として完結しているもの
1については、SPMのPackageというクラスに相当し、上位の存在とします。2については、SPMのProductというクラスに相当し、Packageの下位の存在です。SPMの定義として、その下にTargetがあり複数Targetを1つのProductに入れることができますが、依存関係をなるべく複雑にしないために、ProductとTargetは1対1とします。
Package, Product, Targetについてはこちらの公式
サンプルソースコード
複数Productを作る
SPMパッケージの名前として今回はInfra
とします。ここにProduct
とTarget
として、Api
, Store
を追加していきます。
let package = Package(
name: "Infra",
products: [
.library(name: "Api", targets: ["Api"]),
.library(name: "Store", targets: ["Store"])
],
dependencies: [
],
targets: [
.target(name: "Api", dependencies: []),
.target(name: "Store", dependencies: []),
.testTarget(name: "InfraTests", dependencies: ["Api", "Store"]),
]
)
-
targets
で.target
を追加します。例えば.target(name: "Api", dependencies: []),
-
products
に.library
を追加します。例えば.library(name: "Api", targets: ["Api"]),
。
このように定義した場合、 Sources
配下に.target
のname
と同じディレクトリを作成する必要があります。この例ではApi
とStore
です。
その後、適宜クラスを作成していきます。
作成したサンプルではSources
の中の構成は
- Api
- Api.swift
- Store
- DataStore.swift
のようになっています。
Package内のProductを使用する
Domain
PackageでInfra
Package内のTargetを使用してみます。
let package = Package(
name: "Domain",
products: [
.library(name: "Domain", targets: ["Domain"]),
],
dependencies: [
.package(name: "Infra", path: "../Infra")
],
targets: [
.target(
name: "Domain",
dependencies: [
.product(name: "Api", package: "Infra"),
.product(name: "Store", package: "Infra")
]),
.testTarget(
name: "DomainTests",
dependencies: ["Domain"]),
]
)
-
dependencies
に.package
を追加します。ここでは.package(name: "Infra", path: "../Infra")
-
targets
の中のdependencies
にProductを追加していきます。ここでは.product(name: "Api", package: "Infra"),
このようにすることで、Package内のProductごとに依存関係を追加していくことができます。
将来的にはDomain
Package内でProduct
を分けることが出てくることも考えられます。その際、Infra
Package内で必要なProductだけ依存に追加することで、依存関係をよりしっかり管理できるようになります。
考察
SPMを使い、前回よりもさらに複雑な依存関係を表現できました。
サンプルでは、主に水平方向に機能を分割していますが、場合によっては垂直方向に分割した方が良いかもしれません[2]。その際、Package, Productの2つで表現していけば、同様に垂直方向の依存関係も実現できます。
また、今回はProductとTargetは1対1としていますが、モジュールとしてのPackageが多数になった場合などは、Packageを統合、ProductとTargetは1対多となるように依存関係を構成していく可能性もあります。
Discussion