カバを切る。 Sandy Metzによる設計とリファクタリングについてもう一度

こんにちは、Habr!



Sandy Metzの整然とした本「 Ruby。Object-Oriented Design 」ですでに終わりを迎えています。これは来年更新される予定です。 それまでの間、メッツさんの読者がRubyのOOPだけでなくOOPについての彼女の見解に興味があることを確認したので、多数の写真とトピックに関するかなりの結論を含む9月の記事の翻訳を提供します。 素敵な読書を!



こんにちは



時々、私はアプリケーションがどのように開発されているか、そして結果が私たちに合わない場合はどうするかを考えます。 そうすることで、3つのまったく異なるアイデアを考えます。 この投稿では、3つすべての概要を説明し、それらを組み合わせます。 これらの相互接続を理解したことで、アプリケーションをよりよく理解できることを願っています。



これらの考えは私の個人的な意見であり、私自身の経験にのみ基づいています。 あなたの意見は異なるかもしれませんが、私はあなたに思考の糧を与えることを望みます。 以下はたくさんの写真です。 私があなたの前でホワイトボードに描いていると想像してください。

最初のアイデアはMartin Fowlerに属し、「 デザインスタミナ仮説 」(建築の持続可能性に関する仮説)と呼ばれます。



#1:アーキテクチャの持続可能性の仮説



ファウラーは、このアイデアを次の擬似スキームで示しています。







図 1



縦軸は累積された機能を表します。 チャートの線が高いほど、より多くのことができました。 横軸は費やされた時間を表します。 右に行くほど-遅くなります。



2つの異なるグラフがグリッドに描画されます。 オレンジ色の線は、仕事の初日からデザインを開始した場合に、どの時点でどれだけの機能を生成するかを示しています。 青い線は、真剣な設計を怠った場合の結果を示しています。 注:最初の段階では、青い線は十分に速く成長しますが、最終的にはオレンジ色の線が追いつきます。



建築の持続可能性の仮説によると、プロジェクトの初期段階では、建築についてあまり気にしないのであれば、より多くのことを行うことができます。 ただし、アーキテクチャをまったく行わない場合、プロジェクトの遅かれ早かれ、さらなる開発のためにアーキテクチャを行う必要がある瞬間が来るでしょう。



次のアイデアは、手続き型コードとオブジェクト指向コードの違いに関連しています。



#2:手続き型コードとオブジェクト指向コードの比較



ここでは、1番目と2番目のパラダイムのコードを変更して理解するのがいかに便利かという文脈で、手続き型コードとオブジェクト指向コードを比較します。 次の図は、最初と2番目のオプションが必要とする妥協点を示しています。







図 2



コードを変更する便利さは、垂直軸に沿って遅れています。 変更が最も簡単なコードは次のとおりです。 変更するのが難しいほど、高くなります。



横軸は、コードのわかりやすさを示しています。 最も明らかなコードは左側にあり、最も理解しにくいコードは右側にあります。



簡単な手順は、単なるステップのリストです。 簡単な手順は簡単に理解され、簡単に変更できます。これらはこのスキームの左下4分の1にあります。 このセクターは最も安価で効率的です。



いくつかの問題を解決するには、不要な条件や重複のない単純な手続き型コードが最適です。 もっと手頃な価格のものは何ですか? コードを作成してすぐに開始します。

ただし、状況は時間とともに変化する可能性があります。 新しい機能の要求(機能要求)があります。そのためには、条件付きロジックを追加するか、複数の場所でソリューション要素を複製する必要があります。 3。







図 3



上記のように、安価で効果的な手順が、条件とテイクで大きくなりすぎた複雑な「泥沼」に変わったことが示されています。 そのようなコードを理解して変更することは困難です。



単純な手順は面倒ではなく、複雑な手順は高価です。 複雑な手順で圧倒できる唯一の賛辞(そして実際に唯一の賛辞)は、この全体が$ $%@!であることに注意することです! コードは同じ場所にあります。 ただし、そのようなコンパクトさは複雑さを正当化するものではありません。 コードはより合理的な方法で合理化できます。



次の図では、オブジェクト指向のコードも考慮しています。 注意:オブジェクト指向ソリューションは、通常の手順よりも少し高価ですが、複雑なものとコストが比較されません。







図 4



