バックエンドエンジニアがWebフロント開発で学んだ依存関係の問題と解決 


GxP Incで働くソフトウェアエンジニアの高田（[@takada-gxp](https://qiita.com/yTakada-gxp)） です。
本記事は[グロースエクスパートナーズアドベントカレンダー2021](https://qiita.com/advent-calendar/2021/gxp) 3日目の記事です！

普段はバックエンド実装をすることが多い私ですが、近年いくつかのプロジェクトでWebフロントエンドを開発する機会がありました。そこで得たWebフロントエンド開発の肝所、というと大げさですが、気づきを共有したいと思います。

学んだことはいろいろありますが、テーマに選んだのは「**依存関係が大変だ**」ということでした。依存関係といっても、package.jsonのdependenciesのことではなく（これはこれで大変ですが）コンポーネント(関数)の依存関係のことです。ある関数Aの中で別の関数Bを参照している場合、AはBに依存している、と言います。

依存関係の例

```typescript
// displayAlert は wakeUp に依存している
const wakeUp = (name: string): string => `Wake up, ${name} ...`;
const displayAlert = (): void => {
  const messageNode = document.createTextNode(wakeUp('Neo'));
  //...messageNodeを使った何か
}
```

## 依存関係が大変だ、安定性原則違反だ！
開発が進むにつれ、コンポーネント間の依存関係に苦労する機会が何度かありました。
アトミックデザインの考え方を採用していたので、コンポーネントはatoms/moleculesといった単位で再利用されていました。それらの依存されるコンポーネントへの変更が発生すると、依存する側にも影響することがあったのです。影響を避けるために、似たようなコンポーネントをコピペで別に実装されていることも見受けられました。

この問題を言い換えると、「**UXの5段階モデルの表層/骨格を実装するコンポーネントなので頻繁に更新されることが想定されるのに、他コンポーネントから依存されてしまっていてる。安定性原則違反だ！**」ということになると思います。

すこし掘り下げてみましょう。

### 安定依存原則

ソフトウェア設計原則のひとつ。
クリーンシリーズおじさんとして有名なアンクルボブの名著、[アジャイルソフトウェア開発の奥義](https://www.sbcr.jp/product/4797347784/)から引用すると、
> 20.5 安定依存の法則(SDP: Stable Dependencies Principle)
> 安定する方向に依存せよ

かいつまんで説明すると、「たくさん依存されているコンポーネントは安定している。安定していると変更が難しい。なぜなら、変更すると依存しているコンポーネントに影響が出てしまうから」ということになると思います。

### UXの5段階モデル

goodpatchさんのブログに[UXの5段階モデル](https://goodpatch.com/blog/elements-of-ux)の丁寧な解説があります。
> この概念の中ではユーザー体験を構成する要素は5つありそれぞれの要素が段階的に、そして密接に繋がっています。

５段階の要素のうち表層にあたる見た目を実装するコンポーネント、骨格にあたるインタラクションを実装するコンポーネントがatoms/molecluesとして他から依存される、ということは理解してもらいやすいと思います。
もともと、Webフロントエンド開発でSPAを採用するのは、スマホのネイティブアプリのような操作性、データ読み込みの待ち時間を減らし早く応答する、というユーザ体験でのメリットを得たいためです。どういった体験を提供したいのか十分に検討されていない段階で実装し始めてしまうと、後で見つかった要求に応えるための変更が発生することになります。

＊＊＊

さてさて、これは困りました。たくさん依存されていて安定しているはずのコンポーネントが、開発が進んでいくにつれ変更が発生する、ということが起こってしまうのです。

どうすればよいのでしょうか？

## 依存関係の問題を解決するためのアプローチ

この問題を解決するアプローチを考えていきます。
まず、安定的なコンポーネントに対する修正の大変さは以下の式で示すことができます。

```
修正の苦労　＝　依存されるコンポーネントの変更頻度 * 依存するコンポーネントの数 * 変更による壊れやすさ
```

当たり前のことのようですが、ここから、**依存されるコンポーネントの変更頻度を下げること**、**依存関係の数を減らすこと**、**変更によって壊れるコンポーネントを減らす**ということができれば修正の苦労を減らすことができることがわかります。
それぞれ具体案を考えてみましょう。

### 依存されるコンポーネントの変更頻度を下げる
変更の頻度を減らすには、機能を実装していきながら、部品を分割する、というやり方ではうまくいきません。
依存される前、つまり他の機能が実装される前に、要求を満たす高品質なコンポーネントを用意できればよいでしょう。
実装の前に、UXの5段階モデルの戦略からシステムへの要求を理解し、骨格・表層への要求を明らかにすることで達成できると思われます。
そのためには、プロトタイピングを繰り返し実施するなど、時間や人的資源といったコストをかけて品質を高める活動をなるべくプロジェクトの早い段階からやっていく必要があります。

#### １．プロジェクトの早い段階からUIを検討する
プロジェクトの早い段階から見た目、インタラクションを設計していくことで、実装の変更を減らすことができるでしょう。
ここ数年で、[Figma](https://www.figma.com/) などインターフェースデザインツールによって本格的な実装の前から動くものを確認できるようになりました。これらを利用してUIを検討を済ませてから実装を開始できるとよいと思います。間違ってもSPAのUI設計をExcelでやってはいけません。（チームの名誉のために言っておくと、Excelで設計してません）

このあたりはデザイナーと協力して進められるととても良いと思います。

デザインツールで設計できたものから少しずつ実装し、[storybook](https://storybook.js.org/) で公開するのも効果的です。コンポーネントの使い方を機能の実装の前に確認できるようになります。

#### ２． UIフレームワーク、CSSフレームワークを導入する

OSS／有償の製品として提供されているUIフレームワーク／CSSフレームワークを導入を検討します。提供元やコミュニティでテストされたコンポーネント群が利用可能になりますので、すぐに品質を高めることができます。フレームワークの習熟に学習コストがかかりますが、コストに見合うだけのリターンを得ることができると思います。

UIフレームワーク、CSSフレームワークに関しては一つ以上継続して使用し、複数のプロジェクトで利用することで経験値を開発チームのなかにためていけるとよいと思います。

### 依存関係の数を減らすこと
共有して問題ないものだけを共有するようにします。
なんでもatoms/moleculesに置くのはやめます。共有するものだけが存在するディレクトリを作成し、そこに本当に汎用的に設計されたコンポーネントのみを配置し共有を許可します。汎用的で、共有されることを前提としたライブラリが残るでしょう。

共有に関してはこの記事が参考になりました。
[Atomic Designをやめてディレクトリ構造を見直した話](https://note.com/tabelog_frontend/n/n07b4077f5cf3)

コンポーネントをどう設計していくかについてはこちら
[https://qiita.com/seya/items/8814e905693f00cdade2](https://qiita.com/seya/items/8814e905693f00cdade2)


### 変更によって壊れるコンポーネントを減らす
これはノーアイデア。 :raised_hands: なにかあればコメントで教えてください。

## 終わりに
発生した問題をバックエンドの設計で学んだ安定依存原則と紐づけて考えてみたりしたことは、Webフロントエンド開発を経験して得られた大きな学びでした。

問題意識も、対策も、普段からWebフロントエンドを開発されている方にとっては当たり前かもしれません。現に、あるプロジェクトでは解決のところで挙げた取り組みが初めから実践されていました。しかし、記事にすることで一つ一つの活動にどういう意味や効果があったのか、改めて理解を深める良い機会となりました。また、この学びを共有することで、これからWebフロント開発をやっていこうという人やチームの参考になれば幸いです。

これからもWebフロントエンド開発をエンジョイして、要求にこたえる品質の高いシステムを素早く提供する能力に磨きをかけていきたいと思います:muscle: