トップダウンまたはボトムアップのどちらを設計するのが望ましいですか?


31

私が理解しているように、トップダウン設計は、最小の構成要素が定義されるまで、抽象的な高レベルの概念をより小さなコンクリートのわかりやすい部品に改良することです。一方、ボトムアップは低レベルのパーツを定義し、システム全体が形成されるまで徐々に高レベルのブロックを構築します。

実際には、2つの方法を組み合わせることをお勧めします。ドメインの知識、その関係、および制約を完全に指定するために、高レベルの仕様から始めます。問題が十分に理解されると、最小の構成要素が作成されてシステムが構築されます。

のプロセス:

  • 要件仕様の作成
  • 設計仕様を作成します(図を使用)
  • 実装する
  • 届ける
  • 繰り返します(反復開発では、各フェーズでチャンク全体を行うのではなく、少しずつ繰り返し行い、顧客の動的な要件に適応するために毎日ミーティングを行います)

私には完全に正常に見えます(仕様としての計画)。それには欠点がありますが、それが反復開発を行った理由です:1つのフェーズに時間を費やす代わりに、変更(場合によっては毎日)を受けるドメイン知識のあらゆる可能性を調査するための要件分析ではなく、少し分析します、少し設計してから実装します。

別の方法は、各反復がミニウォーターフォール形式であり、分析が数日(または1週間)で行われることです。同じことが設計にも当てはまります。残りの時間は実装に費やされます。反復的な開発と組み合わせたトップダウンアプローチには本質的に何か問題がありますか?

彼のエッセイであるプログラミングボトムアップでは、ポール・グラハムは完全にボトムアップからビルドを奨励するか、ボトムアップからプログラムするように思われますが、要件分析/設計段階ではありません。

経験豊富なLispプログラマーは、プログラムを異なる方法で分割します。トップダウン設計と同様に、彼らはボトムアップ設計と呼ばれる原則に従います-問題に合うように言語を変更します。

私が知る限り、彼が意味したのは、Lisperがまだトップダウン設計を実行しているが、プログラムはボトムアップであるということです。彼が書いた別のポイント:

ボトムアップ設計とは、同じプログラムを異なる順序で書くだけではないことを強調する価値があります。ボトムアップで作業すると、通常は別のプログラムになります。単一のモノリシックプログラムの代わりに、より抽象的な演算子を備えたより大きな言語と、その中に記述されたより小さなプログラムを取得します。まぐさの代わりに、アーチを取得します。

これは、Lispでプログラムを作成している間に、一般的なツールになるということですか?


おそらく、あなたが参照している本、論文、または記事へのリンクを提供すると、他の人があなたの質問に関してより理にかなった陳述をすることができるかもしれません。また、あなたの質問が具体的に何であるかは不明です。実装したい設計に関するいくつかの詳細についてアドバイスを求めていますか、それとも参照している記事について質問していますか?おそらく、個別に尋ねられるいくつかの質問に分解すると、これは読みやすく、答えやすくなります。
S.Robins

@ S.Robins要約すると、ソフトウェアを開発するための通常のトップダウンのアプローチを示しました。ただし、ボトムアップを好む人もいれば、有名人のポール・グラハムもいます。ボトムアップ設計が一般にどのように役立つか、特にLispには、奨励する特別な機能があるため(Paulが提案したように)どのように役立つかを理解してください。
アムム

1
Amumuどちらの答えもとにかくスキップしたように見えるので、例を編集しました。質問は簡潔にして、質問ごとに質問を1つだけにしてください。
ヤニス

回答:


35

トップダウンは、知っていることを説明したり、既に構築したものを再構築したりするのに最適な方法です。

トップダウンの最大の問題は、多くの場合、単に「トップ」がないことです。システムの開発中およびドメインの探索中に、システムが何をすべきかについて考えを変えます。どのようにして、あなたが知らないこと(つまり、システムに何をしてもらいたいか)の出発点になりますか?

「ローカル」トップダウンは良いことです...コーディングより先に考えることは明らかに良いことです。しかし、考えすぎて計画を立てることはそうではありません。なぜなら、あなたが想像しているのは本当のシナリオではないからです(以前にそこに行ったことがない場合、つまり、構築していないが再構築している場合)。新しいものを構築する際のグローバルなトップダウンはナンセンスです。

ボトムアップは、問題の100%を知っている場合を除き、(グローバルに)アプローチである必要があります。既知のソリューションをコーディングするだけでよく、可能な代替ソリューションを探す必要はありません。