オブジェクト指向ソリューションでは、小さな交換可能なオブジェクトはメッセージを使用して通信します。 メッセージを使用すると、既存のオブジェクトを同じ役割を実行する類似のオブジェクトに置き換えることができる一種の「継ぎ目」を作成できます。 メッセージングを使用すると、動作を簡単に変更できます。変更すると、新しい要素を置き換えるだけで済みます。



また、メッセージングでは結果を取得する詳細が隠されることに注意することも重要です。 送信者の観点からは、メッセージは単に意図を説明するだけです。 メッセージの受信者は、送信者が知らない実装を提供します。 したがって、メッセージの助けを借りて、送信者からリモート実装を隠すことにより、 ローカルな代替性が簡単に提供されます。



複雑な手順に関しては、オブジェクト指向のアプローチは、変更する際により明確で便利です。 簡単な手順の場合、OOコードは変更するのと同じくらい便利ですが、一般に、それを理解することは非常に難しいでしょう。



したがって、オブジェクト指向は否定できず、Win-Winのオプションでもありません。 それはすべて、前のタスクの複雑さと、アプリケーションの耐久性に依存します。

さて、長寿に目を向けて、コードの書き換え(解約)という最新のアイデアを見てみましょう。



#3:コードのフラッピングと複雑さ



「耕す」という考え方の概要は、Michael Physersによる「リファクタリングに関する経験的経験 」の記事に記載されています。 プラウは、ファイルが変更される頻度を評価できる特性です。



「耕す」という現象はそれ自体興味深いものですが、「複雑さ」の文脈で考えることはさらに便利です。 Fisersの記事には次の図があり、緑の曲線を追加しました。







図 5



この図では、耕作のインデックスは水平に配置され、コードの複雑さは垂直になっています。



めったに変更されない複雑なコードは、このスキームの左上4分の1にあります。 はい、複雑さを好む人はいませんが、コードが変更されなければ、複雑さを維持するための費用はかかりません。 コードがプラスチック製の調理器具の山でいっぱいのキャビネットであると想像してください。 ドアを開けるだけで十分です。 リビジョンが点灯するまで、このセグメントのコードを忘れることができます。



非常に頻繁に変更される単純なコードは、右下の四半期を指します。 コードが単純な場合(構成ファイル内のコードなど)、変更は難しくありません。 コードがシンプルである限り、必要に応じて何度でも変更できます。



左下の四分の一は、それほど複雑ではなく、それほど頻繁に変更されないコードです。つまり、すでに効率的に編成されており、無視することもできます。

緑の曲線は、左上4分の1から始まり、左下を通り、さらに右下に進みます。 アプリケーションのコードはこの曲線に沿って集中することが望ましいです。 注:曲線は右上の四分の一には入りません。

右上の四半期は、頻繁に変更される複雑なコードです。 定義上、このようなコードは理解するのが難しく、変更するには不便です。 この四半期は空である方が良いです、そして、何らかのコードがそこに着くならば、それは緊急にリファクタリングを必要とします。



これらのアイデアを一般的なコンテキストで検討したので、それらに基づいて、アプリケーションが悪質な方向にどのように進化するかを説明します。



コードは予想通りに開発され、ハッシュに変わります



私には何度も何度も出くわす特徴的な「ハッシュコード」があります。 Code Climate Webサイトから、いくつかのプロジェクトの例とともに、コードをまさにそのようなミッシュマッシュに変える特徴的な症状を示すいくつかのスキームを提案します(2017年9月7日現在)。







図 6







図 7







図 8



上記の耕作対 品質 "Fieserのアイデアに基づいてCode Climate Webサイトで編集" File Revision vs. 複雑さ。」 注:すべてのダイアグラムで、図の緑の曲線に似た曲線に沿って点が集中しています。 6.これは良いことです。 開発者を称賛します-これらのアプリケーションのほとんどでは、複雑なコードはほとんど変更されておらず、ほとんどの変更は単純なコードで行われています。



ただし、これらすべてのスキームには、望ましくない「周辺」もあります-右上の四分の一にコードがあります。 これらのアプリケーションのソースコードは表示されませんでしたが、これらのスキームだけに基づいて、この周辺にあるクラスについて何かを推測できます。 私は彼らがいると思う:



  1. 他のほとんどのクラスよりも大きい
  2. 条件付き設計と
  3. サブジェクトエリアの基本概念を説明する




