アジャイルやXPなどの進化的手法で設計の行き詰まりに陥った場合はどうしますか?


11

Martin Fowlerの有名なブログ記事Is Design Deadを読んでいたとき 、私が得た印象的な印象の1つは、アジャイル方法論とエクストリームプログラミングでは、デザインとプログラミングが進化的であるという事実を考えれば、物事をリファクタリングする必要がある点が常にあるということです。

プログラマーのレベルが高く、設計の意味を理解し、重大な間違いを犯さない場合、コードは進化し続ける可能性があります。しかし、通常の状況では、この状況での地上の現実は何ですか?

ある重要な開発が製品に組み込まれている通常の日には、要件に重大な変更が生じた場合、それがどれだけ望むかという制約ではないので、基本的な設計の側面を変更することはできませんか?(コードの大部分を捨てずに)。設計と要件のさらなる可能な改善で行き止まりに達する可能性は非常に低いですか?

ここではアジャイル以外のプラクティスを提唱していませんが、実際の経験に関しては、アジャイル、反復、または進化の開発方法を実践している人々から知りたいです。

あなたはそのような行き止まりに達したことがありますか?どうやってそれを避けたり、逃れたりできましたか?または、デザインが進化してもクリーンで柔軟なままであることを保証する手段はありますか?

回答:


17

私はあなたが投稿した記事のリンクを読みました。ファウラーはいくつかの非常に良い点と彼が言った多くのことを言ったと言わなければなりません。

IMO、まともな設計を行う場合、行き止まりの状況と考えられるものに入るべきではありません。私は常にソフトウェアをビルディングブロックで構成されていると見てきました。私はまだいくつかの事前設計を信じていますが、主な目標は製品全体を設計することではなく、全体的なアーキテクチャ/方向性を提供してチームが共通の全体像を視覚化できるようにすることです。キューブと三角形のピースがたくさんある場合は、ピースをたたくだけで始める前に、城がどのように組み立てられるかをスケッチすると役立ちます。

私はオブジェクト指向の土地から来ているので、私にとっては各ブロックはクラスであり、そのブロックの表面積はパブリックインターフェイス(外部または派生クラスから見えるもの)です。適切なSOLIDの原則に従うと、各ブロックが非常にシンプルで、直感的なパブリックインターフェイスを備えていることを確認できます。私の例えに戻って、コードは単純な形状のみを作成するようにします。複雑すぎるクラス(多くの関数、多くの変数)を作成するときはいつでも、要件の変更時に再利用が困難な形状を作成します。

進化的設計の最大のリスク/挑戦は、設計の決定をコーディング時間に任せ、個々の開発者がそれらの決定を行うことを期待することであるという点で、私はFowlerに同意します。適切なフィードバックメカニズムが整っていない場合、システムが故障する可能性があります。新しい機能が求められたときはいつでも、単純に拡張する必要のある関数を見つけ、その中にある種の条件を入れて、その関数の中に大量のコードを追加するだけです。また、これで十分な場合もありますが、これは(IMO)デッドエンドコンポーネントにつながる最も一般的な唯一のプラクティスでもあります。これは進化的デザインとは関係ありません。これは、いわゆる「デザインなし」です。

時間をかけて少し待って、このクラスにはすでに15個のメンバー変数があり、そのうち6つを抽出して、独自の自己完結型のクラスに入れれば、ソフトウェアは非常に軽量になります。 -重量、柔軟性、再利用可能なビルディングブロック。PMが来て、あなたの製品要件の半分を変更したら、ブロックをいくつか取り出して棚に戻し、新しいブロックを作成する必要があります(城を建設するときのように、すべてを使用することはできません)あなたのシリンダー)。しかし、その時点では、それはビジネスの一部にすぎません。要件が変更され、コードの柔軟性とモジュール性を維持することにより、新しいビジネスの方向性に合わせて製品を変更できるはずです。

設計に対するこの進化的なアプローチは、あらゆるレベルのエンジニアのスキルで機能すると考えています。個人的に、私は非常に長い間ソフトウェアを開発してきました。私たちのチームがアジャイル手法に移行する前に、開発用PCからいくつかの主要コンポーネントをほとんど直接QAなしで顧客に出荷する責任がありました。同時に、これらのコンポーネントは常に柔軟性と保守性を維持しています。

私は自分がソフトウェアを設計するのに比較的まともだと考えていると言っているだけです。同時に、100ページのデザインドキュメントを作成し、それをコーダーに渡し、それが機能することを期待するように頼んだ場合、おそらく紙袋から自分でデザインすることはできませんでした。作業を開始するときに、UMLのような(非常に単純化された、完全な言語ではない)図をいくつかスケッチすることもありますが、コーディングを開始すると、必要に応じてリファクタリングし、最終的なコードは元々描いたもののようにはなりません。1か月か2か月かけてすべての細部を考えても、他の誰かが自分のダイアグラムを作成し、コーディング中に設計を変更せずに堅実なソフトウェアを思い付くことができるとは想像できません。

