トップダウン設計はなぜ3回繰り返すのか(2版)
~機能・データ・責務による設計進化のプロセス~
Copyright © 2025 LWP 山中 一弘 本資料は、出典を明記いただければ、商用・非商用を問わず、ご自由に複製・改変・再配布していただけます。なお、著作権表示は改変せず、そのまま記載してご利用くださいますようお願いいたします。
要約
本稿では、ソフトウェア設計におけるトップダウンアプローチが、なぜ実務において「三回繰り返される」のかを、機能・データ・責務という三つの設計軸を通じて体系的に論じる。初回設計では、業務要求や画面操作に対応する形で機能単位の分割が行われるが、この段階では同じようなデータアクセス処理が各関数に重複して記述され、構造的な再利用性は得られない。
第2回目の設計では、関数の背後にあるデータ構造に注目し、CRUD処理や変形操作などをデータ単位で整理することで、共通API化が進む。しかしこの段階でも、処理の手順や検証ロジックが各機能に繰り返し記述されており、意味のある責務としての整理はまだ不十分である。
最終段階となる第3回目の設計では、機能の中に断片的・重複的に存在していた一連のデータ操作を、業務的意味に基づいて抽出し、責務単位で再構成する。これにより、関数構造は「意味をもつ中間層」として明確化され、再利用性、保守性、説明可能性を兼ね備えた設計へと進化する。設計が三回繰り返されるのは失敗の繰り返しではなく、視点を変えながら構造を洗練させていく必然のプロセスなのである。
第1章 はじめに──設計はなぜ繰り返されるのか
1.1 「トップダウン三回説」とは何か
ソフトウェア設計において、「トップダウン設計」は長らく体系的なアプローチとして定着している。要件や仕様といった上位の抽象的な情報から出発し、機能や構造を下位に展開していくこの手法は、初学者にも理解しやすく、構造の全体像を早期に掴む上で有効である。しかし実務においては、この「一度きりのトップダウン設計」で最終的な構造が完成することはまれである。むしろ、設計は何度も書き換えられ、視点を変えて繰り返される。これが本稿で扱う「トップダウン三回説」の出発点である。
本稿で提唱する三回設計説とは、設計の初期段階では「機能軸」による分割が行われるが、進行するにつれ「データ軸」による再編が不可避となり、最終的には「責務軸」による意味づけと構造化が求められるという経験則である。これは単なる再設計ではなく、設計という思考プロセスが段階的に深化し、設計対象を異なる観点から再解釈していく知的過程である。
1回目の設計では、ユーザー操作や業務フローに応じた直感的な機能分割が行われ、設計者は処理の流れを明確に描きやすい。だが、ここでは構造の整合性や再利用性はほとんど考慮されていないことが多く、設計としての安定性には欠ける。
2回目の設計では、関数群が扱うデータに着目し、構造の再整理が行われる。同一のデータを扱う処理が機能を超えて共通化され、構造の整合性と重複排除が進む。
そして3回目では、関数の中に潜む共通処理の連鎖、すなわち業務的意味を持つ処理のまとまりが「責務」として抽出され、意味ベースの構造が形作られる。この段階でようやく、設計は技術的構造ではなく、業務的構造としての完成に至る。
このように、設計は3つの観点──機能、データ、責務──から繰り返し見直されることで、真に意味ある構造へと成熟していく。設計の三回説は、実装を支える構造思考の変遷を体系的に説明する枠組みである。
1.2 設計の繰り返しは視点の交代である
設計はなぜ繰り返されるのか。それは、ソフトウェアの本質が「不確実な対象の構造化」であり、最初に与えられる仕様や要件は、往々にして断片的・あいまいであるためだ。設計初期において見えているのはあくまで「やりたいこと」や「操作手順」であり、それは構造ではなく、操作の表層に過ぎない。そこから構造を組み立てるには、前提と仮説、そして再評価の繰り返しが不可欠となる。
設計が繰り返されるのは、設計者が過ちを犯したからではない。むしろ、視点を変えた再評価こそが設計を深め、構造を明確にしていく本質的な行為である。最初は処理を分割するための視点だったものが、次にはデータの構造として整理され、最終的には責務という意味のまとまりとして再統合されていく。この視点の変化が設計の質を高め、結果として保守性・再利用性・説明可能性の高い構造へと導く。
このプロセスを理解せずに、初期設計に固執すれば、構造の整合性が崩れ、保守や拡張において破綻を招くことになる。設計の繰り返しは「やり直し」ではなく、「成熟」である。その成熟を可能にするのは、異なる軸から同じ対象を再構成するという、構造思考の訓練である。
トップダウン三回説は、設計を単なる成果物ではなく、構造を見抜き・育てていく思考のプロセスとして捉え直すための視座である。本稿では、この視座に基づき、3段階の設計がそれぞれどのような意味を持ち、何を生み出すかを具体的に論じていく。
第2章 第1回:機能軸による初期設計
2.1 要求・UI操作から始まる自然な構造分割
トップダウン設計の初回は、しばしば「仕様書」「業務手順書」「画面構成」など、外部から与えられた操作要求に基づいて構造が分割される。これは非常に自然な出発点であり、設計者もユーザーの思考と直結した形で設計を進められるため、プロトタイプの構築や初期合意の形成には非常に有効である。
たとえば、「データの入力」「検索」「出力」「保存」といった操作単位ごとにボタンが設けられ、それぞれに対応する関数が実装される。この時点での設計方針は「機能単位での分離」であり、UIに対応するコードを順に積み上げることで、画面と処理の整合性を直感的に保つことができる。
このような構成は、業務担当者との会話や要求把握の面でも有効であり、仕様確認や画面レビューなどにおいてもスムーズに議論が進む。しかし、その裏で、構造としての脆弱性や再利用性の欠如が静かに潜在している。
2.2 速さと説明しやすさの反面にある脆さ
機能軸による分割の最大の利点は、設計と実装のスピード感である。UI操作に即した関数分割により、開発者は迷いなく処理の流れをコードに落とし込むことができる。また、ボタンごとに関数が一対一で対応していれば、処理の流れも可視的で説明しやすい。こうした明快さは、小規模なアプリケーションや短納期プロジェクトでは大きな武器となる。
しかしその一方で、この構造は非常に脆弱でもある。たとえば、複数の画面機能が同じデータ項目を処理していた場合、似たような処理が各機能関数内に重複して書かれることが多くなる。また、UIベースで設計が進むため、業務処理の本質やデータ構造の整理は後回しにされがちであり、結果として「コードは動くが、構造が乱れている」状態に陥る。
さらに、後続の仕様変更に対応しにくいという問題もある。処理の粒度が機能単位で細かく分かれているため、1か所の変更が複数の関数に波及しやすく、設計全体としての保守性は低くなる。つまり、速く作ることができても、長く持たないのが、機能軸設計の構造的限界である。
2.3 関数構造の実態:同じデータ処理の重複
この段階での関数群を分析すると、実に多くの機能関数が同じようなデータ処理ロジックを個別に実装していることがわかる。たとえば、「売上データを読み取る」「空欄を除外する」「合計を算出する」といった処理は、複数の画面や機能で共通して求められるものであるにもかかわらず、それぞれの関数内でローカルに実装されていることが多い。
このような重複は、コードの肥大化や保守コストの増加を招くだけでなく、同じ処理であっても微妙な違いが生じることによって、バグの温床ともなり得る。さらには、「この関数がどのデータを対象としているのか」「同じ処理が他にもあるのか」といった情報が分散してしまい、設計全体の一貫性を損なうことになる。
つまり、機能軸による分割は、処理の見通しは良いが、構造の抽象化と共通化が行われていないため、拡張や再構成が困難な状態を生む。このことが、次の設計段階──データ軸による整理──の必要性を生むことになる。
2.4 「仮設構造」としての初回設計
機能軸による初回設計は、あくまで「仮の構造」であると位置づける必要がある。初期段階において、UIや処理要求に即して設計することは合理的であり、むしろ欠かすことのできない出発点である。しかしこの構造は、あくまで「業務フローの写像」であって、「データ構造の反映」や「責務の整理」ではない。
この仮設構造の上にそのまま機能追加を重ね続けると、構造的破綻をきたす。そこで、一定の処理群が実装された時点で、構造的な視点から設計を再点検し、再編成することが必要となる。その第一歩が、共通のデータ構造に着目した、第二回目の設計である。
初回設計が「使いやすさ」と「早さ」に優れた方法論であることは間違いない。しかし、そこにとどまっていては、ソフトウェアの構造は複雑化し、属人化し、やがて手に負えなくなる。初回設計は「作るための設計」、第二回以降は「育てるための設計」である。この認識こそが、設計を一過性の作業ではなく、成長する構造の生成として捉える第一歩となる。
第3章 第2回:データ軸による構造整理
3.1 関数を貫く共通データ構造の可視化
機能軸に基づいて構築された初回設計を俯瞰すると、多数の関数群が同じデータ構造に対して、個別にアクセス・操作を行っていることが明らかになる。たとえば、売上データや顧客マスタなど、業務において繰り返し使用されるデータセットが、関数ごとに異なる形で参照・加工されている場合が多い。
このような状況では、設計上の整合性が崩れやすく、同じデータでも関数によって解釈が異なる、あるいは前提条件が統一されていないといった問題が頻発する。ここで必要なのは、関数から機能名を外し、共通して使われているデータ構造を起点に、設計全体を再構成する視点である。
データに注目すれば、どの関数がどのような構造のデータを受け取り、どのような形に変換・出力しているかという処理の流れと整合性が可視化される。こうして、処理の意味や前提が共有されるようになり、設計に一貫性が生まれる。
3.2 CRUD・変形・制約に基づく操作集約
データ軸による設計の中心的な作業は、対象データに対する典型的な操作──CRUD(Create, Read, Update, Delete)、ならびに**変形(Transform)や制約(Constraint)**の明示的な整理である。これは機能ごとの処理から共通処理を分離し、役割に応じたデータ操作関数へと再編成するプロセスに他ならない。
このとき、複数の機能関数に共通する処理が明確になる。たとえば、売上明細を読み込んで検証し、無効行を除去し、数値に変換して整形する、といった一連の手順が、異なる機能の中で何度も繰り返されていることが判明する。これらは明らかに、データ構造に対する共通操作として独立すべき処理である。
ここで重要なのは、関数をデータ中心に再構成することで、重複の削減だけでなく、設計の意図と制約が明示化されるという点である。データに対する操作の定義は、設計の正しさだけでなく、業務ルールの透明化にもつながる。
3.3 「扇構造」による機能とデータの交点
この段階の設計状態は、二つの扇が交差する構造として比喩的に表現できる。一方の扇は、初期設計で展開されたユーザー機能や画面操作の広がりであり、もう一方の扇は、データを中心に構成された共通操作群の広がりである。二つの扇が交差する「要(かなめ)」の部分が、共通データアクセス関数やデータ制約処理となる。
ここで各機能関数は、それぞれの扇の「骨(処理)」を束ねるように、共通データAPIを呼び出す形で構成される。つまり、関数が個別に処理を抱えるのではなく、共通のデータ操作モジュールに依存する構造へと変化していく。これは、機能とデータを横断する中間層の萌芽でもあり、次の責務軸設計へと接続する前提条件を形成する。
このような構造では、変更や拡張が一箇所で集中管理できるため、保守性が高まり、設計全体の見通しが飛躍的に向上する。
3.4 関数構造の再編:API経由の統一構造へ
データ軸による再構成が進むと、関数構造は**「直接処理する構造」から「APIを呼び出す構造」へと再編**される。つまり、処理の詳細は個々の機能関数内から取り除かれ、必要な操作はすべてデータ操作関数として外部化される。各機能関数は、共通のAPIを組み合わせることで処理の意味を構成するハブとして振る舞うようになる。
この構造は、一見すると関数が薄くなったように見えるが、実際には「関数が本来担うべき構造の調整・呼び出し責任」のみに集中しており、責務の分離という観点で極めて優れている。この再編により、データ操作関数はどの機能からも再利用可能となり、設計の柔軟性と拡張性が格段に高まる。
また、関数呼び出しのパターンが定型化することで、設計レビューやテストも容易になり、チーム全体での設計理解・共有が進む。
3.5 次なる課題:一連の処理の重複と意味不明性
データ構造と処理の整理が進んだこの段階でも、実は依然として残る課題がある。それは、関数の中に断片的に現れる「処理の連鎖」、すなわち一連の業務的処理フローの重複である。たとえば、データの検証 → 整形 → 保存 → 通知といった流れが、多くの機能に共通して埋め込まれていることに気づく。
これらの処理は、技術的には共通関数の呼び出しで構成されているが、設計上は「何のためにこの連鎖が存在するのか」が明確になっていない。つまり、機能の意味が「構造的には整理されたが、業務的には可視化されていない」状態が発生している。
この状態を乗り越えるには、処理の流れを業務的な意味で再定義し、まとめて責任を持たせる構造──すなわち、責務単位の関数構成へと進化させる必要がある。それが次の設計ステップである、責務軸による意味の抽出である。
第4章 第3回:責務軸による意味の抽出
4.1 業務ロジックとは「意味をもつ処理連鎖」である
データ軸による再構成を経た段階では、個々の機能は共通APIを呼び出す形で再整理され、構造の一貫性は高まっている。しかし、この状態はあくまで「データ操作の共通化」にとどまっており、業務としての意味や目的を構造に反映したものではない。ここで設計に必要なのは、「この一連の処理は何のために存在しているのか」「誰の立場から、どんな責任を持って処理しているのか」という問いへの答えである。
業務ロジックとは、単なる処理の組み合わせではなく、ある目的のもとに一貫して実行される、意味ある処理の連鎖である。たとえば、「売上データを集計し、条件付きでアラートを出す」という処理は、技術的には複数のAPI呼び出しから構成されるが、業務的には「売上状況の監視」という一つの責務に束ねられている。この責務こそが、機能やデータの枠組みを超えて、構造に意味を与える設計軸である。
4.2 関数に埋もれた類似処理を抽出する
多くの機能関数には、処理の目的に沿って似たような処理の流れが埋め込まれている。たとえば、データ検証→整形→フィルタ→転記→出力といった一連の操作は、処理内容が多少異なるとしても、業務上の文脈ではほぼ同じ意図をもって繰り返されている。
これらは、初回設計では個別に記述され、第2回設計では共通のAPI呼び出しに整理されているが、それでもまだ「バラバラに存在している」という点では変わらない。ここで必要なのは、それらを「意味の単位」として抽出・定義し直すことである。
具体的には、業務機能を貫く「共通の処理パターン」に着目し、それを「ドメイン固有の業務共通関数」として明示的に定義する。たとえば、「有効売上データの抽出」「取引先コードの正規化」「部門別月次報告行の構築」などが、それに該当する。この抽出により、分散していた業務知識が構造的に整理され、明文化される。
4.3 関数構造の再構成:業務共通関数への集約
こうして抽出された意味的処理は、単なる便利な関数ではなく、業務的な文脈と責任を持つ関数群として位置づけられる。これが、責務軸設計の中核となる「業務共通関数」である。
業務共通関数は、特定のデータ構造と業務文脈において、一定の意味を持った処理を提供するものであり、その存在自体が業務知識の構造化を意味する。この段階では、各機能関数は、単に処理を連ねるのではなく、「どの責務に属する処理を使って構成されているか」という設計上の意味を持つようになる。
この関数構造への再構成によって、システムは単なる処理集合から、「業務責任のネットワーク」としての構造体へと進化する。関数の粒度も変化し、細分化された処理よりも、「業務のまとまりとしての処理単位」に重心が移る。
4.4 責務ベース設計の意義と影響範囲の明示化
責務軸による設計の最大の利点は、関数の意味と立場が明確化されることである。たとえば、「これはUIから呼ばれる処理なのか、業務上の判断処理なのか、それとも保存処理なのか」といった問いに対して、設計構造の中で一貫した回答が可能となる。この構造は、チームでの設計共有、レビュー、保守、引継ぎなど、あらゆる局面での「説明可能性」の基盤となる。
また、責務ベース設計は影響範囲の可視化にも寄与する。「この業務共通関数を変更したら、どの処理に影響するか」が明確になっていれば、保守コストを最小化でき、誤修正のリスクも減らせる。これは、設計の透明性だけでなく、運用フェーズでの品質確保にも大きく寄与する。
最終的に、責務軸に基づく構造化は、設計における最も高次の抽象化である。機能による分割、データによる整理を経て、処理の意味と立場が明確化されることで、設計は業務そのものを記述する構造へと昇華する。これにより、システムは単なるコードの集合体ではなく、業務知識と責任構造の集約体として機能し始める。
第5章 設計構造の成熟──再利用と運用のために
5.1 三層構造の形成(UI/Logic/Store)
トップダウン設計を機能・データ・責務の三段階で繰り返すプロセスを経ることで、最終的に導かれる構造は、明確に分離された三層アーキテクチャである。すなわち、ユーザーインターフェース層(UI)、業務ロジック層(Logic)、データ管理層(Store)である。
この三層構造では、それぞれの層が以下のような責務を担う
UI層:ユーザーとの接点。画面上の入力を受け取り、ロジック層に渡す。出力結果をユーザーに返す。
Logic層:業務処理の中核。検証、演算、判定などを担い、処理の意味と責任を引き受ける。
Store層:データの読み書きを担当。ワークシートやテーブルからの取得、更新、保存などを統括する。
このような分離により、たとえばUIを刷新してもロジックには影響がなく、データ構造が変更されてもStore層のみの修正で済む。設計における層の独立性は、保守性と再利用性を飛躍的に高める鍵である。
しかしこの段階で「それなら最初から三層構造で設計すればよいのではないか」という疑問が浮かぶのは自然である。実際、ドメイン駆動設計(DDD)では、当初から責務を基軸としたレイヤ分離を目指す設計哲学が示されており、理想論としてはそれに異論はない。
だが現実の現場では、初期の設計段階で業務責務が明示されていることは稀であり、画面操作や処理順といった表層的な要素から設計が始まるのが常である。そのため、最初から三層を厳密に区切ろうとすると、意図の曖昧な構造が乱立し、かえって属人化や断片化を助長する結果になりかねない。
三層構造とは、設計の最初に強引に与えるものではなく、複数の視点を経て成熟する「構造の帰結」である。初期設計で機能が分割され、実装の進行とともに共通データ構造が浮かび上がり、最終的に業務的意味に基づく責務として再構成される。三回設計法は、そうした設計の内的成熟プロセスを踏まえた、構造的思考の進化経路である。
5.2 保守性・拡張性・説明可能性の同時達成
三層構造が実現されると、設計における三つの理想──保守性、拡張性、説明可能性──が同時に達成される。
保守性:各層が独立しているため、UI変更やデータ構造変更の影響を局所化できる。修正のリスクが減り、品質を安定させやすい。
拡張性:ロジックが分離されていれば、処理を再利用したうえで、新たなUIやデータソースを追加することが容易になる。
説明可能性:関数やモジュールがどの層に属し、何を担当しているかが明確なため、他者への説明やドキュメント化がしやすい。
これらの要素は単独で成立するのではなく、三つの観点を繰り返し切り替える設計思考を通じて初めて実現される。単にレイヤを分けた設計図を描くだけでは得られない、構造の裏付けと文脈が必要なのである。三回設計法は、この「構造と責務の意味づけ」を経てこそ、三層構造を実質的に機能させる設計方法となる。
5.3 属人化を防ぎ、設計知識を共有資産へ
設計が成熟するとは、単にコードが整理されているということではない。それは、構造に込められた意図と責任が他者と共有可能になり、保守・拡張・教育において再利用される知識として定着することである。
属人化とは、構造が個人の記憶や慣習に依存している状態である。構造が表層的なレイヤ分離にとどまり、なぜこのような構成になっているのかが明示されていないとき、保守は属人に依存し、設計の継続性は損なわれる。
三層構造と三回設計法に基づいて設計されたコードは、関数の粒度、責任範囲、依存関係が整理されており、設計の背景にある意図が構造として読み取れるようになる。これは開発者間での設計知識の共有、レビュー時の構造理解、あるいはドキュメント作成の基盤となる。
さらに、こうした設計を意識的に蓄積すれば、関数テンプレートや命名規約、層別構成パターンといった再利用可能な資産として、設計文化へと昇華していく。設計が個人のスキルではなく、チームの言語となったとき、構造は組織の資産へと変わる。
第6章 終章──構造的視点で設計を考えるということ
6.1 設計とは「意味を構造にする」営みである
設計とは、目の前の仕様を構文に落とし込む作業ではない。それは、断片的な要求や曖昧な操作手順に潜む意図を見抜き、意味のある構造として再構成する知的営みである。処理の順序を整理し、データの流れを整え、最終的には「何のために存在しているのか」という責任と意義を構造の中に織り込む。この一連の過程こそが、本来的な設計である。
第5章で述べたように、設計の成熟は三層構造(UI/Logic/Store)の形成に結実する。しかし、それを実現するためには、単にレイヤーを機械的に分けるのではなく、それぞれの層が担う責務と接続関係を意味によって定義することが求められる。三層構造は「最初から与えるもの」ではなく、「設計の思考が成熟することで結果として生まれるもの」である。
この考え方はドメイン駆動設計(DDD)とも共鳴する。DDDでは、設計の初期段階から「責務に基づく構造」を志向するが、それは業務知識と設計経験が揃っている前提に立っている。三回設計法は、そうした理想構造に段階的かつ実践的に到達するプロセスであり、現場の設計者が「まず何から始め、どう成熟させていくか」を示す道筋となる。
すなわち、設計とは「動くものをつくる」技術ではなく、「構造に意味を与える」思考行為である。設計力の本質は、目の前のコードの背後にある意図を説明できるかどうかに表れる。構造が意味を持ち、他者と共有されるとき、初めて設計は組織の知的資産となる。
6.2 三回設計法を日常に取り入れるために
三回設計法は、特定のツールや技術スタックに依存しない。必要なのは、視点を切り替えて設計を再考する習慣である。関数を1つ書くときにも、「これはUI層か、ロジック層か」「この処理はどのデータ構造に基づいているのか」「なぜこの処理のまとまりが必要なのか」といった問いを投げかけてみる。こうした視点の交代は、設計のあらゆる局面で意味と構造を育てる原動力となる。
プロジェクトの初期では、機能単位の分割が主になるだろう。しかし、実装が進む中でデータ構造が明確になり、次第に共通処理や責務の重なりが見えてくる。そこで設計を見直し、整理し直すことは、手戻りではなく、意味の輪郭を定義するための必然的なステップである。
また、この思考法は設計教育にも適している。設計初心者には、まず機能軸による整理から入り、次にデータ軸による構造整理を経験させ、最後に責務という抽象的視点で意味を再構成するという段階的な学習が効果的である。設計に「正解を当てる」のではなく、「意味を発見し構造に落とし込む」姿勢こそが、成熟した設計者の条件となる。
設計を構造化するとは、構造の内側に意図・関係・責任の網を張ることである。そして、その網が他者にも読み取れるとき、構造は知識として共有される。つまり、設計とは構造による合意の道具である。
本書で提唱した三回設計法は、業務知識が未整備で、属人性が高まりがちな環境──たとえばVBAやスクリプト開発の現場──においても、構造と意味を段階的に可視化・整理するための実践的思考法である。ドメインモデリングのような高度な抽象化技術を使わずとも、視点の切り替えを積み重ねることで、設計は自然に成熟し、業務と構造を接続することができる。
