こんにちは、ソーイ株式会社の髙﨑です。
今回は、最近の業務でDB設計をした際に失敗した設計手順について、問題だった点と改善点についてまとめてみました。
目次
- はじめに
- 実際にやった順序(失敗例)
- なぜダメだったか
- 改善案
- 学び
はじめに
新機能の設計を進めていたとき、想定以上に時間がかかってしまいました。
原因はいくつかありましたが、その一つが「設計書の作成順序」でした。
今回、クラス図・ER図・APIエンドポイント一覧を作成しましたが、最初にAPIエンドポイントから手をつけてしまいました。
その結果、全体のシナリオがうまくイメージできず、途中で何度も手戻りが発生することになりました。
「とりあえずAPIから考える」という進め方はやりがちですが、実際にやってみると意外とうまくいかないことも多いと感じました。
この記事では、なぜその順序で進めるとうまくいかなかったのか、そしてどのような順序で設計を進めると考えやすくなるのかを整理します。
本記事の結論としては、APIは設計の出発点ではなく、ユースケースやデータ構造を整理した後に定義するべきであるという点です。
想定読者
- API設計から先に考えてしまうことがある方
- 設計の進め方に悩んでいるエンジニア
- 設計時の手戻りを減らしたいと考えている方
実際にやった順序(失敗例)
今回の設計では、以下のような順序で作業を進めました。
- 仕様書・見積もりをもとに、APIエンドポイント一覧を作成
- テーブル設計が必要だと気づき、ER図を作成
- ER図をもとにクラス図を作成
- 最後にAPIエンドポイント一覧を修正
一見すると大きな問題はなさそうに見えますが、実際にはこの順序が設計の難易度を上げる要因になっていました。
まず、最初にAPIエンドポイント一覧を作成したことで、「どのようなAPIを提供するか」が前提として固定されてしまいました。
この状態で詳細を詰めていくことになり、後続の設計は常に「このAPIをどのように成立させるか」という視点に引っ張られてしまいました。
次に、APIの検討を進める中で、データ構造が定まっていないことによる曖昧さに直面しました。
そのため途中でER図の作成に移りましたが、この時点ではすでにAPIの方向性がある程度決まっていたため、本来あるべきデータ構造を整理するというよりも、「既に考えたAPIを実現するためのテーブル設計」になりがちでした。
さらに、ER図をもとにクラス図を作成したことで、クラスの責務や振る舞いを考えるというよりも、データ構造をそのままクラスに落とし込むような形になりやすく、設計としての柔軟性が失われていきました。
最終的にAPIエンドポイント一覧を見直すことになりましたが、この段階ではすでに複数の設計成果物が存在しているため、APIの変更がER図やクラス図の設計にも影響を与え、多くの手戻りが発生しました。
結果として、「最初に決めたAPIを後から修正する」ことになり、設計全体の整合性を保つために何度も見直しが必要となってしまいました。
なぜダメだったか
今回の設計がうまく進まなかった原因は、設計の進め方における「順序」と「依存関係」を十分に意識できていなかったことにありました。
まず前提として、APIは単体で成立するものではなく、ユースケースやデータ構造、内部の振る舞いといった要素の上に成り立つ「結果」として定義されるものです。
そのため、本来はこれらの要素が整理された後に設計されるべきものであり、出発点として扱うべきではありません。
しかし今回のように、最初にAPIエンドポイントを定義してしまうと、「このAPIをどのように成立させるか」という視点が前提となり、後続の設計がその制約に引っ張られる形になります。
その結果、本来は柔軟に検討されるべきデータ構造やクラス設計が、APIに合わせるためのものになってしまい、不自然な構造を生みやすくなります。
また、設計には依存関係があり、一般的には「ユースケース → データ構造 → 振る舞い → API」という順序で整理されます。
この順序を逆にしてしまうと、前提となる情報が不十分なまま設計を進めることになり、仮定に基づいた判断が増えてしまいます。
その状態で設計を進めると、一見すると個々の要素は成立しているように見えても、全体としての整合性が取れなくなり、後から修正が必要になる場面が増えてしまいます。
実際に今回も、APIの見直しをきっかけに他の設計にも影響が波及し、手戻りが発生する結果となりました。
このように、設計の順序を誤ると、個別には正しく見える判断の積み重ねが、最終的に全体の破綻につながる可能性があります。
改善案
今回の反省を踏まえ、設計は以下のような順序で進めるのが良いと考えています。
- ユースケースやシナリオを整理する
- データ構造(ER図)を定義する
- クラスや責務を設計する
- APIとして外部に公開する形を整理する
まず最初に、ユーザーがどのような操作を行い、システムがどのように振る舞うのかといったユースケースを整理します。
この段階でシステムの目的や全体像を明確にしておくことで、後続の設計がブレにくくなります。
次に、ユースケースをもとに必要となるデータ構造を整理し、ER図として定義します。
ここでは「どのようなデータを持つのか」「それぞれのデータがどのように関連するのか」を明確にすることを意識します。
その後、データ構造を踏まえてクラス設計を行い、それぞれの責務や振る舞いを整理します。
単純にテーブル構造をクラスに落とし込むのではなく、「どのクラスがどの責任を持つべきか」という観点で設計することが重要です。
最後に、ここまで整理した内容をもとにAPIエンドポイントを設計します。
この順序で進めることで、APIも自然な形で定義でき、無理のない設計にしやすくなると感じました。
今回のような設計の進め方は、ドメイン駆動設計(DDD)における「ドメインを中心に設計する」という考え方にも近いものです。
外部インターフェース(API)ではなく、まずドメインやデータ構造を整理するという点で共通しています。
また、各工程においては以下のような観点で確認を行うことで、設計の質を高められると考えています。
- ユースケースは具体的に説明できるか
- データ構造に無理や矛盾はないか
- クラスの責務が曖昧になっていないか
- APIが内部構造に引きずられすぎていないか
今回のケースでは、永続化されるデータ構造が設計の中心になるため、クラス設計に先立ってER図を整理しています。
一方で、ビジネスロジックや振る舞いが複雑なシステムの場合は、クラス設計(ドメイン設計)を先に行い、その後にデータ構造へ落とし込む方が適しているケースもあります。
このように、ER図とクラス図のどちらを先に設計するかは、システムにおいて「データ」と「振る舞い」のどちらが中心になるかによって選択する必要があります。
学び
今回の経験から、設計においては「何を作るか」だけでなく、「どの順序で考えるか」が改めて重要だと感じました。
特に、APIは設計の始まりではなく、ユースケースやデータ構造、内部の振る舞いといった要素を整理した結果として定義されるべきものであると認識しました。
また、設計には依存関係があり、その順序を意識せずに進めてしまうと、前提が曖昧なまま判断を重ねることになり、結果として手戻りが発生しやすくなることも学びでした。
今回のケースでは、APIを起点に設計を進めてしまったことで、各要素が本来の役割ではなく「APIを成立させるための手段」として扱われてしまい、結果として設計全体の整合性を保つことが難しくなっていました。
今後は、「その設計は十分な前提が揃った状態で行われているか」という観点を意識しながら進めることで、無理のない構造を保ちつつ設計できるようにしていきたいと考えています。
また、個々の要素が正しく見えても、全体として整合性が取れているとは限らないため、常に全体像を意識しながら設計を進めることの重要性も改めて認識しました。
参考
- https://qiita.com/APPLE4869/items/d210ddc2cb1bfeea9338
- https://zenn.dev/sre_holdings/articles/a57f088e9ca07d
お知らせ
技術ブログを週1〜2本更新中、ソーイをフォローして最新記事をチェック!
https://qiita.com/organizations/sewii