スペクトルのもう一方の端では、現在私のチーム(現在アジャイルであり、私はそれを完全にサポートしています)に、過去15年間だけCを行った組み込みの土地から私たちに加わった2、3人の男がいます。私は明らかに初期の計画とクラスのレイアウトを手伝いましたが、定期的なコードレビューとブレインストーミングセッションでフォローアップを行い、SOLIDのアプリケーションと設計原則について話し合いました。彼らはスパゲッティコードをいくつか作成してくれたので、少しうんざりさせられましたが、ほんの少しのナッジで、すでに作成されていたもののリファクタリングを開始しました。それを言うために、しかしそのコードを移動した後、これははるかに読みやすく、理解しやすいように見えます。行き止まりは回避されました。ポイントI ' 作成しようとしているのは、OOに完全に慣れていない人でも、経験豊富なメンターがいれば、「進化的デザイン」は「デザインなし」と同じではないことを思い出させるために、ある程度まともなコードを生成できるということです。そして、彼の「より複雑な」クラスのいくつかでさえ、各クラスがそれほど責任を負わないため(つまり、それほどコードがないため)、それほど怖くはありません。それをチャックして、同じパブリックインターフェイスを持つ代替クラスを記述します(これまでのところ、この偶然性の必要性は、私たちが書いたもので見たことがなく、コードレビューを週に2回行ってきました)。

最後の注意点として、私はデザインドキュメント(少なくとも現在のチームのビジネス条件)を固く信じていますが、デザインドキュメントの主な目標はOrganizational Memoryであるため、実際のドキュメントはコードが生成され、リファクタリング。コーディングする前に、通常、ナプキン/ mspaint / visioのクラスをスケッチする簡単な(時にはそれほど速くない)設計フェーズがあります。このフェーズでは、設計図ではなく、コーディングを開始するときに、従うべきパスが生成されることを常に思い出します。意味をなさないものは変更する必要があります。これらのリマインダーを使用したとしても、新しい人は、たとえたとえそれが彼らにとって不自然であっても、元のデザインにコードをフィットさせようとする傾向があります。これは通常、コードレビューで表面化します。

ダン、私はたくさん書いた。ごめんなさい


1
+1単語ごとに価値がありました。あなたが説明したようにこれらの状況に出くわし、期限が過ぎた後、デザインの常識だと思うものからもっとクリーンアップ(リファクタリングを読む)するよう依頼します。しかし、多くの場合、同じ質問が繰り返されることに気づきます-なぜこの同じことを再びするのですか?今、私は答えを持っていると思います-市場投入までの時間を短縮し、デザインを進化させる必要がある場合、リファクタリングはあなたの古い罪の代償ではなく、実際に行うべき正当なことです。
ディパンメタ

はい、たくさん書きましたが、それは良いことでした。それを読んで本当に楽しんだ:)。
ラドゥムルゼア

11

「設計の行き止まり」現象は、アジャイル手法に直交していると思います。つまり、ウォーターフォールを行い、(悪い)デザインに多くの時間を前もって費やすことができるということです。次に、行き詰まりに陥るまで、多くの時間をかけて実装します。

どちらかといえば、アジャイル手法、悪い設計選択をしたことを早期に発見するのに役立つはずです。この理由は、バックログで顧客価値の最も高い項目を最初に実行し、ソフトウェアの有用な増分を提供することに集中する必要があるためです。デザインが高い価値と有用性を提供できる場合、それはすでに何かに適しています:-)対照的に、滝のような状況では、このデザインが提供できないことを長年にわたって見つけられないかもしれない悪いデザインを持つ可能性があります任意の値と任意の有用性-あなたが持っているのは、それが良いデザインであるという幻想です。彼らが言うように、証拠はプリンにあります。

逆に、アジャイルな方法であっても、反復から反復へと決定を下すシステムの設計に対する実行可能なビジョンを持つことが重要です。ケン・シュワバーは、ひどい開発者のチームがいると、イテレーションごとに一貫して悪いソフトウェアを生産するだろうと言ったと思う。アジャイルとは、実装を開始する前に学習または想像できることが限られているため、事前に多くの時間を費やさないことを意味します(そして要件も変わります)。ただし、事前の作業(研究など)を実行しなければならない場合があります。

行き止まりをどのように回避しますか?

私は、主に将来の要件を予想することで言うでしょう。これは、同様のプロジェクト/製品に関する経験と知識があれば得られるものです。現在のシステムについて多くの「what if」質問を自問するので、この予想は、部分的に良いデザインを配置するのに役立ちます。私にとってこれは重要なコンポーネントです。OOのようなテクニックは、自分が何をしているかを既に知っているときに、単にあなたを助けます。

