安いコードを書いてはいけません


このポストの例はJavaにあります、しかし、示されるパターンは非常に基本的です、そして、基本的なオブジェクト指向で機能的支持を持っている大部分の言語の向こう側に使われることができます.
良いコードをゼロから書くことは、最も経験豊かな開発者にとってさえ難しい仕事です.それはまだ理解しやすい、簡単に変更するには、既存のコードベースを進化させる、テストしやすい、観察可能なプロジェクトの間で過剰なコード重複を持っていない複数の開発者やチームが処理する必要がありますし、いくつかの成功したタスクです.
モノリスは生まれないBig Ball of Mud . 彼らは通常、安定していて、それらに取り組んでいるいくつかの開発者に進化し、ビジネスのニーズを解決するために効果的に非常に簡単であるまともな階層構造を持つ.
私は、すでにこのポストにタイトルである文について、何度か尋ねられました.どのように、あなたは時間の向こうで安いコードを作りますか?変更するのが簡単な良いコードを書く方法に関するハンドブックがありません、しかし、私は共有したい安いコードの若干の特徴を見つけました.
最初にコードをハードに変更する方法を分析し、例と理由.

共有インフラコードは変更するのが難しい


共有コードはコミットメントです.あなたは異なる機能を漏らすと、実際のロジックを行う単一のホットスポットに必要があります.これらのパターンの良い例は基本クラスとユーティリティ関数です:

