スタディサプリ Product Team Blog

株式会社リクルートが開発するスタディサプリのプロダクトチームのブログです

Jetpack Compose と GraphQL Fragment でつくるデザインシステム実装

こんにちは。Android アプリ開発者の geckour です。
今回は、デザインシステムの実装についての話をしたいと思います。

はじめに

弊チームでは、対象ユーザを中学生に絞った新規の学習サービスを開発しています (先日リリースされました!) 。
以降、記事中で「新規サービスチーム」と言った場合にはこの新規学習サービスを作っているチーム全体を指し、「Android チーム」と言った場合にはその中でも Android アプリの開発を担当しているチームのことを指します。

さて、我々新規サービスチームでは UI パーツの再利用性やサービス全体の UI の統一感の向上などの目的でデザインシステムを策定し、導入しています。
既存のアプリでは長年の開発期間の間にデザインの定義に関連する様々な問題が発生していました。
それらの中にはデザインシステムをうまく定義すれば解消するものも多いのではと思われましたが、すでに存在する膨大なデザインを前に二の足を踏んでいる状況でした。

そこで、ゼロベースでスタートできる新規サービスチームでは、最初からデザインシステムを導入していこうと声が上がりすべての UI デザインに導入されています。

本記事では実際に行ったデザインシステムの定義からその実装方法までを紹介します。

デザインシステム

デザインシステムについて少しだけ説明します。

デザインシステム とは?

デザインシステムとは、ソフトウェアやグラフィックなどにおけるデザインの原則や指針と、それらを実現するための仕組みの集合体です。

(中略)

一般的にデザイン原則にはタイポグラフィ・カラーシステムやボイス&トーンなどが含まれ、仕組みにはコードベースのUIコンポーネントやデザイントークンなどが含まれます。

(引用元: グッドパッチエンジニアが選ぶ、推しデザインシステム10選|Goodpatch Blog グッドパッチブログ)

つまり、デザイナーと開発者の両輪で作り上げていくデザインの定義のことだと捉えています。

新規サービスチームにおけるデザインシステム

新規サービスチームでは、Atomic Design をもとに多少改変を加えたデザインシステムを採用しています。
Atomic Design とは、デザインをその粒度ごとに分解し、再利用しながら構成することでデザインの統一感や効率の向上を図るというものです。

大本の定義では、

Atoms (原子) - Modecules (分子) - Organisums (物体) - Templates (雛形) - Pages (画面)

という 5 段構えの構成が取られているのですが、新規サービスチームでは便宜上

Tokens (最小構成物) - Atoms (原子) - Components (最大構成物)

という 3 段階のものに改変しています。

デザインシステムを定義する

デザインシステムを実際に設計し、上記の 3 段階のものに決定されていくには実際には様々な議論と紆余曲折がありました。

既存アプリにおけるデザインの問題点の洗い出しや、5 段階の構成を実際に当てはめて作ってみるプロトタイピング、そもそも Atomic Design のような考え方が自分たちのやり方とマッチしているのかを再度考えたり…

結局の所、デザインの統一感が最も解決したい課題であったこと、またコンポーネントを定義することによる再利用性など副次的なメリットを考慮しつつ、よりゆるい 3 段階の定義とすることで運用のしやすさとのバランスを取ることになりました。

チームやプロダクトによってフィットするデザインシステムは様々だと思うので、取り入れる際にはデザイナや開発者などをしっかり巻き込んで、みんなで考えると良いと思います。

デザインシステムの実装

ここからは実際のデザインシステムの実装の話をしたいと思います。
余談ですが、新規サービスチームではデザインシステムの実装のことをデザインコンポーネントと呼んでいます。

XML によるデザインシステムの実装

新規アプリでは当初 Jetpack Compose が導入されていなかったので、手始めに XML によるデザインシステムの実装に手を付けました。
Tokens、Atoms、Components を愚直に XML で表現することに挑戦し、検証しました。

XMLカプセル化

XML でデザインコンポーネントを作る際に、Style を利用しようと考えプロトタイピングをしていきました。

