トップダウン設計はなぜ3回繰り返すのか
~機能・データ・責務による設計進化のプロセス~
Copyright © 2025 LWP 山中 一弘 本資料は、出典を明記いただければ、商用・非商用を問わず、ご自由に複製・改変・再配布していただけます。なお、著作権表示は改変せず、そのまま記載してご利用くださいますようお願いいたします。
要約
本稿では、ソフトウェアにおけるトップダウン設計が「3回繰り返される」と言われる理由について考察する。第1回目の設計では処理や要求に基づく「機能」単位で分割されるが、次第に「データ構造」の存在が明らかになり、第2回目では構造ベースの再整理が行われる。そして最終的に、確立された構造に対して「責務と意味」の観点から機能が再定義される。この3段階の設計プロセスを通じて、設計はより洗練され、再利用性と拡張性を備えたものとなる。
1. はじめに
1.1 トップダウン設計の三回説とは何か
ソフトウェア設計において、トップダウン設計は一般的に「上から順に全体を見渡し、構造を分割して設計していく手法」として知られている。この方法は、仕様や要件から出発して設計全体を形作る上で有効であり、特に業務システムや画面駆動型のアプリケーションでは自然な流れとなる。しかしながら、実際の開発現場では「一度のトップダウン設計」で完成することは稀であり、実質的には「三回繰り返される」という経験則が存在する。
第一回目の設計では、処理の流れや画面構成、機能要求といった「機能軸」に基づいて構造が決定される。これはユーザーの操作順や業務フローを起点とするため、最も直感的で着手しやすい。しかしこの段階では、関数の粒度や再利用性、構造整合性が十分に吟味されていないことが多い。
第二回目では、機能の実装過程において見えてくる「データ構造」が焦点となる。処理を支えるテーブルやオブジェクトが明確になることで、今度はデータごとに関数を再配置・統合し直す流れが発生する。ここでは、機能よりも構造、操作よりも対象データが中心となるため、設計軸が明確に変化する。
そして第三回目は、完成しつつある構造に対して「責務」という観点から再統合が行われる段階である。UIや保存層に挟まれた中間層に存在する関数群に対し、それぞれの責任範囲や意味的役割を再定義し、業務共通処理やビジネスロジック単位で整理し直す。この段階では、関数が「何をするか」だけでなく「なぜそこにあるのか」「どこまでを担当するのか」が問われるようになる。
この三段階の設計プロセスは、それぞれ異なる軸で構造を捉え直す作業であり、単なる修正ではなく、視点の交代による設計の成熟である。これを体系化して理解することで、設計の混乱を避け、明快で再利用可能な構造を構築することが可能となる。
1.2 設計はなぜ繰り返されるのか
設計が一度では終わらず、何度も繰り返されるのは、設計作業そのものが「不確実な対象の構造化」であるためである。ソフトウェア設計において、最初に与えられる要件や仕様は、多くの場合「断片的」であり、「構造」ではなく「要望」や「手順」として記述されている。そのため初期の設計はどうしても処理順や操作画面に引きずられた、並列的で脆弱な構成になりやすい。
また、設計の初期段階では、データの全体像や関連性が把握できておらず、構造的整合性を考慮した分割が困難である。その結果、実装を進めながら「あ、この処理も同じデータを使っている」「この関数は別のところでも使える」といった気づきが得られ、設計をやり直す必要が生じる。すなわち、実装過程が逆に「要件の構造化プロセス」となり、設計のやり直しを促す。
さらに、設計は「コードを構造的に書く」ための作業であると同時に、「チームで共有し、保守する」ための枠組みでもある。そのため、見通しのよさ、責務の明確さ、再利用可能性といった観点から、設計の見直しは必然的に発生する。現実的には、業務の理解が深まるにつれ設計も進化していくため、設計は単なる前準備ではなく、全体のプロジェクトライフサイクルにおいて繰り返し行われるべき知的作業である。
繰り返される設計は「失敗のやり直し」ではなく、「視点の洗練」である。最初は見えなかった構造や責任の輪郭が、実装と検証の過程を通じて明らかになり、それを反映して設計が更新されていく。この積み重ねによって、ソフトウェアは単なる処理集合から、意味を持った構造体へと成長していく。
2.1 要求・操作手順に基づく機能分割
設計の初期段階では、与えられた要件や仕様に基づいて、処理の流れや操作の順序をそのまま設計に落とし込むことが多い。これは「要求主導型」あるいは「操作順駆動型」の機能分割であり、ユーザーの目線に近い自然な手法である。たとえば「データを入力する」「検索する」「印刷する」「保存する」といった処理単位で関数を設計し、それをメニューやボタンに対応させるという形で構築される。
この段階では、設計の起点が「何をしたいか」にあるため、ユーザーや業務担当者とのコミュニケーションもスムーズである。また、具体的な操作に沿って画面や処理が設計されるため、プロトタイプの作成や初期実装も迅速に行えるという利点がある。
しかしこの方法は、「処理単位の並列配置」に留まりやすく、関数間の関係性や構造的整合性が見えにくいという弱点を持つ。また、同じような処理が異なる機能に重複して実装されたり、データの共通化が後回しになったりすることで、後の保守や拡張が困難になる傾向がある。
設計の第一段階としては合理的で有効な出発点であるが、それはあくまで「処理の羅列」に過ぎず、アプリケーション全体の構造を見通すには不十分である。この段階を踏まえて、後にデータ構造や責務という視点に基づく設計の再構成が必要になる。
2.2 初期設計の速さと脆さ
機能軸によるトップダウン設計は、設計のスピードという点では非常に優れている。処理の順序や操作の流れに沿って分割するため、設計者は迷うことなく構成を決定できる。とりわけ小規模なアプリケーションや試作段階のプロトタイプにおいては、短時間で動作する形を構築できるという実務上の利点がある。
また、ユーザーの期待する動作と設計構造が直結するため、レビューや仕様確認も容易であり、ステークホルダーとの合意形成もスムーズに進みやすい。この点で、初期段階の設計方針としては実践的である。
しかし、この初期設計は「速さ」と引き換えに「脆さ」を内包している。処理順をもとに分割された構造は、再利用性や柔軟性に乏しく、仕様変更に対して脆弱である。複数の機能にまたがって同じようなコードが散在することで、修正時に手間がかかり、バグの温床となる可能性が高まる。
さらに、データ構造を意識せずに関数を並列配置すると、同じデータを複数箇所で別々に扱い、整合性を損なう危険がある。UI主導で設計された構造は一見わかりやすいが、内部ロジックの一貫性には欠け、長期的には設計の見直しが避けられない。
このように、初期設計はスピードを重視する一方で、後に続く設計工程に再編成の余地を残す「仮設構造」であると理解する必要がある。その前提に立つことで、次の段階での設計刷新を自然な進化として受け入れられるようになる。
3. 第2回目:データ軸による構造整理
3.1 分割の中で見えてくるデータ構造
機能に基づく初回のトップダウン設計によって、一通りの処理単位は見えてくる。しかし、そこで定義された関数群を整理していく中で、各関数がどのようなデータを受け取り、どのようなデータを生成しているかという情報の流れに注目すると、処理単位とは異なる構造が浮かび上がってくる。たとえば、同じ「売上データ」を扱う関数群が、異なる命名や構造でデータを定義していることに気づいた場合、それはデータ設計の観点から不整合を意味している。つまり、関数設計を通じて見えてくるのは、暗黙的に仮定されていた「データの構造」であり、ここに着目することで関数同士の整合性、さらには設計全体の一貫性を担保する道が開ける。この段階では、処理単位の機能ではなく、データ単位の意味づけを再整理することが目的となる。
また、VBAのような構造化言語においては、型安全なデータ構造が存在しないため、RangeやVariantを通じて柔軟にデータが受け渡される傾向がある。この柔軟性は初期設計を容易にする反面、同じデータを別の意味で解釈する危険性をはらんでいる。たとえば、売上表の「価格」列と「数量」列をそれぞれ引数として受け取る関数が複数ある場合、それらの関数間で共通の意味が保証されているかどうかは、設計者の記憶に依存している。ここで必要なのは、データ構造を明示的に定義し、それを参照しながら関数を再評価するプロセスである。この作業によって、データと処理の結びつきが明確化され、機能分割だけでは見落とされがちな責務の重複や漏れを発見できる。
3.2 データ単位での処理統合と整合性強化
関数群をデータ構造の観点で俯瞰すると、複数の関数が同じデータ構造を前提に処理を行っていることが分かる。これは言い換えれば、データを基準として処理のグルーピングが可能であることを意味する。この段階で重要なのは、同じデータ構造に対して行われている処理を洗い出し、それらを統合または再配置することによって、責務の整理と整合性の向上を図ることである。たとえば、売上データをもとに「グラフを描く」「合計を出す」「警告を出す」といった関数が分散している場合、それらを「売上データの分析」という抽象的な責務のもとに再配置することで、機能とデータの一貫性が生まれる。
整合性の強化とは、同じ入力に対して同じ出力が得られる設計、すなわち副作用の排除と前提の明示である。処理の中で「このセルに必ずデータが入っているものとする」といった暗黙の前提がある場合、それは整合性を崩す原因となる。データ軸での再設計では、関数がどのようなデータ構造を要求し、どのようなデータ構造を返すのかを明確に定義し、かつ可能であれば構造体に相当するユーザー定義型やクラスモジュールの導入を検討することも重要である。VBA環境下でも、ListObjectやDictionaryを用いることで、一定の構造化は可能である。
さらに、こうしたデータ単位の再編成によって、関数の呼び出し順序や依存関係も再構築される。これはすなわち、第二回目のトップダウン設計とは、単にデータの整理にとどまらず、データが流れる道筋を制御するための処理順序の再設計に他ならない。関数がどのような状態のデータを期待し、どのような出力を次に渡すのかを明示することで、モジュール間の結合度を下げつつ、整合性を保つアーキテクチャが構築できる。
4. 第3回目:責務軸による意味づけと再編
4.1 中間層に宿る意味と責任
機能とデータの両軸からの設計を経て、最後に求められるのは「意味」による整理である。処理単位として妥当であり、かつ共通するデータ構造を扱っていたとしても、それらの関数が果たして「誰のために、どのような意味をもって存在しているか」という責務の観点から検討したとき、まだ整理しきれていない中間的な構造が浮かび上がる。すなわち、関数は技術的には正しくとも、業務としての文脈や目的の中で初めてその存在が明確に意味づけられる。この段階では、関数に内在する暗黙の責任、つまり「この処理は誰の立場で行われているか」「この結果は何を伝えるためのものか」といった問いが中心となる。
たとえば、集計関数が単に数値の合計を返すだけではなく、「部門別レポートの作成に必要なフォーマットを整える」という目的を果たしているならば、その関数の責務は集計処理以上のものである。こうした「業務にとっての意味」を見極めることによって、中間層、すなわちアプリケーションロジック層の輪郭が形成される。これまでの分割が処理や構造の整理であったのに対し、ここでは業務責務による意味の集約が求められる。この意味軸の設計によって、関数群は単なる便利な道具から、業務に対する説明責任を持つ構成要素へと格上げされる。
4.2 業務共通関数・ドメインロジックの抽出
意味に基づく責務設計において重要となるのが、業務共通関数やドメイン固有ロジックの抽出である。業務全体を俯瞰したとき、各モジュールにまたがって繰り返し使われている処理が存在する。それらはしばしばコピーペーストや類似実装の形で散在しており、属人的な命名や処理順に依存している。責務の視点からこれらを再評価すると、「この処理は報告書作成業務の一部として、常にこの形式で使われる」「この関数は必ずエラーチェックとセットで呼び出される」といった業務的な前提が現れてくる。このような繰り返し現れる意味付き処理は、共通関数として抽出し、単独のモジュールに集約するべきである。
共通関数は単に再利用性の観点から有用なのではない。むしろ、共通化によって業務ルールが明文化されることが最大の価値である。たとえば「売上が0円の行は除外する」といった業務ルールが複数の箇所で個別に実装されていた場合、それを「売上有効データ抽出関数」として明示化することで、業務知識をコードの形で再現することができる。このようなドメインロジックの抽出は、設計の正当性を担保すると同時に、後続の変更に対しても堅牢な基盤を提供する。
4.3 意味による再統合の意義
責務の明確化と共通関数の抽出を経たあと、最終段階として行われるべきは「意味による再統合」である。これは、関数やモジュールを、技術的な関係性や呼び出し順序ではなく、業務的な文脈と責務の意味に基づいて再配置するプロセスである。たとえば、「日次処理」「月次処理」「報告書作成」といった業務フロー単位に再編することで、各関数の役割と意味がより明確になる。技術的には同様の処理であっても、使われる文脈が異なればその関数の振る舞いや期待される結果は変化するため、意味軸での整理は業務品質の安定化に直結する。
再統合はまた、保守性と説明可能性の向上にもつながる。関数の意味が文脈とともに整理されていれば、変更があった際にも影響範囲を容易に特定できる。また、新しい開発者や非技術者に対しても、「この関数群は請求書発行に関係している」といった形で説明することが可能になる。これにより、システム全体がブラックボックスではなく、「意味のある構造体」として運用されるようになる。最終的に、意味による再統合は、システムを単なるコードの集合体から、業務知識と論理の集約体へと昇華させる鍵となる。
5. 設計構造の成熟と再利用性
5.1 三層構造としての完成形(UI/Logic/Store)
三回にわたるトップダウン設計を経て、最終的にたどり着くべき設計の姿は、明確な三層構造である。すなわち、ユーザーインターフェース層(UI)、業務ロジック層(Logic)、データ管理層(Store)である。この三層構造は、各層が異なる責務を担い、相互に明確に分離されていることによって、設計の安定性と再利用性を高める。UI層はユーザーとの接点を担当し、入力や出力に関連する処理を限定的に扱う。Logic層は業務知識を中心に据え、処理の主たる意味と責任を引き受ける。そしてStore層は、データの取得・保存・更新といった低層の操作を担い、構造化された状態で情報を保持する。
このような層構造を実現するためには、各関数やモジュールにおいて「どの層に属するか」を明示することが必要である。たとえば、UI層に属する関数は、フォームからの入力値を受け取り、それをLogic層の関数へと引き渡すだけにとどめる。逆にLogic層では、UIの存在を一切意識せず、定義されたパラメータのもとで純粋に処理を行い、結果を返すことに徹する。そしてStore層では、対象のシートやテーブルからデータを取得・格納する操作を定義し、Logic層からの依頼に応じて動作する。
三層分離はコードの整理にとどまらず、変更に強い設計を生む。たとえば、UIの仕様変更があった場合でも、Logic層がUIに依存していなければ、そのまま再利用が可能である。Store層に関しても、テーブル名や列構造が変更された場合はStore層の実装のみを更新すればよく、Logic層やUI層のコードには一切手を加える必要がない。このように、層の独立性は設計の成熟度を表す指標であり、再利用性の前提となる設計思想である。
5.2 保守性・拡張性・説明可能性の確保
設計の成熟とは、単に機能が揃っている状態を指すのではない。それは、時間の経過とともに運用され、修正され、拡張されていく中でも破綻せずに構造を保ち続けられることを意味する。すなわち、保守性・拡張性・説明可能性の三要素が揃っていることが、成熟した設計の必要条件である。
保守性とは、既存の構造を壊さずに部分的な変更が容易であることを意味する。そのためには、各関数が副作用なく動作すること、そして依存関係が明確であることが不可欠である。三層構造の導入は、まさにこの保守性の基盤となる。
拡張性は、将来的な要件変更や機能追加に対して柔軟に対応できる能力である。層が明確に分離されていれば、新しいUIに差し替える、異なるデータソースに切り替える、といった拡張が最小限の影響で実現可能となる。VBAにおいても、Logic層のコードが純粋な処理ロジックとして抽出されていれば、それを他のアプリケーションや外部APIと接続する際にも、再利用可能なモジュールとして機能する。
説明可能性とは、コードやモジュールの設計意図を他者に説明できることを指す。これは属人化を防ぎ、チーム開発やドキュメント整備において極めて重要な要素である。三回設計法によって設計の由来が明確化されていれば、「なぜこうなっているのか」「どの処理がどの意味を担っているのか」を第三者に対しても明瞭に伝えることができる。これにより、設計は暗黙知ではなく、共有可能な業務知としてチーム内に定着していく。
最終的に、三層構造と三回設計を組み合わせることで、再利用可能であり、成長可能であり、共有可能な設計体制が確立される。これが、単なる個別のマクロやスクリプトを越えた「業務に組み込まれる仕組み」としてのVBA設計の完成形である。
6. おわりに
6.1 三回設計法の普遍性と応用可能性
本書を通じて提示した三回設計法は、VBAに限らず、あらゆる構造化言語、あるいは業務システム設計において適用可能な抽象的フレームワークである。その本質は、機能・データ・責務という三つの視点から繰り返し全体を見直し、各レイヤを通して設計を洗練させていくという循環的な構造思考にある。単なる一次元的なトップダウン設計では、部分最適や依存関係の混乱が生じやすいが、本手法ではそれぞれの観点での「再帰的整理」を繰り返すことで、結果として高い一貫性と可塑性を備えた構造を導出する。
特に業務ロジックが可視化されにくいVBAなどの環境では、実装と設計の境界が曖昧になりがちであるが、この三回設計法は、設計の可視化と責務の分離を強力に支援する。また、この方法論は小規模なマクロから中規模の業務システムまでスケーラブルに適用できるため、属人化したマクロの脱却や、標準化・再利用といった中長期的な運用基盤の整備にも貢献する。
さらに、他の技術要素――たとえばPower Query、GAS、Python、あるいはローコード開発ツールにおいても、同様の構造整理原則として応用可能である。システムの特性や技術レイヤが変わっても、「何をする関数か」「どのデータを扱うか」「どのような責任を持つか」という三つの問いは、常に有効であり続ける。すなわち、三回設計法は「ツールに依存しない構造的視座」として、今後も設計者にとって重要な手がかりとなるだろう。
6.2 より良い構造設計に向けた視点の推奨
設計とは、単なる作図や分割の作業ではない。それは、「なぜこのように分けるのか」「なぜこの形にしたのか」といった、思考のプロセスそのものであり、構造に込められた意図を他者と共有するための言語である。だからこそ、設計を磨くとは、構造を通じて他者と合意可能な思考の軸を作り上げることに他ならない。そのためには、見えている問題に反応的に対応するだけでなく、見えない構造の背景にある責務や意図に目を向ける習慣が求められる。
たとえば、単純な繰り返し処理であっても、「それは業務上どのような意味をもっているか」「変更が入ったときにどの層が影響を受けるか」といった観点から再評価することで、設計の粒度と責務の明確化が促進される。また、再利用や拡張といった未来の運用を視野に入れて設計することは、現在の課題に対する最善の答えを導くだけでなく、将来の選択肢を増やす設計的余白を残すことでもある。
本書で述べた三回設計法は、いわば「構造的に考えるための思考の型」である。設計において正解は常に複数存在するが、思考の型がなければその選択肢すら認識できない。よって、この三回設計法を単なる知識として終わらせるのではなく、日々の設計業務における反復的実践の中で身につけていくことを強く推奨する。思考の深さと構造の明晰さは比例する。構造を制する者は、実装を超えて、業務そのものを制することができる。