Lispアプローチは、蒸留されたボトムアップです。ボトムアップでビルドするだけでなく、必要に応じてレンガを形作ることもできます。何も固定されておらず、自由は完全です。もちろん自由には責任があり、この力を悪用することで恐ろしいものを作ることができます。

しかし、恐ろしいコードはどの言語でも書くことができます。心のためのケージのような形をした言語でさえ、それらの言語で猿でも良いプログラムを実行できるように設計されています(考えているだけでも痛いほど多くのレベルで非常に間違った考えです)。

あなたの例はウェブサーバーについてです。2012年には、これは明確に定義された問題であり、従うべき仕様があります。Webサーバーは単なる実装上の問題です。特に、そこにある他の数十億のWebサーバーと実質的に同一のWebサーバーを作成することを目指している場合、いくつかの特徴を除いて、実際には何も明確ではありません。RSAについてのあなたのコメントでさえ、正式な仕様で明確に定義された問題について話し続けています。

明確に定義された問題、正式な仕様および既知のソリューションを使用すると、コーディングはドットで接続されます。トップダウンは大丈夫です。これがプロジェクトマネージャーの天国です。

ただし、多くの場合、ドットの接続に使用される実証済みの既知のアプローチはありません。実際には、ドットとは何かを言うのも非常に困難です。

たとえば、自動切断機に、切断する部品を理論上の反復ロゴに完全に適合していない印刷物に合わせるよう指示するように求められたとします。機械で撮影された材料の部品と写真が提供されます。

アライメントルールとは何ですか?あなたが決める。パターンとは何ですか?あなたが決める。部品の位置合わせ方法は?あなたが決める。部品を「曲げる」ことはできますか?依存するものもあれば、そうでないものもありますが、もちろんそれほど多くはありません。材料が変形しすぎて部品が許容範囲内で切断できない場合はどうすればよいですか?あなたが決める。材料ロールはすべて同一ですか?もちろんそうではありませんが、ロールごとにアライメントルールを調整するようにユーザーをバグにすることはできません...それは非現実的です。どの写真がカメラを見ていますか?マテリアルは、それが何を意味するにせよ...それは色でありえ、光反射だけでパターンが明らかになる黒の上に黒であることができます。パターンを認識するとはどういう意味ですか?あなたが決める。

次に、この問題の解決策の一般的な構造を設計し、お金と時間で見積もりを出してください。私の賭けは、あなたのシステムアーキテクチャさえ...(そう、アーキテクチャ)が間違っているということです。コストと時間の見積もりは乱数になります。

私たちはそれを実装し、現在は動作するシステムになっていますが、システムの形について何度も気が変わりました。メニューからもアクセスできないサブシステム全体を追加しました。プロトコルでマスター/スレーブの役割を複数回切り替えました。おそらく今、私たちはより良い再構築を試みるのに十分な知識を持っています。

もちろん、他の会社も同じ問題を解決しました...しかし、これらの会社のいずれかに所属していない限り、おそらくトップダウンの詳細なプロジェクトは冗談でしょう。トップダウンで設計できます。前にやったことがないからできません。

おそらく同じ問題も解決できます。ただし、ボトムアップで作業します。あなたが知っていることから始めて、あなたが知らないことを学び、合算します。

新しい複雑なソフトウェアシステムは、設計ではなく成長しています。時々、誰かが大きな新しい複雑で不特定のソフトウェアシステムをゼロから設計し始めます(大きな複雑なソフトウェアプロジェクトでは、3つの可能性しかありません。またはc]両方...そして、ほとんどの場合[c]が該当します)。

これらは、パワーポイントスライドとUMLダイアグラムだけに数千時間も費やされる典型的な大企業プロジェクトです。それらは、恥ずかしいほどのリソースを燃やした後は必ず完全に失敗します...または非常に例外的なケースでは、初期仕様のほんの一部だけを実装する高価なソフトウェアを最終的に提供します。そして、そのソフトウェアは常にユーザーから深く嫌われています...あなたが買うソフトウェアの種類ではなく、あなたが強制されているために使用するソフトウェアの種類です。

これは、コードだけを考えるべきだと思うということですか?もちろん違います。しかし、私の意見では、構築は下から始まり(レンガ、具体的なコード)、上に行く必要があります...そして、細部への焦点と注意は、あなたが持っているものから遠くなるにつれて、ある意味「フェード」するべきです。トップダウンは、多くの場合、システム全体に同じレベルの詳細を一度に配置する必要があるかのように表示されます。すべてが明らかになるまで、すべてのノードを分割し続けるだけです。現実のモジュールでは、サブシステムはサブルーチンから「成長」します。特定の問題で以前の経験がない場合、サブシステム、モジュール、またはライブラリのトップダウン設計は恐ろしいものになります。どの関数を挿入するかがわかれば、適切なライブラリを設計できます。