しかし、Style はそれ単体でデザインを表現するものではなく、あくまでも実際のレイアウトに適用することで意味を成します。
この制約がデザインシステムの表現をする際にはかなりやりづらい場面があり、作業は難航しました。

具体的には、デザイナの考えた綺麗なコンポーネントの内包関係が Style で表現しきれず、どうしても定義の切れ目とは違った実装になってしまう場面が出てしまいました。

Jetpack Compose によるデザインシステムの実装

時を経て、Android チームにも Jetpack Compose の波が訪れました。

Jetpack Compose でデザインシステムの実装をすることになった際に、XML でやっていた時の反省を踏まえ、きちんと 1 つのコンポーネントにデザインの実装を閉じ込め、利用する際には部品としてそのコンポーネントを埋め込むという思想に統一することで、デザイナーの思想通りのコンポーネントを実装することができています。

宣言的 UI とデザインシステム

さて、Jetpack Compose は宣言的 UI の一派と言われています。
宣言的 UI とは、ざっくりいうと「UI の定義とそれを利用したロジックの定義がかけ離れた場所にない UI の書き方」といったものです。

これを採用することにより、UI のまとまりが追いやすくなり、見通しが良くなります。
また、UI に関連する実装がまとまることで、前述の XML の際のような実装の分断が起こりにくく、コンポーネント実装が容易になります。

GraphQL

新規サービスチームではサーバとの通信に GraphQL を採用しています (詳しくは こちらの記事 をご覧ください) 。
そして、GraphQL を活用する上で、上の記事中にも出てくる Fragment による Colocation が重要になってきます。

Colocation とデザインシステム

Colocation の詳細については記事を参照してもらうとして、言わずもがなですが Colocation とコンポーネント化を前提としたデザインシステムが如何に相性が良いかという小話をしておきたいと思います。

Colocation とは UI にとって必要なデータを Fragment として UI と近い場所にまとめておき利用する、というやり方だと理解しています。
これを、デザインコンポーネントが整備された世界線に持ち込むと、非常にきれいにハマってくれます。

Jetpack Compose で説明すると、関数の引数に Fragment として必要なデータを取り、関数内部でデザインにデータを当ててあげれば良いわけです。

ドメインモデルを作るまでもなく、ほしいデータをほしい形で手に入れて、そのまま UI に渡してあげるという GraphQL らしいことが実現できます。

Fragment にまとめることで、特に Apollo Android を使って data class を生成している場合などにはデザインコンポーネントの再利用性の向上にも役立ちます。

@Composable
fun Person(fragment: PersonFragment) {
    Column {
        Text(text = fragment.name)
        Divider()
        PersonDetail(fragment.detailFragment)
        ...
    }
}

@Composable
fun PersonDetail(fragment: PersonDetailFrgament) {
    Row {
        Text(text = framgent.age)
        Text(text = fragment.height)
        Text(text = fragment.weight)
    }
    ...
}

このあたりに関しては、 Quramy さんの記事 が詳しいです。

Jetpack Compose とマテリアルデザイン

ところで、Jetpack Compose はマテリアルデザインを前提として作られています。
すなわち、マテリアルデザインというデザインシステムに最適化されているということです。

では、Jetpack Compose を利用するからには我々はマテリアルデザインを踏襲したデザインシステムを定義する必要があるということでしょうか?

私は答えは否だと思っています。
マテリアルデザインの枠組みは一旦無視しても Jetpack Compose で UI を組んでいくことはできますし、最低限必要な部分についてのみ opt-in することも可能だからです。

なので、臆することなくまずはプロトタイピングから始めると良いのかなと思います。

おわりに

デザインシステムを適切に定義することで、アプリ全体のデザインの統一感やデザイン定義の再利用性が上がること、また Jetpack Compose や GraphQL Fragment と組み合わせることで更に快適な開発が可能になることをお伝えしました。

皆さんのプロダクトで取り入れられているデザインへの取り組みも紹介していただけると嬉しいです。

それでは!


私達のチームでは、一緒に最高のプロダクトを作っていってくれる仲間を募集しています。
もし少しでもご興味ありましたら こちら のページを御覧ください!

ご連絡をお待ちしています!