保守可能なコードを書く

何百ものソフトウェアサポートプロジェクトがあり、そのうちのいくつかはほぼ10年間サポートされています。 保守可能なコードの概念(保守しやすいコードとしてこの概念を翻訳します)が主要なものの1つであると推測するのは簡単です。 幸いなことに、保守が容易なコードは(ユニット)テストでも簡単で、新しいチームメンバーが簡単に学習できるなどです。 ほとんどの場合、これは、メンテナンス可能なコードを作成するために、プロジェクトの優れたアーキテクチャを管理し、適切な習慣を作成する必要があるという事実によるものです。

この記事では、そのような習慣についてお話します。そのおかげで、しばしば優れたアーキテクチャがそれ自体で判明します。 良い例ですべてを説明しようとします。









しかし、文字Mの省略形であるMVC、MVP、MVVMなどが好きではないことを説明することから始めます。 アプリケーションを設計する方法に関する彼の最初の本と記事を読んでいる初心者にとって、これらの略語は最初のものの中に現れます。 彼は、プログラムは、たとえばモデル、コントローラー、ビューから構成される一種のトライアドであり、最も危険なのは、このトライアドのメンバーの重要性が等しいという誤った印象を与えます! これらの記事とビデオチュートリアルの多くは、シリーズの例でこの危険な嘘を補強しています。「プレゼンテーション用のテンプレートエンジンを用意しましょう。コントローラーはフレームワークのコントローラーであり、モデルはActiveRecord ORMの一種です。」 この後、彼が何か悪いことをしていることを初心者に気付かせるには、何年もの間Thick Dumb Ugly Controllersが必要になるかもしれません。 モデルがこれらのトライアドの主要な位置を占めており、アプリケーションが複雑になるほど顕著になります。



プログラムを上位レベルの部分に分割する主な原則は、 データアクセスレイヤー、ビジネス(ロジック)レイヤー、プレゼンテーションレイヤーのように 、数十年間変わっていません。 さらに、アプリケーションの本質と価値を反映するレイヤーがビジネスレイヤーであり、 DALPLが何らかのサービスレイヤーであることは明らかです。 そして、文字Mのこれらの略語はすべて、プログラムでプレゼンテーション層を編成する方法を説明するアーキテクチャパターンであり、それ以上のものではありません。



さて、私は習慣について話すことを約束したので、 最初のものを選びます:データを保存する、またはユーザーに提示するファッショナブルな技術の競争では、アプリケーションがビジネス層であることを忘れないでください、残りは時間とともに容易に変化する殻です。



そしてすぐに、前文なしで、 2番目の良い習慣 :固体。 私は残りがどのようにSOLIDにあるのかわかりませんが、 Sイングレス責任の原則の重要性を過大評価することはほとんどできません。 私はそれを良いコードのための必要十分条件と呼びます。 悪いコードでは、常に複数のことを行うクラスが存在します(Form1.csまたはindex.php、サイズが数千行、おそらく誰もが見た、あるいは見たことがあります)。 SOLIDの残りの原則は私にとってそれほど重要ではありません。ところで、最近、ハブについてこのテーマに関する良い記事がありました。 多くの点で、そこに書かれたものに同意し、この記事の著者に感謝します。自分で説明する必要はありません。

単一責任の原則(以下、単にS原則)を使用すると、文字通り高品質のコードを記述できます。多くの非常に多くの手法は、この原則を満たすコードを記述するための単なるツールです。

また、 3番目の良い習慣で強調している例は、依存性注入です。 多かれ少なかれ、DIなしでSの原則を公言する大規模なプロジェクトをかすかに想像します。 私は例をあげることを約束しました、そして、ここはこれを始める良い場所です。 通常のクラス。オンラインストアの注文を処理するロジックです。



public class OrderService
{
    public void Create(...)
    {
        //  
        
        //   email    
        var smtp = new SMTP();
        //  smtp.Host, UserName, Password   
        smtp.Send();
    }
}

      
      





, , , , — OrderController . , , . OrderService SMTP! . :



public class OrderService
{
    private SmtpMailer mailer;
    public OrderService()
    {
        this.mailer = new SmtpMailer();
    }

    //  -      ,       
}

public class SmtpMailer
{
    public void Send(string to, string subject, string body)
    {
        //      SMTP
    }
}

      
      





, S, , OrderService , «» . : , OrderService , , , , SmtpMailer. . IMailer



public interface IMailer
{
    void Send(string to, string subject, string body);
}

      
      





SmtpMailer . - IoC-, , IMailer SmtpMailer. OrderService :



public class OrderService
{
    private IMailer mailer;
    public OrderService(IMailer mailer)
    {
        this.mailer = mailer;
    }

    //  -      ,       
}

      
      





? OrderService SmtpMailer . IMailer OrderService mailer, , , , . , , OrderService .

— , . , -. : ( -!), — IoC- SmtpMailer NewTechnologyMailer — ( !). . . , , - , . , — . , . , — , OrderService !



: (, ).

OrderService. , IOrderRepository, . , 1999 , OrderService . - . , OrderService IOrderService ( Create ) , .



public sealed class OrderService: IOrderService
{
    private IOrderRepository repository;
    private IMailer mailer;
    public OrderService(IOrderRepository repository, IMailer mailer)
    {
        this.repository = repository;
        this.mailer = mailer;
    }

    public void Create(...)
    {
        var order = new Order();
        //   ,     -. ,   ..
        this.repository.Save(order);

        this.mailer.Send(<orders user email>, <subject>, <body with order details>);
    }
}

      
      





, mailer Create . -: workflow - . , , , , - . maintenance. -: — . , , , IUserParametersService. , , ITranslator ( ). , . . Injection happy. IoC- , . , - . , S. , OrderService . Event Driven . :



namespace <base namespace>.Events
{
[Serializable]
public class OrderCreated
{
    private readonly Order order;

    public OrderCreated(Order order)
    {
        this.order = order;
    }

    //  C#     {get; private set},        
    public Order GetOrder()
    {
        return this.order;
    }
}
}

      
      





« ». , OrderService . .



namespace <base namespace>.EventHandlers
{
public class OrderCreatedEmailSender : IEventHandler<OrderCreated>
{
    public OrderCreatedEmailSender(IMailer, IUserParametersService, ITranslator)
    {
        //        
    }

    public void Handle(OrderCreated event)
    {
        this.mailer.Send(...);
    }
}
}

      
      





Serializable . , , , (Redis, ActiveMQ ). -, , -. , ().



, OrderService, ( -, , ), , DI. - , . . Find usages IDE OrderCreated .



, . DI Events, , IOrderRepository. - — , . OrderCreated. , : .



, . , . , . , , , , , . , - -. . , . , , S ;-)



P.S. , . , . , , IoC, Event-Driven — . , . « », . , , . , , .



All Articles