Lispのアイデアの多くは人気が高まっています(ファーストクラスの関数、クロージャー、デフォルトとしての動的型付け、ガーベッジコレクション、メタプログラミング、インタラクティブな開発)あなたが必要なもののために。

たとえば、キーワードパラメータはすでに存在しますが、存在しない場合は追加できます。私が試しているおもちゃのLispコンパイラ用に(コンパイル時のキーワード検証を含めて)実行しましたが、コードはあまり必要ありません。

代わりにC ++を使用すると、キーワードパラメータはそれほど有用ではない、または非常に複雑で壊れた、裏付けのあるテンプレート実装であり、実際にはそれほど有用ではないというC ++の専門家の集まりが得られます。C ++クラスはファーストクラスのオブジェクトですか?いいえ、それについてできることは何もありません。実行時またはコンパイル時にイントロスペクションを使用できますか?いいえ、それについてできることは何もありません。

Lispのこの言語の柔軟性は、ボトムアップの構築に最適なものです。サブルーチンだけでなく、言語の構文とセマンティクスも構築できます。そしてある意味で、Lisp自体はボトムアップです。


はい、私が意味したのは地元のトップダウンでした。要件を改善し続け、反復を通じて進化させます。トップダウンのポイントは、可能な限り正しいコード構造を取得することです。継続的なリファクタリング。たとえば、最初は関数に文字列を渡す必要がありますが、後で変更に対応するにはクラス全体が必要であり、関数がすでにどこでも使用されている場合はリファクタリングに時間がかかります。
アムム

明確に知られている方法で明確に知られているものを再構築するには、トップダウンで構いません。Webブラウザはこの例です。プログラムのすべての変数に保持されている値のすべての型を(ひどい構文を使用して)予期して正式に指定することを強制するC ++のような言語を使用しても、実行可能なオプションです。
6502

私の例はデータ通信の基本的な知識を持つ人によって作成されたものであり、C ++コードはドメインの知識(この場合はネットワーク)からの非常に基本的な設計の結果であると仮定しているため、私の例は明確に知られた方法ではないと思います。これは進化設計の例です。次の反復では、開発者はドメインの知識についてさらに学習するため、進化した知識に合わせて設計を拡張します(Webサーバーのすべてのレイヤーにセキュリティの側面を追加するなど)。次に、新しい設計に従って実装を改良します。
アムム

ここでのポイントは、ドメインに依存しない言語から派生した実際のソリューション(自然言語、数学言語など)はドメインに依存することです。コーディングの行為は、生成されたソリューションからコードへの単なる詳細なマッピングです。
アムム

1
こんにちはMr.6502 1年後、私はより多くのことを学んだので、あなたの言ったことが真実になるのを見始めました。私は別のスレッドを作った:programmers.stackexchange.com/questions/179000/...を。時間があれば、私の考えをもう一度明確にしてください:D。
アムム

6

この答えがLispにどのように適用されるかはわかりませんが、アジャイルの原則、パターン、および実践を読み終えたばかりで、著者のボブおじさんはC#(C ++にも適用可能)のトップダウンアプローチを強く推奨しています。同意します。

ただし、トップダウンアプローチでは最初の対話ではドキュメントと全体的なデザインのみを提供するという結論を導き出した他の回答とは異なり、この本は別の方法を指します。TDDと進化的デザインの組み合わせです。

アイデアは、最上位から始めて、最高の抽象化レベル(またはローカル最高)を定義し、それらが定義されるとすぐに、機能#1がすぐに機能するように有用な作業を行うことです。その後、より多くの機能を追加するにつれて、コードをリファクタリングし、必要に応じて設計を進化させながら、常にSOLIDの原則を認識し続けます。このようにすると、抽象化レイヤーが多くなりすぎず、全体的なアーキテクチャに適合しない低レベルのデザインになりません。これが何を意味するのかわからない場合、上記の本には、開発者が概念を取り入れ、UMLダイアグラムと低レベルクラスから始める例を含む章全体があります。このアプローチでは、本質的に、プロジェクトでより高レベルの詳細が定義されると、低レベルのコードが自然にプッシュダウンされます。

