はじめに
この記事はand factory.inc Advent Calendar 2023 3日目の記事です。
昨日は @hagmon さんの「Adjust友達紹介プログラムのTips」でした。
現在、担当している既存アプリでUIをデザインシステム化しているのですが、
iOSエンジニアとして対応していることを備忘がてら記事にしたいと思います。
なにを書くか
- 書くこと
- デザインシステム化するうえでの対応したこと
- デザイントークンをiOSプロジェクトに組み込む大枠の流れ
- コンポーネント化の取り組みについて
- やってみての所感
- デザインシステム化するうえでの対応したこと
- 書かないこと
- デザインシステムの詳細な説明
- iOSに組み込むための詳細な変換処理の実装(
json
→xcassets
)
デザインシステムとは
詳細は割愛しますが、ChatGPTに聞いた内容をおいておきます。
簡潔に言うと、一貫性のあるUIを実現するための仕組み、という感じでしょうか。
また、その実現方法の一つとしてデザイントークンという概念があります
参考: デザイントークンって何?|seya
なにをしたか
デザイナーが作ったガイドラインやコンポーネントを実プロジェクトに反映させるわけですが、
具体的なエンジニアリング作業としては、以下のことを行っています
- カラー定義のデザイントークンへの追従
- 一気に変えるのではなく、とりあえず第一弾としてカラー定義の追従を行っています
- 将来的に opacity,spacing,font なども適応したい
- 一気に変えるのではなく、とりあえず第一弾としてカラー定義の追従を行っています
- コンポーネント定義をデザインシステムに揃える
- アプリで使うボタン、リスト、タグなどUI要素の定義
デザイントークン自体は、あくまでデザインシステムの一部(実現するための手段)という位置づけですが、
基本的な設計を詳細な実装に落とし込むエンジニア視点では、方法論であるデザイントークンについての話がメインになります
デザイントークンへの追従
既存プロジェクトに導入するとなると、固定値などで設定されてる値をすべて差し替える必要があるので、どこまでトークン化するのか、というのが問題になると思います。
以下の理由で今回はカラーのみ
対応することにしました。
- 私が担当しているアプリはゴリゴリxibやstoryboardを使っていたが、AssetCatalogを利用することでxib上の定義にも手がつけやすかった
- fontなどはカラーの定義自体は変わることはそこまでないはずなので、変更頻度の観点で恩恵の高いカラーを選んだ
デザイントークンをiOSプロジェクトへ反映させるまでの流れ
大枠の流れは以下のようになっています。
大元のトークンはFigmaのLocal Variablesによって管理しています。
元々はTokens Studio for Figma (旧Figma Tokens)を使う計画でしたが、
今年Figma公式の新機能としてLocal Variablesが提供されたことでデザイナーの意向でそちらを使用することにしました。
下記のような使用感でトークンを管理することができます。
これをFigmaのプラグインであるVariables Import ExportによってJSONでexportします。
そして、このJSONファイルを形式をxcassetsに変換します。
xcassetsは
Colors.xcassets/
├── sysColorPrimary.colorset/
│ └── Contents.json
└── sysColorSecondary.colorset/
└── Contents.json
といった形式のファイル郡であり、その実態はContents.jsonファイルで表現されるので、その形に変換することで実現します。
ここも詳細は割愛しますが、弊社では規定のフォーマットのJSONをxcassets形式にパースするPythonツールが存在するので、そちらを利用してxcassets形式に変換しています。
これらの過程を経てデザイントークンからiOSで利用するxcassets形式に変換をします。
なお、デザイントークンの段階ではよしなに変数化されているため、トークンの参照関係を含んでいますが、xcassets段階では定義 → 値 といった形で参照関係を含まない形になっています。
xib・コードへの反映方法
xib・storyboardへの反映
xcassets形式のファイル郡をAssets Catalogにいれれば簡単に呼び出せるので、
今までCustomなどで入れていた色定義をデザイントークンに置き換えます。
コードへの反映
SwiftGenを使ってxcassetsからSwiftで扱えるコードに変換して使用しました。
命名など定義が変わったときは必ずSwiftGenの自動生成を再度行わなければなりません
SwiftGenの自動生成コードは最終的にはベタ文言でAssets Catalogの定義を呼び出すので、自動生成コード側とのバージョンに差分があるとクラッシュします
検討してやめたこと
ここはgrepなどによる一括置換も検討しましたが、
以下の理由で諦めて一つ一つ地道に人の手でやることにしました。
- 置き換え前のカラー定義が一つになっていると限らない
- beforeの段階でCustomで指定してしまっているので、一意に定まることを保証できない
- (どちらかというとxib・Storyboardだからだが)一気に変えたときに変更管理が難しい
コンポーネント化の取り組み
デザインシステム化の取り組みの中でデザインのコンポーネントの単位が確立されたので、それをアプリにも落とし込む作業を行いました。
が、これがなかなかつらかった(つらい)です。
もともと既存のコードは、
- コンポーネントという単位が確立されていなかったので、共通化の粒度がバラバラ
- 変わりうるものと変わりにくいものの定義がデザインとあっていなかったので、共通化がしづらい
- 結果コピペの類似のViewが大量に生成される
- 変わりうるものと変わりにくいものの定義がデザインとあっていなかったので、共通化がしづらい
- 長年の運用の間に大元のデザインが変更されており、デザインとコードがあっていないことが散見される
- デザイン側も担当者の変更やデザインツール(Sketch→Figma)の変更によりルールがだんだん曖昧になっていった
という状態だったので、デザイントークンを反映しつつ、
古いコードを刷新して、新しいデザインシステムに則ってコンポーネント粒度に揃える
ということをしていきました。
この作業が入ることによって単純に物量が膨大になりました。
技術的に記事としてかけることはそんなにないんですが、主に以下のようなことを考えながら対応していきました。
リリース計画
- 一気にリリースするのではなく、修正したところからリリースする
- 画面単位でコンポーネント化をすすめる
- 画面A・画面Bで同じコンポーネントを使っていても、リリース途中では画面Aのみに新しいコンポーネント定義が適用される、という状況が発生する
- リリース途中で微妙にUIが変わってしまうこともあるが、そこは一時的なものとして妥協する
- コンポーネントを一気に反映していくと影響箇所が芋づる式に膨らんでしまうが、それは避けたかった
- 画面単位でコンポーネント化をすすめる
実装上注意したこと
- 極力Figmaの表現にあわせる
- 同名のコンポーネントでVariableでパターンが表現されている箇所はenumで実装して、同じまとまりとして表現する
- とはいえ、エンジニアの観点からするとまとまりの粒度に違和感ある箇所が発生するので都度デザイナーと相談する
やってみての所感
- 変更しやすいUI体系になる
- 今までは似たパーツの実装がいくつもあったので、デザイン仕様が変わったときに変更漏れが起きやすかった
- そもそものデザインシステムの目的の一つですが、変わりうるところと変わりにくいところをデザイン仕様レベルで定義することができ、それを実装する中で実感した
- デザインを共通言語で議論できるようになる
- 直感的・センスによるものとしてデザイナーに投げるのでなく、それぞれの役割を意識して議論できるようになる
- Viewまわりの実装を整理できる
- デザイン上の実装漏れの部分
- コンポーネント化が伴ったことで実装がかなり大変
- 既存のデザインを流用するので1からとまでは言わないが、当初想定したよりも整理し直す上でかなりの実装量になった
- ただし今後の運用コストの軽減と技術的負債の解消を考えると必要経費でもあった
最後に
デザインシステム化するにあたって仕組みの部分をベースに対応したことをまとめました。
文章が多くなってしまいましたが、最後まで読んでいただきありがとうございました。
今後長年運用を考えるとデザインの次元から共通言語で管理できるようになることは大きな恩恵を得られると思います。
新しい内容があったかはわかりませんが、誰かの参考になればと思います。