---
title: 鋼の意思で実施した、技術的負債解消のためのリアーキテクチャ
tags:  #フロントエンド #モノレポ #snapshotテスト  
author: [HireRoo](https://convert.docswell.com/user/hireroo)
site: [Docswell](https://www.docswell.com/)
thumbnail: https://bcdn.docswell.com/page/LEL93M2VJR.jpg?width=480
description: もっと開発を早くできそう、もっと品質担保のためにできることがありそう、でもやるべきことが多すぎてどこがボトルネックになっているのかの調査も難しい。いつか余裕ができた際には、この「もやもや」を脱してより解像度が高い状態を目指し、改善を進めていきたいものの、時間がたてば立つほど、この「もやもや」は増えていってしまう。  HireRoo でも、少数のエンジニアでフロントエンドとサーバサイドの両方を担当して開発を行っており、開発速度の遅さや、品質担保の維持に漠然とした課題感、つまり「もやもや」を抱えていたことがありました。  本登壇では、HireRoo が抱えていた「もやもや」を技術的な負債として解像度を上げ、それらの負債に対して具体的にどのような対応を行ったか、アーキテクチャをどう変えて負債を生みにくくしたか、それらの対応にどの程度のコストがかかったのか、実際に経験した内容をお話します。
published: April 08, 23
canonical: https://convert.docswell.com/s/hireroo/ZGXXP8-techtalk1-2
---
# Page. 1

![Page Image](https://bcdn.docswell.com/page/LEL93M2VJR.jpg)

鋼の意思で実施した、
技術的負債解消のための
リアーキテクチャ
@Himenon
1


# Page. 2

![Page Image](https://bcdn.docswell.com/page/4JMZDY8NEW.jpg)

イントロダクション
自己紹介
姫野 滉盛
@Himenon
SNS
●
●
GitHub: Himenon
Twitter: himenoglyph
エンジニアリング領域
●
Webフロントエンド（メイン）
●
開発支援ツールを作るのが趣味
前職
●
株式会社ドワンゴ
代表的なOSS
●
Himenon/openapi-typescript-code-generator
© HireRoo, Inc.
2


# Page. 3

![Page Image](https://bcdn.docswell.com/page/PJR6495479.jpg)

Agenda
1
フロントエンドの開発体制と課題
開発体制 &amp; 開発者のスキル傾向
2
課題解決に向けたリアーキテクチャ
何をリアーキテクチャするか？
従来の不具合の発生とトラブルシューティング
課題の精査
責務分離の戦略
現在の不具合の発生とトラブルシューティング
3
持続可能なアーキテクチャへ
コードテンプレートを作成
UIの初期化のテスト
依存関係のテスト
4
開発者のスキルアップ支援
UIコンポーネントの名前空間のテスト


# Page. 4

![Page Image](https://bcdn.docswell.com/page/PEXM2QKZ7X.jpg)

イントロダクション
最近のフロントエンドの開発事情①
初期
リリース後
●
●
●
技術選定
要件定義
実装
壊れやすい
●
●
ライブラリのバージョンアップで壊れる
実装とスタイルが密結合なのでちょっとの変更があ
ちこちに波及する
長期的に保守する
●
●
機能が減ることはなかなかない
開発当時はベストプラクティスでも時が経てばベス
トではなくなる
全体の実装量と開発者の人数の乖離していく
考えることが多い
●
© HireRoo, Inc.
●
●
追加実装
修正
4


# Page. 5

![Page Image](https://bcdn.docswell.com/page/3EKGM95VJD.jpg)

イントロダクション
最近のフロントエンドの開発事情②
開発を続ける限り戦いは続く
実装の老朽化（いわゆる技術的負債）vs 開発可能な時間と実装量
技術的負債と戦う理由
●
●
機能の追加・変更の難易度を上げる
不具合発生時のトラブルシューティングに時間がかかる
どうやって技術的負債を解消して行くか
●
問題の解像度を上げ、分解し、問題を局所的になるようにしていく
→ これについてHirerooでの事例を紹介します
© HireRoo, Inc.
5


# Page. 6

![Page Image](https://bcdn.docswell.com/page/L73NYW1Q75.jpg)

01
フロントエンドの開発体制と課題


# Page. 7

![Page Image](https://bcdn.docswell.com/page/87DW5KXWJG.jpg)

フロントエンドの開発体制と課題
ハイヤールーの開発体制 &amp; 開発者のスキル傾向
機能ごとに一貫して開発・保守を行う
●
インフラ・バックエンド・フロントエンドのような明確な区切りはない全部やる
開発者のスキル傾向
●
インフラ・バックエンドのほうがフロントエンドよりも得意
フロントエンドの技術スタック
●
React + TypeScript + 色々
© HireRoo, Inc.
7


# Page. 8

![Page Image](https://bcdn.docswell.com/page/VJP9GKPXE8.jpg)

フロントエンドの開発体制と課題
ソフトウェア開発で必ず発生すること
バグ修正
© HireRoo, Inc.
機能変更
機能追加
8


# Page. 9

![Page Image](https://bcdn.docswell.com/page/2EVM6V23EQ.jpg)

フロントエンドの開発体制と課題
従来の不具合の発生とトラブルシューティング
Backendは疎結合なので
不具合が機能単位・MS
単位で分解できる
Backend
機能A
=開発者A
機能B
=開発者B
機能C
=開発者C
機能D
=開発者D
不具合
不具合
不具合
不具合
不具合
Frontend
不具合
不具合
密結合な状態なので特定の機能の不
具合が別の機能の不具合に影響お及
ぼす（実際はそうでなくてもユー
ザーにそう見えるケースも）
© HireRoo, Inc.
不具合が発生した場合、報告のあった機能から
調査= 担当者が機能開発者に。
→ コードを読めば読むほど実は別の機能が原
因なこともしばしば。
9


# Page. 10

![Page Image](https://bcdn.docswell.com/page/57GGNLRY7L.jpg)

フロントエンドの開発体制と課題
現状のフロントエンドの開発体制・アーキテクチャ下での問題点
●
不具合の根本原因に当たりをつけるのが難しい
○
いろんな機能のコードを紐解きながらトラブルシューティングをする必要がある
●
機能
○
●
追加・修正が針に糸を通すような作業
他の機能を壊さずに追加するために針の穴に糸を通すような作業が続く
変更の影響範囲を特定しにくい
○
機能ごとのコンテキストが巨大なファイルの中に複数入り込んでいるため、正しい変更か自信が持てない
サービスが成長すればするほどコードの変更・追加の難易度が高くなる
ここに終止符を・・・！
© HireRoo, Inc.
10


# Page. 11

![Page Image](https://bcdn.docswell.com/page/4EQXQYV67P.jpg)

02
課題解決に向けたリアーキテクチャ


# Page. 12

![Page Image](https://bcdn.docswell.com/page/KJ46NWMM71.jpg)

課題解決に向けたリアーキテクチャ
何をリアーキテクチャするか？
大前提として・・・
●
●
課題がわかっていてもその解き方がわからないとリアーキテクチャ
することができない
今解決したい課題の本質がわかっていないと解決したことにならない。
現状のフロントエンド開発はどのようなものなのか振り返る
“近年のWeb 開発は、虫食いのテンプレートエンジンにデータをはめ込む方式から、デザインシステムに
カタログされたコンポーネント群に、 API から取得したステートを流し込み、それらを「いつ、どこ
で、どう」レンダリングするかという課題への最適解を、各位が模索するフェーズとなっている。”
抜粋: 次世代 CSS 仕様が与えるコンポーネント時代の Web への影響
https://blog.jxck.io/entries/2023-01-07/new-css-capabilities-for-component.html
ある程度までは道筋がありそうだが、途中から自分たちで探すようになっている...!
© HireRoo, Inc.
12


# Page. 13

![Page Image](https://bcdn.docswell.com/page/LE1V5Y8Y7G.jpg)

課題解決に向けたリアーキテクチャ
ライブラリやフレームワークはいい感じに課題を解決してくれるか？
結論：NO
●
課題
Framework
フレームワーク（Next.js、NestJS等）、開発ツール
（Storybook等）、テストツール（Cypress、jest）を
導入したからといってすべてが解決するわけではな
い
各ツールが解決するスコープには限りがある。
いま自分たちが解決したい課題の解像度を上げ、どのツー
ルを使い、どう扱えば解決できるか評価する必要がある。
Library B
Library A
もう守りきれないよ・・・
© HireRoo, Inc.
13


# Page. 14

![Page Image](https://bcdn.docswell.com/page/GEWL5GZ172.jpg)

課題解決に向けたリアーキテクチャ
課題の精査
- 現在の課題の分解能を上げる① -
●
考えられる問題の要因
○
責務分離の知識が乏しく、コンテキストの境界が実装上で不明瞭
●
従来の抑制する方法
○
レビュー
●
抑止力が機能していない理由
○
名前空間が効果的に分離されていないためレビューでそれを指摘できない
○
機能ごとの境界が見えていないのでレビューで指摘できず、責務の境界線を安易に侵犯する
© HireRoo, Inc.
14


# Page. 15

![Page Image](https://bcdn.docswell.com/page/47ZMNL1XE3.jpg)

課題解決に向けたリアーキテクチャ
課題の精査
- 現在の課題の分解能を上げる② -
●
考えられる問題の要因
○
フロントエンドの開発はTry &amp; Errorで書いて動いたコードが「動いてしまう」ので、「動いているから大
丈夫」というコードが生まれやすい
→ 実行時エラーなどで初めて分かるケースも。
●
従来の抑制する方法
○
レビュー
●
抑止力が機能していない理由
○
テストを効果的に利用できていない
○
設計方針が人によってバラバラ
© HireRoo, Inc.
15


# Page. 16

![Page Image](https://bcdn.docswell.com/page/YJ6N8WLPJV.jpg)

課題解決に向けたリアーキテクチャ
課題の精査
- 課題として見えること -
課題
実現方法
責務分離をしやすい状態・責務分離
の恩恵を享受しやすい状態にする
●
●
誰が実装しても同じ構造になるようにコードをある程度自動生成する
モノレポ構成に変更し、packageを1つの境界とする
責務分離を行う
●
●
●
BFF層を形成する（追加要求）
Presentation層 / Container層に分離する
巨大なStoreを機能単位で動くように解体する
責務分離を維持する
●
●
●
初期化テストを行う
依存関係の方向をテストする
利用可能な名前空間を制限する
React作者 Dan先生による Presentational and Container Components の記事
https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0
© HireRoo, Inc.
16


# Page. 17

![Page Image](https://bcdn.docswell.com/page/GJ559M1PJ4.jpg)

Hirerooのアーキテクチャを見直す
17


# Page. 18

![Page Image](https://bcdn.docswell.com/page/LE3NYW16E5.jpg)

課題解決に向けたリアーキテクチャ
Hirerooのリアーキテクチャ前の境界線
Backend
MicroService A
MicroService B
Page 1
Frontend
機能AのComponent
MicroService C
Page 2
機能BのComponent
MicroService D
Page 3
機能CとDのComponent
共通化されたUIパーツ
© HireRoo, Inc.
18


# Page. 19

![Page Image](https://bcdn.docswell.com/page/8EDW5KXM7G.jpg)

課題解決に向けたリアーキテクチャ
Hirerooのリアーキテクチャ前の境界線
Backend
MicroService A
トラブルシューティングのとき
MicroService B
MicroService C
MicroService D
特定のページで不具合が発生した場合、そ
れに関連するcomponentをたどっていく
Page 1
Frontend
機能AのComponent
場合によってはロジックを持っているもの
もある。これを変更するとあちこちに影響
が波及する。
© HireRoo, Inc.
Page 2（不具合）
機能BのComponent
Page 3
機能CとDのComponent
CとDの機能が実装されたコンポーネントを
変更すると、Page 3に影響を及ぼす。デグ
レの可能性。
共通化されたUIパーツ
19


# Page. 20

![Page Image](https://bcdn.docswell.com/page/V7P9GKPQJ8.jpg)

課題解決に向けたリアーキテクチャ
Hirerooのリアーキテクチャ前の境界線
実際はより複雑
React.useEffect関連の不具合
●
●
●
Stateを更新すると期待していないところが変化する
すぐにデグレが発生する
useMemoを使うべきところをuseEffectを利用している
同じUIだけどロジックが内包されているため、再利用できない
●
Storeを使いたいために内部でif分を持っている（依存性を注入すべきところをしていない）
不具合が発生した箇所はTry &amp; Errorを繰り返して修正されている
●
Try &amp; Errorの修正の上にTry &amp; Errorの修正がある（n回）
© HireRoo, Inc.
20


# Page. 21

![Page Image](https://bcdn.docswell.com/page/2JVM6V2PJQ.jpg)

Hirerooのリアーキテクチャの世界
21


# Page. 22

![Page Image](https://bcdn.docswell.com/page/5EGGNLRQEL.jpg)

課題解決に向けたリアーキテクチャ
Hirerooのリアーキテクチャ後の境界線
Backend
MicroService A
Page
MicroService B
Page 1
MicroService C
MicroService D
Page 2
Page 3
Container層
Frontend
Presentation層
Widget
機能AのWidget
機能BのWidget
Widget
Widget A
Widget B
Usecase
AとBの機能の共通ドメインで利用するUIコンポーネント
Primitive
© HireRoo, Inc.
機能CのWidget
機能DのWidget
Widget C
どのドメインにも属さないUIコンポーネント
22


# Page. 23

![Page Image](https://bcdn.docswell.com/page/4JQXQYVWEP.jpg)

課題解決に向けたリアーキテクチャ
新しいアーキテクチャの責務分離はどのように行われているか？
●
ディレクトリ構成 - モノレポを作成する
●
Presentation層（Presentational Component）
●
Container層（Container Component)
© HireRoo, Inc.
23


# Page. 24

![Page Image](https://bcdn.docswell.com/page/K746NWM1E1.jpg)

課題解決に向けたリアーキテクチャ
責務分離の戦略 - モノレポ構成を作成する ●
●
pnpm workspaceで実現
import * as Module from “@hireroo/{package name}”; という形式でパッケージ
間の参照が可能。
Container層とPresentation層を次のようなパッケージに収めた
●
●
●
@hireroo/backend –
@hireroo/app
–
@hireroo/ui
–
BFF層
Container層
UI層
@hireroo/appのdependenciesの例
© HireRoo, Inc.
ディレクトリ構成
24


# Page. 25

![Page Image](https://bcdn.docswell.com/page/LJ1V5Y85EG.jpg)

課題解決に向けたリアーキテクチャ
責務分離の戦略 - Presentation層（Presentational Component）-
●
●
●
UIの責務だけに集中したコンポーネント
Atomic Designの構造をベースに
Layout/Page/Widget/Usecase/Primitiveという構造を作成
PageとWidgetのみContainer層で利用可能
Layout
Page
Usecase
Primitive
Widget
@hireroo/uiのディレクトリ構成
© HireRoo, Inc.
WidgetはLayoutを持たない。
Container化した後、PageのReact.NodeのPropsに
直接渡す
25


# Page. 26

![Page Image](https://bcdn.docswell.com/page/GJWL5GZWE2.jpg)

課題解決に向けたリアーキテクチャ
Hirerooのリアーキテクチャ後の境界線 - Presentation層 -
Backend
MicroService A
コンポーネント名にドメイン名が入る可能性
があるが、内部の実装はUIの責務に閉じる。
Page
MicroService B
Page 1
MicroService C
MicroService D
Page 2
Page 3
Container層
Container層のStoreの更新、APIの通信などは
一切しない。
Frontend
Presentation層
Widget
機能AのWidget
機能BのWidget
Widget
Widget A
Widget B
Usecase
AとBの機能の共通ドメインで利用するUIコンポーネント
Primitive
© HireRoo, Inc.
機能CのWidget
機能DのWidget
Widget C
どのドメインにも属さないUIコンポーネント
26


# Page. 27

![Page Image](https://bcdn.docswell.com/page/4EZMNL12J3.jpg)

課題解決に向けたリアーキテクチャ
責務分離の戦略 - Container層（Container Component) - 1/2
FetchContinaer
●
Container Component
データの取得を行う
Container
●
FetchContainer
Container
Presentation層との境界
useGenerateProps
useGenerateProps
●
Presentatino層のInterfaceに沿ってStateをマッピング
●
Event Handler中にデータの更新・ビジネスロジックを実装する
@hireroo/appのディレクトリ構造
© HireRoo, Inc.
27


# Page. 28

![Page Image](https://bcdn.docswell.com/page/Y76N8WW67V.jpg)

課題解決に向けたリアーキテクチャ
責務分離の戦略 - Container層（Container Component) - 2/2
ErrorBoundaryはContainer Componentの単位で設置
●
ロギングのスコープがContainer Component単位で分類される
Container Componentは1つのアプリケーションとして完結した単位
●
●
pageのContainerはルーティングに配置される
widgetのContainerはpageのContainerに配置される
同じUIかつ振る舞いが異なるContainer Componentも作成できる
●
他Container ComponentのuseGeneratePropsからWidgetが呼び出される
Candidate・Employeeといった異なるドメインでContainerが実装される
○
●
ErrorBoundaryはContainer側で差し込む
※ 必要に応じて共有できるコンポーネントも作成可能（shared）
WidgetのContainer Componentはpageを跨いで利用できるため、ロジックの再
実装を防げる
© HireRoo, Inc.
28


# Page. 29

![Page Image](https://bcdn.docswell.com/page/G7559MM574.jpg)

課題解決に向けたリアーキテクチャ
Hirerooのリアーキテクチャ後の境界線 - Container層 -
Backend
MicroService A
Page
Pageは通信のライフサイクルとStoreを独立し
て持つ。Layoutとしての機能を持つことがで
き、そこにWidgetを配置することが可能。
MicroService B
Page 1
MicroService C
MicroService D
Page 2
Page 3
Container層
Frontend
Widget
機能AのWidget
機能BのWidget
Widget
Widget A
Widget B
Presentation層のComponentに対してpropsを
提供する層。通信のライフサイクル、Storeの
更新などの責務に集中する
Presentation層
Usecase
Primitive
© HireRoo, Inc.
機能CのWidget
機能DのWidget
Widget C
Widgetは通信のライフサイクルとStoreを独立
して持ち、各ページに配置するだけで機能す
る単位。
AとBの機能の共通ドメインで利用するUIコンポーネント
どのドメインにも属さないUIコンポーネント
29


# Page. 30

![Page Image](https://bcdn.docswell.com/page/9J2N299GER.jpg)

Hirerooのリアーキテクチャ後の
トラブルシューティング
30


# Page. 31

![Page Image](https://bcdn.docswell.com/page/DEYPY44GEM.jpg)

課題解決に向けたリアーキテクチャ
Hirerooのリアーキテクチャ後の境界線 - トラブルシューティングのとき -
Backend
MicroService A
Page
MicroService B
Page 1
MicroService C
MicroService D
Page 2
Page 3
Container層
Widget
Frontend
機能AのWidget
機能BのWidget
不具合
Widget A
Widget B
Widget
ビジネスロジックに不具合がある。機能Bの担当者が修正
ErrorBoundaryによって原因箇所がすぐにわかるように
Presentation層
Usecase
Primitive
© HireRoo, Inc.
機能CのWidget
機能DのWidget
Widget C
AとBの機能の共通ドメインで利用するUIコンポーネント
どのドメインにも属さないUIコンポーネント
31


# Page. 32

![Page Image](https://bcdn.docswell.com/page/VJN5PYY878.jpg)

課題解決に向けたリアーキテクチャ
Hirerooのリアーキテクチャ後の境界線 - トラブルシューティングのとき -
Backend
MicroService A
Page
MicroService B
Page 1
MicroService C
MicroService D
Page 2
Page 3
Container層
Widget
機能BのWidget
Widget
Widget A
Widget B
Usecase
AとBの機能の共通ドメインで利用するUIコンポーネント
UIに表示崩れがある
不具合レポートはPage1/Page2からやってくる。共通
のドメイン単位でコンポーネントが作成されているた
め、機能A/Bのどちらかの実装者が修正可能。
Frontend
Presentation層
機能CのWidget
機能AのWidget
Primitive
© HireRoo, Inc.
機能DのWidget
Widget C
どのドメインにも属さないUIコンポーネント
32


# Page. 33

![Page Image](https://bcdn.docswell.com/page/YE9Y3PPXJ3.jpg)

課題解決に向けたリアーキテクチャ
Hirerooのリアーキテクチャ後の境界線 - トラブルシューティングのとき 実装面
●
●
●
●
Presentation層とContainer層を構築することでフロントエンドの実装を2つの大きな責務に分離した
Presentation層が再利用可能な状態になったことで異なるコンテキストで同じUIを利用できた
Container Componentはそれ単体で機能する一つの小さなアプリケーションであるため、ロジックもまるごと
再利用可能なコンポーネントを実装できるようになった。
修正したい場所に対して名前がついているため、実装場所と実装意図がレビュー時に明確にわかり、認知負荷
を低減させる
トラブルシューティング面
●
●
Presentation層 / Container層のどちらの問題か区別がつくようになった
Container Componentは機能ごと単位で分離され、エラーログもこの単位で送信されるため問題発生時の根本
原因の特定時間が短くなる
© HireRoo, Inc.
33


# Page. 34

![Page Image](https://bcdn.docswell.com/page/GE86MDD97D.jpg)

03
持続可能なアーキテクチャへ


# Page. 35

![Page Image](https://bcdn.docswell.com/page/LEL93MMMJR.jpg)

持続可能なアーキテクチャへ
アーキテクチャを維持を困難にする課題と対策
「長期的に保守する」とは....
●
●
●
機能が減ることはなかなかない
開発当時はベストプラクティスでも時が経てばベストではなくなる
全体の実装量と開発者の人数の乖離が大きくなる
どうやって老朽化に抗うか
●
●
実装の規格化
手動で作業するとアーキテクチャが崩壊しそうな場所は自動化する
フロントエンドの実装の老朽化防止のための施策（ガードーレール）
●
●
コードテンプレートを作成
テスト
○
依存関係
○
名前空間
○
UIの初期化
© HireRoo, Inc.
35


# Page. 36

![Page Image](https://bcdn.docswell.com/page/4JMZDYY6EW.jpg)

持続可能なアーキテクチャへ
コードテンプレートを作成
Presentation層
●
●
●
[ComponentName].tsx
[ComponentName].stories.tsx
[ComponentName].spec.tsx
pnpm run ui-generator -o src/widget/HelloWorld -n HelloWorld
Container層
●
●
●
FetchContainer.tsx (Optional)
Container.tsx
useGenerateProps.tsx
pnpm run container-generator -o src/widget/shared/HelloWorld -n
HelloWorld -ns widget
commanderパッケージを利用してCLI化。内部実装はCLIの引数で与え
られた情報を元にString Literalでテンプレートコードを生成する単純
な実装。
© HireRoo, Inc.
テンプレートコードを作成するための実装
36


# Page. 37

![Page Image](https://bcdn.docswell.com/page/PJR6499N79.jpg)

持続可能なアーキテクチャへ
コードテンプレートを作成
[ComponentName].spec.tsx
●
●
Presentation層のコードテンプレート中にあるテスト
ファイル
中身はUIコンポーネントのスナップショットを作成
するだけのテスト
実はかなり厳しい設定が入っている
●
Snapshot作成時にconsole.warn、console.errorが検知
されたらテストを失敗させる。
○
keyの設定漏れの検知
○
ValidateDomNesting Errorの検知
→ 例外なくすべてのUIコンポーネントに入っている
© HireRoo, Inc.
jest.spyOnでconsole.warn/error検出時にErrorをthrowする
38


# Page. 38

![Page Image](https://bcdn.docswell.com/page/PEXM2QQ87X.jpg)

持続可能なアーキテクチャへ
UIの初期化のテスト - [ComponentName].spec.tsx - もう一つの狙い
jest --collectCoverageによってカバレッジスコアが循環的
複雑度と類似した指標を表すようになる。
スナップショットテスト用に与えらてたサンプルデータに
よってカバレッジスコアの満点にならない場合、何らかの
分岐がコンポーネント内に含まれていることがわかる。
次のようにCoverage Scoreを利用できる。
●
●
点数の低いコンポーネントほど挙動が不安定である
リファクタリング・テストの優先度が高いコンポー
ネントとなる
Coverageスコア 一覧。
e2eテストでしかカバーできないようなコンポーネント スコアが低い
© HireRoo, Inc.
39


# Page. 39

![Page Image](https://bcdn.docswell.com/page/3EKGM99LJD.jpg)

持続可能なアーキテクチャへ
名前空間のテスト
@hireroo/ui内の書く粒度（page/widget/usecase/primitive）で利用
可能な名前を制限するテスト
WidgetやPageにはDomain Keywordが1語以上含まれていなければテ
ストが失敗するようになっている。
Domain Keyword
Algorithm Answers Form
AnswersFormだけでは境界が抽象的すぎる
AnswersFormだけの場合、Domain（Quiz/Challenge/SystemDesign）を内包することを許容してしまう
Widgetのコンポーネント名は利用シーンが
わかるような名前になっている
© HireRoo, Inc.
40


# Page. 40

![Page Image](https://bcdn.docswell.com/page/L73NYWW675.jpg)

持続可能なアーキテクチャへ
依存関係のテスト
2つ利用
●
●
package.jsonのexportsでexport可能なモジュールを制限
○
→ viteがexportsを解釈するため、違反した場合ビルド時が失敗する
dependency-cruiserで依存関係をテスト
テスト内容
●
●
基本的なテスト
○
循環参照の検出
○
どこからも参照されていない孤立したファイルの検出
カスタムテスト
○
package間の依存
○
Presentation層
■
page, widget, usecaseの参照方向を制限
○
Container層
■
各ディレクトリから参照可能なディレクトリを制限
●
例：CandidateからEmployeeを参照できないように
© HireRoo, Inc.
41


# Page. 41

![Page Image](https://bcdn.docswell.com/page/87DW5KKMJG.jpg)

持続可能なアーキテクチャへ
まとめ
●
●
●
各レイヤーで必要なコードを自動生成する
Presentation層（UI）の側のテスト
○
Snapshotテストによって、初期化がerror/warnなく実施できていることを厳密に確認
■
カバレッジスコアが循環的複雑と同等の指標を表し、リファクタリングの必要性などを示す材料となる
○
コンポーネント名の制限を導入
■
page/widget/usecase/primitiveなどで利用可能な単語を制限している
依存関係の制限
○
pacakge.jsonのexportsフィールドを利用して各パッケージから公開するAPIを制限
○
Dependency-cruiserにより循環参照などを検知している
■
カスタムテストを追加することでアーキテクチャの依存関係をテストで表現している
© HireRoo, Inc.
42


# Page. 42

![Page Image](https://bcdn.docswell.com/page/VJP9GKKQE8.jpg)

04
開発者のスキルアップ支援


# Page. 43

![Page Image](https://bcdn.docswell.com/page/2EVM6VVPEQ.jpg)

開発者のスキルアップ支援
持続可能なアーキテクチャへの続き
問題の要因
フロントエンドの開発はTry &amp; Errorで書いて動いたコードが「動いてしまう」ので、「動いているから大丈夫」
というコードが生まれやすい
→リアーキテクチャしてもしなくてもこの問題は発生する
堅牢にシステムを維持するためには開発者のスキルアップを促す必要がある
●
●
●
新しいアーキテクチャに対する理解
デザインパターンやDDDに基づく実装パターン
第一原理がフロントエンドのシステムの中でどのように使われているのか、基礎と応用のマッピング
© HireRoo, Inc.
44


# Page. 44

![Page Image](https://bcdn.docswell.com/page/57GGNLLQ7L.jpg)

開発者のスキルアップ支援
Lunch And Learn
やってること
●
●
●
●
●
Lunch and Learnという時間を12:00 - 13:00の間で
確保している
話して以外はご飯食べながら聞く会
アーキテクチャのルールや、テクニカルな内容
を紹介していく
Google Meetで行っており、録画されている
録画を後から見返すこともでき、新しく入って
きた人たちも見ることができる状態にしている
→ 全員のレベルアップを促す会を開催している
© HireRoo, Inc.
45


# Page. 45

![Page Image](https://bcdn.docswell.com/page/4EQXQYYW7P.jpg)

Take Away
全体のまとめ
●
リアーキテクチャを行う前に課題に対する分解能を上げた
●
モノレポを導入し、Presentation層とContainerそうに分離した
●
アーキテクチャが持続可能な状態にするための施策を実施
○
テンプレートコードを自動生成した
○
UI
○
■
初期化が厳しいSnapshotテスト
■
コンポーネント名を制限
依存関係のテストを実施
■
package.jsonのexportsを利用
■
dependency-cruiserでpackage間やディレクトリ間で依存可能な方向を制御
© HireRoo, Inc.
46


# Page. 46

![Page Image](https://bcdn.docswell.com/page/KJ46NWW171.jpg)

ご清聴ありがとうございました
47