そして最後に、SOLIDを実践する場合、高レベルの抽象化が定義されている状況に陥ってはならず、その後、詳細に入り、OODや抽象化がないことに突然気付くべきではありません。それは実際にはトップダウン設計のせいではなく、怠engineeringなエンジニアリングです。

XPと進化的設計についてさらに詳しく知りたい場合は、もう1人の偉大な著者であるMartin Fowlerからの良い読み物があります。「Design Dead?」


パーフェクト。これが私が話していることです。また、SOLID原則について知っておくと便利です。また、アジャイルはトップダウンアプローチをサポートします(TDDとXPでは、人々はできるだけ早くコードにジャンプし、ドキュメントを避けると思いました)。
アムム

@Amumu:Fowlerが書いた別の記事へのリンクを追加しました。設計/ドキュメントのないカウボーイコーディングと、XP / Agileが実際に推進しているものとの違いについて詳しく読むことができます。個人的には、ドキュメントには価値があると強く信じており、デザインドキュメントを維持するためにチームを積極的に推進してきましたが、徐々に見解を変えてきました。現在、「設計タスク」はすべてホワイトボード/ナプキンタイプのものですが、実際のドキュメントはストーリーが書かれた後にのみ更新されます。また、ドキュメントが唯一のハイレベル/アーキテクチャのものをカバーするように、実際に文書化されているものに縮小されてきた
DXM

3

私にとって、Paul Grahamが彼の記事で述べている最も重要な発言は次のとおりです。

[...] Lispプログラマー[...]は、ボトムアップ設計と呼ばれる原則に従います。問題に合わせて言語を変更します。Lispでは、プログラムを言語に向けて書き留めるだけでなく、プログラムに向けて言語を構築します。

または、C ++界で知られているように:ライブラリデザインは言語デザイン(Bjarne Stroustrup)

トップダウン設計の主なアイデアは、最初に計画を立て、次にコーディングを行うことです。Beanowは、実行可能コードがプロセスの後半に来ると問題が発生すると書いています。ボトムアップ設計では、常にコードがあり、そのコードをテストできます。

また、コードはフラットではありません。つまり、より抽象度の高いレベルを持つ傾向があります。トップダウン設計では、多くの場合、任意のレベル以下の抽象度のない大きなアブストラクトになります。ボトムアップで設計されたコードOTOHは、抽象化される可能性が高いため、多くの場合、低レベルの制御とデータ構造を含みません。


2

理想的には、Lispだけでなく任意の言語でプログラムを作成すると、次のプログラムの速度を上げたり、現在のプログラムの機能強化を加速したりできる汎用ツールのセット全体を作成できます。

実際には、これらのツールを追跡することは困難です。ドキュメンテーションは貧弱で混乱しており、それらについて知っている人々は去っていきます。実際には、コードの再利用は多くの場合、それが価値があるよりも厄介です。しかし、コードが適切に文書化および編成され、プログラマーが固執する(または便利なコードを独自に提供する)場合、再構築するのではなく、ウェアハウスからコードを取得することで膨大な作業を節約できます。

すべてのデザインはトップダウンである必要があります。さもないと、自分が何をしているのかわかりません。小屋や車を建てていますか?ボトムアップ設計のものはわかりません。しかし、左フロントホイールを構築する場合、このプロジェクトと他のプロジェクトの両方で、後でさらに多くのホイールが必要になると考えるかもしれません。そして、再利用可能なホイールを構築する場合、1つの価格で4つ使用できます。(そして、あなたが次に建設しているそのトラクター・トレーラー用の18は、すべて無料です。)

実際の車や実際のホイールとは異なり、1つのソフトウェア「ホイール」を作成した場合、無限の数のホイールを作成したことに注意してください。

トップダウン設計の詳細:これから始めなければなりません、ホイールを構築できない場合、車で多くの作業を行う前にそれを見つける必要があることを指摘する義務があります。したがって、トップダウンでの作業とほぼ並行してボトムアップで作業する必要があります。また、車輪組み立てることができるということは、トラクタートレーラーのように、これまで考えもしなかった多くのプロジェクトを示唆する可能性があります。トップダウンのアプローチが支配的である必要があると思いますが、非常に軽いタッチです。

したがって、Paul Grahamの言い換えを続けると、理想的にはプログラムを書くときに、元のプログラムと他のプログラムの両方で多くの時間を節約できる再利用可能な部分がたくさんあることになります。Paul Grahamから少し距離を置くために、これはどの言語でも機能します(ただし、一部の言語は他の言語よりもプロセスを促進します)。

