見出し画像

SwiftUIでコンポーネントをどう設計するか

最近は仕事でSwiftUIを使う機会が増えてきました。また1からiOSアプリ開発を学び直している感覚があり、楽しさもあるけど難しさも感じます。

SwiftUIではこれまでと比べてUIコンポーネントがつくりやすくなりました(詳細は後述)。それによって、自分もようやくコンポーネントあるあるな課題(粒度は? どう分割する?)に直面しました。まだベストプラクティスは見つかってないのですが、試行錯誤している内容を書いてみます。

はじめに

コンポーネントは3つの要素を含みます。

・構造
・見た目
・振る舞い

昔はコンポーネントという単位が重要視されてなかったのか、Web開発でもiOSアプリ開発でも、3つの要素をバラバラに実装していました。

画像1

Web開発ではReactの登場によって、これらを1つのコンポーネントとしてまとめて実装できるようになり、コンポーネント単位での開発が容易になりました。iOS開発でもSwiftUIの登場によって、ようやくそれを実現しやすくなりました。

コンポーネントの分類

コンポーネントの分類というとAtomic Designが有名です。

画像2

ですが、何がMoleculesで何がOrganismsかを区別するのは難しく、個人的には全部「コンポーネント」で良いのではと考えてます。以下はすべてコンポーネントです。

画像3

CookingSlotRowのように「横スワイプでページングできる」振る舞いをもったコンポーネントもあれば、CookingSlotPageのように複数のコンポーネントをレイアウトしただけで振る舞いを持たないコンポーネントもあります。

コンポーネントの粒度

例えば、塗りで角丸のボタン1つとっても、色やサイズ、状態の違いで以下のようなバリエーションが考えられます。

画像4

これらをどういう粒度でコンポーネントにすればよいでしょうか? デザインファイルと違ってコードでは何でもできてしまうので、1つにまとめることもできれば、別々に分けることもできます。

1つにまとめると、何か変更があったときに修正箇所が1ヶ所で済むのがメリットです。一方で、コンポーネントを利用しているすべての箇所に修正が反映されてしまうので、一部だけ反映したい場合には不便です。特に、UIは変化が激しいし、微妙なバリエーションを増やしたくなりがちです。まとめすぎるとあとで後悔するケースがあります。

試しに、SwiftUIの表現力でどれだけわかりやすく1つのコンポーネントにまとめられるかを探ってみたところ、やっぱりまとめすぎるといまいちでした。

コードの見通しが悪くなる
 ・条件分岐が増えて、宣言的であることのメリットが失われる感じに
 ・がんばって宣言的っぽく書いても行数が長くなり、見通しが悪く
 ・modifierの指定に順序依存が発生する箇所があり、1つにまとめると余計な抽象化が発生
・プレビューが重くなる
・プレビューの一覧性がおちる

参考までにコードはこちらです。

意味によってコンポーネントを分割する

そもそも大きいサイズと小さいサイズを1つのコンポーネントにまとめるのは正しいのでしょうか? 見た目の共通性はありますが、ボタンのもつ意味・使われ方は違いそうです。

大きいサイズであれば、ページ内の主要アクション1つだけに使うボタンとして定義できます(画像左側)が、小さいサイズであれば複数表示したくなりそうです(画像右側)。

スクリーンショット 2021-08-20 9.35.56

このような場合は、別のコンポーネントにしたほうが良いでしょう。

おわりに

コンポーネントの設計について色々考えてみました。正直、他のコンポーネント指向のフレームワークをしっかり使ったこともなければ、SwiftUIもまだ経験が浅いので、知見があれば教えてください🙏

意味によってコンポーネントを分割すると書きましたが、意味を正しく設定するのは難しいです。実際には、コンポーネントが大きくなりすぎない程度(目安としては100行)で分割することを指針にしてもよさそうです。デザインファイルですでにコンポーネント設計がされているなら、それをそのままコードにもってくるというのもありだと思います。

この記事が気に入ったらサポートをしてみませんか?