行き止まりの場合はどうしますか?

「行き止まり」は、斬新なものの開発中ヒットする他の技術ブロックと変わりません。最初に気付くのは、完全に後戻りすることを余儀なくされる真の「行き止まり」がないことです。少なくともこの時点までの学習は、努力が無駄にならないように前進することを可能にするものです。あなたが行き止まりを打つとき、あなたは問題を抱えています。問題は、新しい(または古い)要件を満たすために変更する必要があるものと、この変更を最適化する方法です。この問題を解決するだけです。変更ははるかに簡単であるため、これはソフトウェアであり、たとえば飛行機の設計ではないことに感謝してください。問題を特定し、修正します==リファクタリング==ソフトウェアエンジニアリング。時には多くの作業が関係しています...

スクラムを使用する場合、この変更は当然ユーザーストーリーに基づいて行われる必要があります(ユーザーはこの変更から何を得ますか?)このプロセスは、現在の設計では簡単に対応できない1つのストーリーから始まり(oops)、このストーリーをどのように分解するかについて製品オーナーと議論が行われます。この変更を通じてアジャイルの原則を適用し続けます。

私の頭に浮かぶOSの世界からのいくつかの有名な大きな要件の変更:

これらをどのように見るにせよ、彼らは多くの仕事です。元の設計では、ほぼ確実にこの問題が発生する可能性を考慮していませんでした(つまり、移植性は大きな要件ではありませんでした)。デザインがオブジェクト指向であったかどうかは、おそらく大きな要因ではありません。優れた設計では、プラットフォーム固有の部分がある程度分離され、作業が容易になります。


実際、Windows NTの初期のバージョンは「ハードウェア抽出レイヤー」を実装し、DEC Aphaとx86をサポートしていました。誰もDEC alphaベースのマシンを購入したことがないため、これは静かに削除されました。この「マシンの独立性」は、現在のリリースではまだ痕跡のある形式で存在しているため、ARMポートはそれほど難しくないかもしれません。
ジェームズアンダーソン

3

プロジェクトを永続的にリファクタリングし、UMLクラス図も使用します。つまり、パッケージによって1つ以上のクラス図を作成します。各図は、パッケージのルートに保存されます。各UML分類子には、関連するJava IDにマップされる独自のIDがあります。つまり、ダイアグラムを開くと、最新のコードリファクタリングの変更に自動的に更新されます。グラフィカルレベルでクラス図を直接変更することもでき、すべてのプロジェクトはすぐにリファクタリングされます。それはかなりうまく機能しますが、人間に取って代わることは決してありません。UMLクラス図も、コードのグラフィカルビューにすぎません。リファクタリングが完了するとすぐにモデル情報も失われるため、EMF Eclipseのようにコードとモデルを混在させないことが非常に重要です。これは役に立たないので、モデル駆動開発コードジェネレーターは使用しません。しない

私のプロジェクト構造のすべての詳細を表す100以上のクラス図を持ち、どこにでもメモがたくさんあると言って本当に助かります。通常、開発者は他の図を学習したり使用したりする時間がないため、プロジェクトのクラス図のみを作成します。クラス図も自動的に更新されるため非常に優れています。クラス図は、パッケージを反転してメモを追加するだけで、コードの後に​​作成できます。高速で常に正確で、100%反復的です。

コードを生成するモデルであるモデル駆動型開発と、通常はコードから更新されたUMLクラス図でグラフィカルなプレゼンテーションとしてUMLを使用することとを混同しないでください。複数の繰り返しを行う場合、UML同期コードのみが実際の値を持ちます。

長くなってすみませんが、プロジェクトのグラフィカルビューとしてのみ使用する場合は、UMLクラス図に2回目のチャンスを与えるべきだと思います。これは、UMLがプロジェクト全体をカバーし、プロジェクト全体を表す大規模なクラス図で構成される単一のモデルを持つことを意味します。数百のビューを持つプロジェクト内に、数百の小さなビューと各ビューのモデルがあるのはばかげているでしょう:-)


1
投稿コードUMLのアイデアを示すために+1!興味深いことに、コードの後でダイアグラムドキュメント戻ることはありません。
ディパンMehta

はい、これはまさにUMLに関連するモデル駆動型開発の問題です。ドキュメントを生成し、プロジェクトが変更された場合は使用しないでください。モデルとコードのマージにより、UMLを使用し、必要に応じて何度でも変更できます。
UML_GURU

3

悪い設計、方向の変更などのために、コードや他のコードが行き止まりになりました。他の多くの人がこの問題にぶつかるのを見ました。大きな間違い(少なくとも、私には間違いのように思えます)は、動作中のコードを捨てて、すべてをゼロから再実装したいという即座の欲求です。

