良いコードか悪いか? 個人的には、良いコードには次のような性質があります。
- コードは、さまざまなスキルの開発者にとって理解しやすく、よく構成されています
- コードは簡単に変更および保守できます。
- アプリケーションはその機能を実行し、現在のタスク範囲に対して十分な耐障害性を備えています
これらの3つの条件をどのように達成するかについての短い説明にもかかわらず、多くの厚い本が書かれています。
なぜこれらの基準がぴったりなのでしょうか? すぐに予約を入れて、ビジネス用ソフトウェア(エンタープライズアプリケーション)の開発について話し合っています 。 リアルタイムシステム、航空機、生命維持システム、およびISSのコード評価基準は異なります。
確かに誰でも、ほとんど誰でもこの三角形を知っています。
同時に、3つの条件のうち、迅速、効率的、安価に満たすことができるのは2つだけです。
ビジネスアプリケーションを開発するとき、私たちの目標は、予算内で、許容できる期間に十分なソフトウェアを開発することです。 実際には、これはアプリケーションにエラーがあるかもしれないが、システムにとって重要ではない場所にエラーがある可能性があることを意味します。 これが何を意味するのかをよりよく理解するために、いくつかの例を見てみましょう。
事例番号1
フォームにはテキスト入力フィールド(textarea)があります。 そこに100500文字を入力できますが、アプリケーションは「最大リクエスト長を超えました」という例外を伴って失敗します。
これは私たちのケースですか? ほとんどない。 これが公開部分である場合、Javaスクリプトバリデータを配置し、そのようなフォームの投稿を許可しないことは価値があります。 java-scriptを無効にしているユーザー向けに追加のサーバーをセットアップするのは時間の無駄であり、予算を意味します。 これは行いません。 はい、アプリケーションに潜在的なエラーがあります。 誰でも修正する必要がありますか? いや
事例番号2
クライアントからリクエストがあります。パートナーページが必要です。 このページには、それぞれについての簡単な情報と、iframeにパートナーのサイトからページを埋め込む必要があるページへのリンクが含まれます。
興味深いケース。 おそらくデータベースに変更を加え、パートナーエンティティを追加する必要があります。ビューにdb-entityを渡さないので、DTO、db-entityからdtoへのマッピング関数、および自動デプロイのデータベース移行が必要です。 うーん、まだパートナーを追加するには管理パネルにページが必要です。 / Partner / <PARTNER_NAME>かなり多くの作業があるように、コントローラーのルーティングを忘れないでください...
10,000のパートナーに当てはまります。 興味を持ってみましょう: 「パートナーは何人になるでしょうか? 」 答えが「今年は3年」の場合。 私たちの見解を再考する必要があります。 これも時間と予算の無駄です。 パートナーは3つだけですか?
namespace Habrahabr.Models.Partner { public class PartnerViewModel { public string Name { get; set; } public string WebSiteUrl { get; set; } public string ShortDescription { get; set; } public string FullDescription { get; set; } } } using System.Web.Mvc; using Habrahabr.Models.Partner; namespace Habrahabr.Controllers { public class PartnerController : Controller { private static PartnerViewModel[] partners = new[] { new PartnerViewModel() { Name = "Coca-Cola", WebSiteUrl = "http://coca-cola.com/partner", ShortDescription = "Coca-cola short description", FullDescription = "Coca-cola full description" }, new PartnerViewModel() { Name = "Ikea", WebSiteUrl = "http://ikea.com/partner", ShortDescription = "Ikea short description", FullDescription = "Ikea full description" }, new PartnerViewModel() { Name = "Yandex", WebSiteUrl = "http://yandex.ru/partner", ShortDescription = "Yandex short description", FullDescription = "Yandex full description" } }; public ActionResult Index() { // TODO: populate partners from database if a lot of partner required return View(partners); } // TODO: refactor this if a lot of partner required [ActionName("Coca-Cola")] public ActionResult CocaCola() { return View("_PartnerDetail", partners[0]); } public ActionResult Ikea() { return View("_PartnerDetail", partners[1]); } public ActionResult Yandex() { return View("_PartnerDetail", partners[2]); } } } @model IEnumerable<Habrahabr.Models.Partner.PartnerViewModel> <ul> @foreach (var p in @Model) { <li> <h3>@Html.ActionLink(p.Name, p.Name, "Partner")</h3> <div>@p.ShortDescription</div> <p class="info">@Html.ActionLink("Partner page", p.Name, "Partner")</p> </li> } </ul> @model Habrahabr.Models.Partner.PartnerViewModel <h2>@Model.Name</h2> <div>@Model.FullDescription</div> @if (!string.IsNullOrEmpty(Model.WebSiteUrl)) { <iframe width="100%" height="500" src="@Model.WebSiteUrl"></iframe> }
すべてについてのすべてのために-テキストの入力を考慮に入れて最大1時間。 かなり良いパートナーページを開発しました。 基準を満たしていますか?
- 明確で構造化-はい
- 変更が簡単-はい
- 十分な信頼性-はい
ドメイン、データアクセス、およびアプリケーションアーキテクチャ
ファウラーは、彼の著書「 Enterprise Patterns of Enterprise Application Architecture 」で、「アーキテクチャ」という用語が非常にぼやけていることを正しく指摘しています。
「アーキテクチャ」という用語は、怠け者ではないすべての人、およびすべての人が独自の方法で解釈しようとしています。 ただし、2つの一般的なオプションがあります。 1つは、システムを最大のコンポーネントに分割することに関連しています。 2番目のケースでは、いくつかの建設的な決定が意図されており、それらの採用後に変更することは困難です。 また、アーキテクチャを説明する方法は複数あり、それぞれの重要度はシステムのライフサイクルを通じて変化するという理解が深まりつつあります。
上記のパートナーとのアプローチには、1つの重要な制限があります。 このスタイルでアプリケーションコードを常に記述することはできません。 遅かれ早かれ、システムは成長します。 この場合、アプリケーションロジックを「縫い合わせ」ました。 特に新しい開発者にとっては、これらのコントローラーをいくつか追加してシステムを理解することは非常に困難です。
パートナーが3人ではなく、100,500人ですべてが表示されるわけではないことが判明した時点で、金曜日から土曜日の夜(13から14)に支払い、6人の処女を犠牲にした人だけを表示し、ページをローテーションする必要があります木星に関する金星の位置との対応(実際には、ケースはもちろん異なりますが、開発者にとっては、例外と特別なケースだけで構成される「ビジネスロジック」ほど非論理的ではないと言うことはありません。) 両方の意味で建築について考える必要があります。
事前にアプリケーションに「縫い目」を残しておき、それらを引き裂き、必要な部分を縫い始めます。 ORMを使用して、 PartnerViewModelの名前をPartnerに変更し、パートナークラスをデータベースにマップします。 Database-Firstを使用したことはなく、 Entity FrameworkをCode-Firstアプローチのバージョンがリリースされるまで真剣に受け止めませんでした。 この場合、 PartnerViewModelで Partnerをマップする必要はありません。 はい、これらのエンティティは意味的に異なるタスクを実行し、一般にPartnerViewModelは異なる場合がありますが、まったく同じクラスを記述する単一の理由はありません。 Mapit ViewModelは、ロジックをビューにドラッグせずにそれなしでは実行できない場合に意味があります。 通常、ドメインの複数のエンティティで同時に動作する複雑なフォームをインターフェイスで表示する必要がある場合、またはモデルプロパティにSystem.Webアセンブリの属性を使用する必要がある場合、 ViewModelの必要性が生じます。 後者の場合、今後6か月以内にメインのWebアプリケーションを除き、アプリケーションに新しいエントリポイントがなくなると確信している場合、この依存関係をサブジェクトエリアを含むアセンブリにドラッグする傾向があります。
私が参加したあるプロジェクトでは、データにアクセスするために、ファサードにアクセスするサービスを呼び出す必要がありました。そのサービスは、 Entity Frameworkが呼び出したDALレイヤーにアクセスしました。 ファサードとDALは異なるアセンブリにあり、 EFはDatabase-Firstアプローチを使用しました。 通常、 DALはすべてのロジックを実行し、残りのレイヤーは、90%のケースの結果をまったく同じDTOに再マッピングします。 同時に、システムには他のクライアントがなく、サービスは客観的に不要でした。 「なぜそんなにオーバーヘッドがかかるのか」と尋ねると、プロジェクトに携わった開発者は、「わかりません。他のプロジェクトはこのように書かれているので、アナロジーでやろうと決めました。」 はい、この「他のプロジェクト」は20個のアプリケーションで構成されており、デプロイに2日しかかかりませんでした。 このアプリケーションのAPIには多くのクライアントがあります。 このような複雑な構造が必要でした。 私たちの場合、それはスズメの大砲からの射撃でした。
しかし、
適切なオプションは
IOC / DI
アプリケーションの成長に伴い、アプリケーションが緊密に接続される危険があり、これによりシステムが遅くなり、コードの変更が妨げられます。
IOC / DIが何であり、何と一緒に食べられるかをもう一度説明することはしません。原則としてそれを理解する必要があります。
- 依存関係を明示的に作成しないでください
- IOCコンテナーを使用する
プロジェクト内のクラスごとにインターフェースを作成する必要はありません。 多くの場合、インターフェースは後で簡単に強調表示できます。 R#はこれをうまく処理します。 ただし、クラスを作成するときはこのことに留意してください。 特定の実装ではなく、インターフェイスと考えてください。 DIを使用すると、実装を柔軟に管理できます。 必要に応じて、ある実装を破棄して別の実装に置き換えることができます。たとえば、何らかの理由でデータベースが機能しなくなった場合、リポジトリ実装を置き換えることで透過的に置き換えることができます。 さらに、 IOC / DIを使用すると、テストコードを書くのがはるかに簡単になります。
テスト
プロジェクトカバレッジの90〜100%は好きではありません。 たいていの場合、これにより開発が遅くなり、コードサポートが面倒になります。 私はシステムの動作をテストすることを好みます、すなわち アプリケーションの基本的なビジネスルール。 したがって、テストはエラーを保証するだけでなく、新しい開発者がシステムのロジックをすばやく理解するのにも役立ちます。 このようなテストは、どのドキュメントよりもうまく機能します。 BDD表記を使用したテストは特に効果的です。
システムのさらなる開発
アプリケーションが成長し続ける場合、具体的なアドバイスを与えることは困難です。考慮すべき要素が多すぎます。 プロジェクトの詳細に依存しすぎます。 良い解決策はSOAです。 一般に、大規模システムの分解は素晴らしいアイデアです。 IDEに10個のプロジェクトまたは100個のプロジェクトがアップロードされます-違いは非常に大きいです。 この規模のソフトウェアを開発する場合、展開スクリプト、インストーラー、およびリリース管理は不可欠ですが、これはまったく別の話です...
ラムダ、アスペクト、機能、その他のホリバー
最後に、私は意図的に物議を醸す瞬間を残すことにしました。 多くの開発者は、彼らが作業するスタックに慣れる傾向があることに気付きました。 プログラマーが自分のスタックに「使用」されると、その有用性に関係なく、新しいプロジェクトにドラッグする傾向があります。 だから、機能的なスタイルで「いちゃつく」、「何を知っている」、「デバッグしない」ようにコンパイルされたラムダ、および他の拡張メソッドに対するC#の批判を繰り返し聞いてきました。 客観的には、クロージャーがphpに追加され、 Streamがコレクションを処理するためにjava8に表示されることがわかります。
価値があるのであれば、パラダイムを組み合わせることを恐れないでください。 「どのくらいのプラットフォーム/言語/ OSがタスクに適していますか?」および「タスクを可能な限り効率的に完了するのに役立つテクノロジーはどれですか?」という質問を自問してください。 私のポイントは、 イリアカンの引用で最もよく説明されています。
Erlangを習得するか、Javaを十分に高速に動作させる方が速いと思い、Erlangを習得することにしました