仕組みから学ぶ Web
応用読了目安 15 分#React#コンポーネント設計#共通化#合成#凝集度

コンポーネントをどう分けるか — 見た目が同じでも、変わる理由が違えば別の部品

共通の商品カードは、1 年で引数が 23 個になった。ある画面の修正で、別の画面のカードが崩れた。似ているものをまとめた部品は、変わる理由の数だけ分岐を抱える。

この記事の進み方

What — 何を共通にして、何を分けるか

凝集度と結合度で見たとおり、まとめてよいかの基準は同じ理由で同時に変わるかです。画面の部品では、これが特に見誤りやすくなります。見た目が似ていると、変わる理由も同じに見えるからです。

部品には、変わる理由の違う 2 つの層があります。

層例変わる理由共通にしてよいか
見た目の部品ボタン、カードの枠、価格の表示形式、バッジデザインの決まりよい。全画面で揃っているべき
業務の部品一覧の商品カード、セールの商品カードその画面の目的慎重に。画面ごとに変わる

冒頭の ProductCard は、業務の部品を 1 つにまとめたものでした。一覧は「比べて選ぶ」、セールは「急いで買わせる」、お気に入りは「あとで買う物を見直す」。目的が違うので、足したい表示も画面ごとに違い、そのたびに引数が増えました。

Compare3 画面のカードを、どう作るか

共通の商品カードを 1 つ作り、違いは引数で切り替える。

ProductCard(引数 23 個)
├ 一覧
├ セール
└ お気に入り

変更 1 つ → 3 画面すべてに影響
最初に書く量
少ない
1 年後の分岐
400 行
変更の影響
全画面
デザインの統一
—
  • –引数が増えるたびに、組み合わせは掛け算で増える。どの組み合わせが使われているか誰も分からなくなる。
  • –冒頭の事故はこれ。

同じ見た目から出発しても、分け方で 1 年後の姿が変わる。

引数で切り替えるより、中身を差し込む

共通の部品が必要なとき、違いを引数(フラグ)で切り替えると、組み合わせが掛け算で増えます。代わりに、違う部分を外から差し込める形にする方法があります。

// 引数で切り替える: 足したい表示のたびに引数が増える
<Card showPrice showBadge isSale saleEndsAt={end} />

// 中身を差し込む: カードは枠だけを持ち、中身は使う側が決める
<Card>
  <ProductImage src={p.image} />
  <Price value={p.price} was={p.listPrice} />
  <SaleCountdown endsAt={end} />
</Card>

これを合成(composition)と呼びます。カードは「枠と余白」だけを知り、何を入れるかは使う側が決めます。セール画面が残り時間を足しても、カードにもほかの画面にも触れません。

確認 — ここまで読めたか

次のうち、全画面で共通の部品にしてよいのはどれですか?

まず選ぶ(解答例は a〜d の記号で説明します)

状態と取得を持つ部品、持たない部品

もう 1 つの分け方は、状態やデータの取得を持つかどうかです。

  • 持たない部品: 受け取った値を描くだけ。同じ値なら同じ見た目になる。どの画面でも使え、見本の画面やテストで扱いやすい
  • 持つ部品: データを取り、状態を管理し、持たない部品に値を渡す。画面ごとに 1 つずつ

見た目の部品は、ほとんどが「持たない部品」です。データをどこで取るかで見た「取ることと描くことを分ける」は、この分け方と同じ形です。そして状態を持つ部品を小さく、使う場所の近くに置くと、描き直される範囲も狭くなります。

Why — なぜ業務の部品をまとめてしまうのか

見た目の一致は、今だけの偶然

立ち上げのとき、3 画面のカードは本当に同じ見た目でした。まとめるのは自然な判断です。ただ、同じだったのはデザインの初期値であって、画面の目的ではありませんでした。目的が違うものは、時間とともに違う方向へ変わります。

判断するときは、見た目ではなく、誰がどんな理由で変更を頼んでくるかを見ます。一覧の改善を頼むのは検索の担当、セールを頼むのは販促の担当。頼む人が違えば、変わる理由も違います。

引数を足すのが、いちばん楽に見える

共通の部品に新しい表示が要るとき、選択肢は「引数を 1 つ足す」か「部品を分ける」かです。引数を足すほうが、その場の変更は小さく済みます。1 回ずつは正しい小さな判断が、23 回積み重なって 400 行の分岐になります。

分け直すのは、まとめるより難しい

まとめた部品を分けるには、どの画面がどの引数の組み合わせを使っているかを全部調べる必要があります。まとめるのは 1 日でも、分けるのは数週間かかります。だから、まとめる判断は遅めにします。3 回同じものが出てきて、変わる理由も同じだと確かめてからで間に合います。

確認 — ここまで読めたか

共通のカードに、ある画面のためだけの表示を足したいと頼まれました。最初に考えるべきことはどれですか?

まず選ぶ(解答例は a〜d の記号で説明します)

演習 — まず自分で判断する

解説を読む前に、まず自分で判断してみてください。ここで一度詰まっておくと、 次の節の判断軸が「なるほど」ではなく「そう来たか」に変わります。

演習 — 設計判断を問う

引数 23 個の ProductCard を、どう直しますか?

与えられた条件
  • 一覧・検索・セール・お気に入り・管理画面の 5 か所で使われている
  • 引数は 23 個。中は組み合わせによる分岐で 400 行
  • 価格の書式、画像の縦横比、角の丸みは、全画面で揃っているべきと決まっている
  • フロントエンドは 3 人。来月にセール画面の大きな改修が予定されている
この軸で考える
  • · 変わる理由は、画面ごとに違うか、全画面で同じか
  • · 全画面で揃えるべきデザインの決まりを、どこに残すか
  • · 来月の改修の前に、どこまで分けるか
まず選ぶ(解答例は a〜d の記号で説明します)

演習 — 説明できるか

「同じ見た目のカードが 3 画面にあるなら、1 つの部品にまとめるべきだ」と言うレビュアーに、まとめない理由を説明してください

与えられた条件
  • 相手は重複を減らすことを大事にしていて、その考え自体は正しい
  • 3 画面のカードは、今は同じ見た目だが、使っている画面の目的は違う
  • 価格の書式など、共通にしている部分もある

読み終わりましたか?

読了にすると、これを前提とする記事がロードマップで開放されます。