私はそれぞれのケースに同じようにアプローチしましたが、うまくいくようです:

  • 現在の設計が機能していない理由を特定する
  • 新しい設計移行計画を考え出す
  • 非推奨として使用されないコードにタグを付けます
  • 差し迫ったニーズを満たすために、新しいデザインに必要なものだけを実装する
  • 新しいコードで廃止されたコードを削除する

費用:

  • 同時にコードベースに2つの実装を行うため、より複雑になります
  • 優れたユースケースとテストを想定した完全な再設計/再実装を行うよりも、機能/バグ修正ごとの総コストが高くなります

利点:

  • 古い作業設計/コードがまだ残っているため、少なくとも1桁のリスクが軽減されます。
  • 完全な再設計を必要としない1〜n-1の機能の市場投入までの時間を短縮
  • 完全な再設計を完了する前に製品/コードが死んでしまう場合、開発時間の差を節約できます。
  • 反復アプローチとそこにあるすべての利点

2

約1〜2年前、現在のプロジェクトは、SCRUM開発スタイルを使用したいくつかの不適切な設計決定(および1か所に多くの設計の欠如)が原因で少し行き詰まりました。

私たちのソリューション(そしてSCRUMの標準的なものだと信じていること)は、リファクタリング以外にスプリント全体(約2週間)を捧げることでした。この期間中に新しい機能は追加されませんでしたが、現在のコードベースについて考え、私たちがやっていることに対してより良いシステムを設計することができました。

私たちは今、そのハードルを過ぎており、新しい機能を再び追加しています。


これは別の大きな摩擦です。最初のバージョンが引き渡された後、新しいものではない機能について、顧客に言う必要があります。これを顧客にどのくらいの頻度で、また頻繁に(もしあれば)伝えることができますか?またはどのように説明しますか?
ディパンメタ

2つの基本的なオプションがあります。最初に単純な真実を伝えるだけです。つまり、持っているものが混乱して前進するために整頓する必要があるが、2つ目は進行中の開発をサポートするインフラストラクチャを構築するということです(これも同様ですが、少しポジティブになるようにスピンされます)。機能を提供するために、現在返済する必要がある技術的負債が発生したと言うことで、これらの両方をまとめることができます。
マーフ

@Dipan Mehta:顧客が2階建ての家を望んでいるとします。あなたはそれを設計し、提供します。それから、彼らは4つの追加の階を持ちたいです。現在の建物をさらに堅牢にするためだけにこの時間を費やさなければならないと言います。したがって、元の計画に2階建てしか含まれていない場合、これは顧客にとって問題になるとは思わない。当初から6階建てが計画されていた場合、はい、顧客に伝えるのは問題かもしれません。
ジョルジオ

@DipanMehtaまた、顧客がこのプロジェクトについて必ずしも知っているとは限らないという点でも少し幸運です。現在使用している製品へのアップグレードであり、半ば曖昧な完成日は今年の終わり頃です。彼らはそうでもリファクタリングのための遅延について知る必要はありません。)(設計上の決定のほとんどを扱う管理者が社内である)
Izkata

2

設計変更のコストを制限する鍵は、コードを可能な限りドライに保つことです。これにより、ほとんどのアプリケーションコードが非常に高いレベルになり、ほとんどのコードが意図を直接表現し、メカニズムを比較的わずかに指定します。これを行うと、設計上の決定はコード内で可能な最小の式を持ち、設計変更は最小のコストで済みます。


2

設計の行き止まりを回避するための鍵は、設計を変更する必要がある場合、できるだけ早く認識し、それを変更することです。最大の問題は、設計を継続的に進化させることではなく、巨大な問題になるまで設計の進化を拒否することです。

例として、Netflixにはプロファイル機能があり、異なる家族が同じプランに請求することができますが、別々のキューがあります。数年前、彼らはユーザーの約10%しか使用していないため、その機能をキャンセルする必要があると発表しましたが、実装がハッキングされたために、膨大な量のメンテナンス作業を消費していました。大騒ぎの後、彼らは弾丸を噛み、それらの顧客を維持するために高価な再設計を行いました。

最初にその機能を追加したときに、次善の設計を認識したエンジニアがいたはずです。当時、彼らがそれを変えていたなら、それは大したことではなかったでしょう。


1

「最初のものを捨てる計画」のようなことを言ったのはフレッド・ブルックスではなかったでしょうか?行き詰まりを感じないでください。行き止まりのデザインも、すべてのデザインを前もってやろうとするプロジェクトに現れます。再設計は、最初から実行不可能な設計(最後の20%が「悪魔は細部に潜んでいる」)であったか、顧客が焦点を変更したために、あらゆる種類の開発で発生します。警報ベルの本当の必要性はありません、あまり心配しないでください。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.