このほぼ魔法のようなプロセスの敵は、非常に短期的な見通しを持つプログラマーです。これは人格の欠陥に起因する可能性がありますが、より一般的には、雇用する企業の内部および企業間で、職と責任の切り替えが速すぎることが原因です。


2月16日から返信があり、受信トレイに何も表示されませんでした。私はあなたに同意します。非常に軽い計画であっても常に計画を立て、それから少し構築してから計画を洗練する必要があります。それは完全に合理的です。しかし、多くの開発者がコードを書いている間、頭の中ですべてを計画するのが好きな理由を理解していないようです。かなりの時間を節約でき、実装プロセスに沿ってコードアーキテクチャを継続的にリファクタリングするのではなく、実際の問題にもっと集中することができます。
アムム

@Amumu執筆中の計画の1つの理由:一部のプログラマは、計画プロセスではなく、コーディングのボトルネックであるキーボードとマウスの操作についてよく知っています。(再利用可能なコードは、彼らが思考を再び困難な部分にする新しい創造的な仕事をすることを可能にします。)
RalphChapin

@Amumu執筆中に計画するもう1つの理由:言語/プログラマ/問題の組み合わせによっては、言語が問題を考える最良の方法です。言語はあなたの考えを「紙」に書く最も簡単な方法です。私はあちこちでLispについて少しだけ読んだことがありますが、それから私はLispについて特に良いと思います。(一部の言語は、最初に問題を表現する方法として作成されたもので、機械にそれを解決させるのではありません。)コードを考えと同じように簡単に再配置できる場合は、コードも可能です。しかし、これが機能するためには、プログラマー、言語、および問題がうまく調和しなければなりません。
ラルフチャピン

信頼できます。計画のアイデアは、ドメインの概念と実際のプログラミングプロセスとの間のドメインの知識と関係の識別を分離することです。他のクラスと通信するためのインターフェースを作成する計画が十分にない状態で、あるクラスが他の多くのクラスで使用されているとしたら、簡単に統合とリファクタリングを行うことができます。この場合、コードの入力と再構築に費やされる時間は、紙での識別に費やされる時間を大幅に上回ります。
アムム

例を見てみましょう。クライアント/サーバーアプリケーションを作成しているとします。交換メッセージ、メモリ内でのメッセージの配置方法(ヘッダー16バイト、ID 4バイトなど)を定義してプロトコルを識別する必要があります。図はモデリング/計画とは異なります:abstratt.com/blog/2009/05/03/on-code-being-model UMLはOOPにのみ焦点を合わせているため、UMLまたはダイアグラムを使用してモデル化する必要はありません。UMLクラスダイアグラムの入力に費やされる時間は、実際のコードを入力するよりも少なくありません。
アムム

1

反復開発と組み合わせたトップダウンアプローチの何が問題になっていますか?

反復的な開発でトップダウンアプローチを使用しても、最初の反復で動作するコードは提供されません。設計ドキュメントなどを提供し、顧客はフィードバックを提供するのに苦労します。「そうだと思う(これは私には抽象的すぎる)」などの応答は、顧客が希望するシステムの詳細をさらに指定するのに役立ちません。

代わりに、要求内容の一般的な概要のみを作成します。(要件)完成品を定義するものと実装する優先度に値するものの一般的なガイドラインとして使用する。そこから、顧客が実際にいじって、これが彼らが念頭に置いていたものであるかどうかを見ることができる、反復ごとに実用的な製品を作成します。そうでなければ、顧客が現在求めているものとは異なるシステムを設計するのに何百時間も費やしていないので、問題にはなりません。

ポール・グラハムはボトムアップでのビルドを完全に奨励しましたか?または、要件分析/設計段階ではなく、ボトムアップでプログラムしますか?

私は他の人のために話をしません。また、私は彼のエッセイを読みませんでした。私があなたに与えている答えは、私の教育と経験から来ています。

つまり、Lispでプログラムを作成している間に、元のプログラムと同様のプログラムを作成するために使用できる汎用ツールになりますよね。

このアプローチを使用すると、より抽象的な構成要素になります。すぐに提示できるスタンドアロンのサブシステムを構築する必要があるため、重く絡み合って一度に実装する必要があるトップダウン設計を作成することはできません。再利用性、保守性が向上しますが、ほとんどの場合、変更に対するより柔軟な対応が可能になります。


1
太字は、あなたが既にブロック引用している場合、私の目には不要です...
mk12
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.