必要に応じて、自分で確認できます。 上記の各図をクリックすると、アプリケーションに対応するページがCode Climateで開きます。 そこに到達したら、周辺ポイントをクリックします-対応するコードへのリンクが開きます。 私が言ったように、本質的に、これらのアプリケーションは知りませんが、...そのサイズ、複雑さ、耕作の速度に基づいて、私はこの場合に間違えられないと確信しています。 この記事を読むまでにスキームが変更された場合は、この例をスキップしてください;)原則が機能すると信じてください。



この構造は、多くのアプリケーションで追跡できます。 アプリケーションのほとんどのコードは理解可能であり、そのようなコードの変更は簡単です。 しかし、アプリケーションには、いくつかの大きく複雑で常に耕作可能なクラスが必ずあります。これらのクラスでは、主題分野の非常に重要なアイデアが表現されます。



これらの周辺クラスでの作業は誰にとっても嫌いです。 それに触れると、すぐに壊れます。 テストはセキュリティを保証しません。 対策はありません。 あらゆる努力にもかかわらず、クラスは目の前で激しくなり、より複雑になっています。 それは悪かった-悪化する。



これはどのように起こりますか?



上記の3つのアイデアを使用して、問題を説明できます。 そして問題が明確であれば、それを防ぐ希望があります。



私は断言します:



  1. 時期尚早の設計作業は作業の無駄です。

    (図1-初期段階のオレンジ色の線)
  2. デザインをまったく行わないと、コードはひどい混乱に変わります。

    (図1-後期の青い線)
  3. 特定の段階で、デザインに投資する必要があります。これにより、お金を節約できます

    (図1-2本の線の交点)
  4. 単純な手順はほとんど設計を必要とせず、保守が容易です。

    (図2、図1:青い線の始まり)
  5. 時間の経過とともに手順はより複雑になり、手順の維持はますます費用がかかります。

    (図3、図1:後期の青い線)
  6. 経済的な観点から見ると、オブジェクト指向コードは複雑な手続き型コードよりも利益があります。

    (図4)
  7. サブジェクトエリアにとって最も重要な手順は、非特定の手順よりも頻繁に変更されます。
  8. サブジェクト領域にとって最も重要な手順は、他のコードよりも複雑です。
  9. アプリケーションが「設計の適切性」の境界を越えるポイントを把握することは困難です

    (図1)
  10. 10.開発のペースが遅くなり、問題が増え始めると、このラインが遅れていることを理解できます。

    (図1-設計の適切性の線の下にある青い線の一部)
  11. これを理解するまでに、最も重要なコードはすでに最も無視された形になっています。
  12. 中程度に複雑な手順は、オブジェクト指向に簡単に変換できます。
  13. 非常に複雑な手順は、オブジェクト指向に変換するのが最も困難です。
  14. 中程度に複雑な手順をオブジェクト指向に変換する試みは、通常成功します。
  15. 非常に複雑な手順をオブジェクト指向に変換しようとすると失敗することがよくあります。


そして、これは、多くの小さな効果的なクラスが、条件付き構造が詰め込まれた高価でかさばるカバと共存するアプリケーションの結果です。 アプリケーションの最も重要なコードの無害な小さな修正の数は、このコードを、誰もこの問題を修正できないような複雑なクラスに変えます。 この問題は、上記のリストの段落15に明確に示されていますが、すべてのロジックがリターンのないポイントを通過するまで、複雑さが少しずつ大きくなる段落8に根ざしています。



手続き型コードにしがみつくことは、設計を早めに開始することと同じくらい有害です。 サブジェクト領域の重要なクラスが頻繁に変更され、条件付き構文で絶えず増加し、成長している場合、そのような開発をすぐに停止します。 既存のオブジェクトとやり取りする、小さく、適切に設計されたクラスの形式で変更を実装します。



5,000行のクラスは非常に引き付けられるため、新しい要件を満たす10行の補助クラスのセットをどのように記述するか想像するのが難しくなります。 いずれにしても、新しいクラスを作成します。 周辺クラスを再び緑色の線に引き付けるために、すでに巨大なオブジェクトにさらに多くのコードを詰め込まないように誘惑しないでください。 小さなオブジェクトを作成すると、時間の経過とともに大きなオブジェクトが消えます。



All Articles