これは抽象的に抽象化され、3つの可能性のないドメインに影響を及ぼします.
この問題を回避するには、次の3つのオプションがあります.
  • 共有コードを使用するフレームワークに委任します.
  • インフラストラクチャコードをコードベースから分離し、カスタムフレームワークを構築します.
  • コードを複製します.
  • 最も安いオプションはフレームワークに委任した最初のものです.フレームワークは、すでに最も一般的な問題の解決策を提供しています:あなたがユニークな問題に直面している可能性は本当に低いです.可能であればフレームワークにデリゲートインフラストラクチャ.
    次の最も安いオプションはコード複製です.重複したコードが比較的うるさくても、複数の場所で正確に同じコードを持つ可能性は低いです.早熟なコード再利用は解決の早めの一般化の確率を増やします.そして、ビジネスに集中しないコードに至ります.後にビジネス言語を話していないコードは、ビジネスについて学ぶために使用するのは難しいです、そしてそれは変更するのは難しいです.
    また、コードの重複は、サービスの可用性に役立ちます.ホットスポットを避けることは、ホットスポット(メモリリーク、接続プールのリークと関連)に依存するすべてのクラスに影響を与える失敗の連鎖の可能性を減少させる.

    共有ドメインコードを変更するのは難しいです


    最初のポイントに関連して、ドメインコードも変更するのは難しいです.
    あなたのプロジェクトの冒頭では、すべてがcrudのように見えます.いくつかのテキストボックス、ドロップダウン、および送信ボタンを必要とするだけで、挿入操作があります.後で、あなたは、提出されたアイテムのリストを見たいと思います.
    注意しなさい.ビジネスルールは時間と複雑になります.今日何が数ヶ月で、それは完全に異なる何かのように見える.多分それは単なるボタンであり、それはすべて自動化する、Oは複雑なユーザーの旅は別のサードパーティのサービスから別の情報を充填になります.
    ドメインコードを共有しないでください.抽象オブジェクトを回避し、値オブジェクトの依存組成を回避します.たとえば、Javaクラスを見てみましょう.
    public abstract class BaseBook {
        private long bookId;
        private String bookTitle;
        private String authorName;
        private BigDecimal price;
        private BigDecimal salesPrice;
    
        ...constructor
    }
    
    public class Book extends BaseBook {
        private long stock;
        private long warehouse;
    }
    
    ベースクラスが成長するとき、ベースブックが成長するとき、ベースブックが成長するとき、ベースブックが成長するとき、ベースブックが成長するとき、ベースブックが成長するとき、ベースブックを拡張するのが安全に見えます.また、プロパティの境界とそれらの関係をぼかします.代わりに、値を明示的に設定します.
    public final class Cover { 
        private final String bookTitle;
        private final String bookName;
    
        ...constructor
    }
    
    public final class Author {
        private final String authorName;
    
        ...constructor
    }
    
    public final class Price {
        private final BigDecimal original;
        private final BigDecimal sales;
    
        ...constructor
    }
    
    public final class Stock {
        private final long quantity;
        private final long warehouse;
    
        ...constructor
    }
    
    public class Book {
        private final long bookId;
        private Cover cover;
        private Author author;
        private Price price;
        private Stock stock;
    
        ...constructor
    }
    
    値オブジェクトの周りの知識を分割すると、コードが長期的に理解しやすくなり、値オブジェクトが変更されます.

    関係のファンを避ける


    クラス間のファンインの関係は、クラスが別のより大きい数のクラスから直接的または間接的に依存している場合です.たとえば、同じドメインオブジェクトを使用するいくつかの機能があります.例のダイアグラムは次のとおりです.

    これが起こるとき、あなたはあなた自身に以下のウォームアップ質問をするべきです:
  • からデータが必要ですかBook または彼らの行動?
    これに対する答えがちょうどデータであるなら、値オブジェクト(実体全体の代わりに)を使用することを検討するか、新しい読取りモデルを定義してください.SQLデータベースがある場合は、ビューの結果を共有できます.単一のビューの移行は、コード内の10ポイント以上で使用されるクラスを変更するよりもはるかに簡単です.
  • 私は、同じデータまたは行動を必要としますかBook すべての場所で?
    答えがNOの場合、新しい読み取りモデルを定義する必要があります.データとふるまいが異なるならば、多分、我々は異なる有権文脈/製品について話しています.
  • 私は読書だけですか?または書き込みも?
    あなたが書いている、そして、行動が異なるならば、おそらく、あなたは異なる境界文脈/製品です.コードを別々に保つ.あなたが読んでいるだけであるならば、読まれたモデルは十分です.
  • しかし、実際に我々のコード境界がはっきりして、異なる方法で抽出して、取り替えるのが簡単であることを確認するのに我々が使うことができる若干のツールがあります.

    製品に基づく有利な線形階層


    並列階層の変更XController, XService, X, XRepository ) は、通常、データに基づいて定義されているためです.これらの関係を定義しないでください.OneClickPurchase , StandardPurchase , SearchPage , Newsletter より多くのビジネスレベルで表現され、より良い境界を定義します.

    値オブジェクト合成に基づいて平らな階層を支持する


    継承は間違っていません、しかし、私たちが正しい推論なしでそれを使うならば、結合のホットスポットは価値オブジェクトの構成を支持することができます.

    境界を定義する機能を使用してトグル


    コードを無効にすることができます.いつでも無効にすることができます機能のトグルを使用して境界を定義します.また、これはあなたのコードをより信頼できるようにするので、事件があるならば、製品または特徴はいつでも無効にされることができます.機能のトグルの用例は次のようになります.
    public final class StandardPurchase {
        private final StandardPurchaseContext context;
        private final DeliveryInformation delivery;
        private final FeatureToggle toggle;
    
        ...constructor
    
        public PurchaseSummary summary(User forUser) {
            PurchaseSummary summary = context.summary(forUser);
    
            if (toggle.enabled(ONE_DAY_DELIVERY)) {
                OneDayDeliveryForecast forecast = delivery.oneDayDelivery(forUser);
                return summary.oneDayDelivery(forecast);
            }
    
            return summary;
        }
    }
    

    テスト中に可能であればモッキングを再考する


    デフォルトでmock依存関係ならば、テスト時間を高速化します.しかし、これはまた、あなたのコードのぼやけた境界につながることができます.なぜなら、外部依存関係をモックアップすることは比較的安価です.
    あなたの統合テストが高価であるならば、あなたはクラスの大きいチャンクに応じているかもしれません.