私はコンサルティング会社でしばらくの間、さまざまな規模のクライアントで働いており、非常に単純なものから複雑なものまで、さまざまなWebアプリケーションを見てきました。
本当に複雑に:
しかし、スペクトルの両端で、品質要件はほぼ同じです。単純なプロジェクトでは、新しい開発者/コンサルタントは、何が起こっているのかを理解するために6層の抽象化をたどる必要がなく、複雑な抽象化を誤解し、コストを削減するリスクなしに、期待に応え、変更を加え、すぐに貢献できます。
すべての場合において、実際にコードをスワップ可能または再利用可能にする必要はありませんでした。また、要件が変更されたため、テストが実際に最初の反復を超えて維持されたことはなく、時間がかかりすぎ、期限、ビジネス上のプレッシャーなどがありました。
だから-最終的に-
...エンタープライズクライアントに複雑な問題を解決するためにさえ、超単純なアーキテクチャを推奨するのは間違っているでしょうか?エンタープライズソリューションを定義するのは複雑ですか、それとも信頼性、同時ユーザー数、メンテナンスの容易さ、またはこれらすべてですか。
私はこれが非常に曖昧な質問であることを知っており、どの回答もすべてのケースに当てはまるわけではありませんが、私はしばらくの間ビジネスに携わっており、これらのさまざまな程度の複雑さで機能している開発者/コンサルタントからの連絡に興味があります、少なくともプロジェクトの開発中は、クールだが高価な抽象化が全体的なコストに見合うかどうかを聞くため。
...エンタープライズクライアントに複雑な問題を解決するためにさえ、超単純なアーキテクチャを推奨するのは間違っているでしょうか?
それはクライアントに依存します。多くの場合、より簡単なアプローチで問題ありません。単純なアプローチでは問題が解決しないため、自分は無能だと考える人もいます。「全体としては、ある理由で超安価である必要があります...」という理由で、一部のアイテムは作成コストよりもはるかに高価になります。
テストとインターフェースは使用されません
私は、これらのいずれかを使わずにコスト効果の高い重要なソフトウェアを作成する方法はあり得ないとは思いません。会社として、あなたがそれらなしで私に何かを売ろうとした場合、私はあなたが完全に柔軟性がなく、維持できない蒸し犬のうんちの山で私を抱き締めることを恐れるでしょう。 (edit:明確にするためにここでinterfacesについて話している、 not interfaces
。Javaスタイルのインターフェースが欠けていても、手続き型プログラムと関数型プログラムはすべてがらくたの山ではありません。
クールだが高価な抽象化が全体的なコストに見合うかどうか
プログラムの設計者として、私たちは物事がどこで変化するかについて知識のある推測を行い、そこに線を引くことで、変化する物事がすばやく、簡単に、そして正しく行われるようにする必要があります。避けられない変更が安くなるため、優れた抽象化は時間をかけてお金を節約します。
しかし、間違いなく、「建築宇宙飛行士」という用語が存在するのには理由があります。あなたはいつもスペースシャトルを作っているわけではありません。変更が必要なものの真ん中に存在する、または存在しない変更をサポートするために存在する不良な抽象化を追加すると、コストがかかる可能性があります。
しかし、私の経験では、抽象化されたコードのoverについて不満を言うのを聞いたことがありますが、プロジェクトだけを見たfail due抽象化されていないコードに。
アインシュタインを言い換えると、「物事は可能な限り単純でなければならない-しかし、より単純ではない」。一部のアーキテクチャの真の使用方法を理解することが重要です。それらは必ずしも個々のパフォーマンスのためではなく、多くの場合、仕事の満足のためでもありません。
エンタープライズプロジェクトは非常に大規模であり、非常に多くの人が働いているため、アーキテクチャが非常に複雑になる場合があります。そのアーキテクチャは、大部分の人がだれでも他の人につまずかずに、多くの人が何かに向かって取り組むことを可能にするものです。時には、個人の生産性を低下させ、仕事を難しくする複雑さを追加するだけですが、多くの人々が仕事をすることができます。これは、追加された努力が個人の減少した意欲を上回った場合に機能します。つまり、「生産性」を意味します。
これはあなたのクライアントの状況ですか?まあ、彼らの予算がこのプロジェクトの何百万ドルにない場合、多分そうではないでしょう。 100k未満であれば、ほぼ間違いなくそうです。薪ストーブではなく、原子炉用のコンクリートバンカーを建てます:)
それが状況が要求するものであるならば、それがあなたのクライアントのために「うまくいくかもしれない最も単純なもの」を提案することは必ずしも間違っていません。それを処理するための最良の方法かもしれません。確認する最も簡単な方法は、同様のタスクを実行するように設計された市販/オープンソースプロジェクトと比較して(とにかくこれはデューデリジェンスマーケットリサーチです)、彼らが何をするために彼らが何をしたかを確認することです。
もちろん、数百万ドルを使って作業しているときは、悪質なインセンティブがあることに注意してください。要するに、「お尻を覆う」:PhDが正しく理解する必要がある超複雑なアーキテクチャシステムを推奨する場合、それが地獄に行くとき、それは誰のせいでしたか?もちろん、あなたのものではない-あなたは誰もが最高だと言っている洗練された技術の中で最高のものだけを提案しました-しかし、それらは「複雑」で「難しい」ので、責任はそれを実装しようとした人々にあります。彼らは、十分に賢くも、十分に熟練もしていないに違いありません...つまり、プロジェクトが失敗したときに見栄えが悪くならないようにするために、多くのアドバイスが与えられます。それは悪いジュジュですが、それは私たちの現実の事実です。
テストを継続的に更新し、アーキテクチャの決定(更新ではなく変更時に計画を投げるなど)に失敗すると、多くのシステムが廃棄され、ゼロから書き直されるか、新しいものに置き換えられてしまうため、ソリューション」は数年後のことです。
便宜上、明快さと一貫性を強制するものが投げ出されると、あなたが非常にずるくると思って、実際に将来の変更をより難しく複雑にしたときに、本当に「やりがいがある」と考えるのは簡単です。 即時の利益を得るために将来の生産性を盗むことは非常に一般的です。特に、それが起こっていることに誰も気付いていない場合は悪いことです。
たとえば、テストは物事が変化したときに特に最適です。新しい方向性を反映するようにテストを変更してから、人々が考えを変えた、または前回何かを見逃したという認識に達したために現在「壊れている」ものすべてを修正します。今週はやることがたくさんあるので、これは睡眠をあきらめるようなものです。
アーキテクチャの複雑さは、実店舗でのビジネスのためにより大きなスペースを借りるようなオーバーヘッドコストです。管理する必要がある実際の複雑さがある場合にのみ意味があります。それが比較的一般的なソリューションに取り組んでいる3人のチームである場合、おそらく単純なMVCと最小限のツールで十分です。
それが複雑なマルチサブシステムのエンタープライズソフトウェアソリューションであり、予算に数百万もの予算があり、3から5のチームが少なくとも6ダースある場合、オブジェクト指向のプログラム分析とそのすべてのチャート、ダイアグラム、モデルでの往復エンジニアリングのみが与えることのできる、甘くて甘い愛を乞うでしょう。何十、何百もの目がまばたきなくあなたを見つめるのを防ぎ、彼らが今日何をすることになっているのか、どうやって何かを成し遂げるのだろうと思っているのを助ける何か。
複雑なのは相対的です。ポインタの概念、特にリンクされたリストのプログラミングを最初に学習したときは複雑でした(「フィールドとして機能するものを持つにはどうすればよいですか」)が、その概念を思いついたら、それは簡単でした。
関数型プログラミングの学習を始めたとき、ラムダの概念は複雑に見えました。しかし、それをC++からの関数ポインターのアイデアに関連付けましたが、それは簡単でした。カレー、そして完成品なども同様です。
最初にTDDの学習を始めたとき、それは複雑であるか、または開発プロセスにオーバーヘッドを追加すると考えました。現在、少なくともハッピーパスをカバーするテストがない限り、コードが完全であるとは思いません。依存性注入と具象クラスの代わりにインターフェースを使用することは、最初は複雑に見えます。ただし、依存関係の詳細を理解し、より高いレベルの構造に最初に焦点を当てることを前提として、コードをビルドできます。
"Uncle Bob" MartinによるClean CodeとThe Clean Coderをチェックしてください。最初は、より良いコーディング方法について話します。 2番目は、より良いコーダーになる方法について話します。 2つの間に違いがあります。
たとえを言えば、私はギターを学んでいます。簡単なメロディーやコードを弾くことができる段階です。コードとポジションの間の移行は困難です。もっと練習することで、それらのトランジションを簡単にヒットできるようになり、それが私にとって第二の性質になります。
リポジトリ/作業ユニットパターンを使用して、基本的な機能を構築しているときにインメモリリポジトリを使用し、納品に近づいたときに「sql lite」または「odata」リポジトリに変換します。これにより、最終的なインフラストラクチャが整う前(または決定する前)でも、より多くの機能を完了することができます。抽象化により、モックとスタブをより簡単に作成できるため、抽象化に依存するコードが期待どおりに機能することを確認できます。繰り返しますが、私は機能をトップダウンで完了することができます。
最初にインフラストラクチャを作成するのは間違っていると思います。単純な事実は、それが反俊敏であることです。 「インフラストラクチャ」にスプリントを費やすと、最終的に必要になるかどうかさえわからないものを構築することになり、ユーザーはフィードバックを提供するために何も見る必要がなくなります。
それが抽象化によって提供されるものです。それらを使用して練習すればするほど、それらは第二の性質になり、この議論を振り返って、あなたがどこまで開発したか驚嘆するでしょう。ちょうどうまくいけば、数年後にはコードの切り替えがどのように私にとって難しいのか疑問に思います。
コンサルティングへようこそ。
大量のお金を稼ぎ、機能をクライアントにすばやく提供するのに最適な場所です。
現在、両方ともうまく機能する、保守可能で適応性のある美しいソフトウェアを作成することを目指している場合および将来的には、より良いニッチを切り出すことができるヘルスケアまたは政府などの特定の業界で働くことをお勧めします質の高い仕事。
堅実な設計から得られるのは、長期にわたる信頼性の高い変更サイクルです。適切にトレーニングされたプログラマーと適切な設計が必要なため、最初はコストが高くなりますが、意図するところは、後の変更によるコストが急上昇しないようにすることです。
確かなアーキテクチャがなければ、変更は最初から安くなるだけです。プロジェクトが進化するにつれて、変更はますますコストがかかります。これは、より安価な労働力とより迅速な反復への欲求と相まって、変更は最終的に会社が支払うとに費やすよりもコストがかかるため、プロジェクトを中止する可能性があります。会社が待つことができるより多くの時間。平均的なチームと平均時間を必要とする可能性のあるその後の変更では、代わりに超人的なチームと、何年ものコードをふるいにかけて、変更を安全に行うのに十分なリファクタリングに長い時間が必要になります。
クライアントがこの犠牲を理解し、それを犠牲にしたい場合は、最も速い方法で必要な変更を行います。しかし、これらのトレードオフを彼らのために行うことは賢明ではありません(そしておそらく不正直です)。このプロセスは彼らのビジネス上の決定に影響を与えるからです。
仕事の一部は、「これらは必要なのか」と尋ねるだけでなく、リストしたすべての抽象概念を理解することです。しかし、それらがいつ、なぜ必要なのかを理解し、ソフトウェアの操作の一部としてそれらのパターンをどのように適用するのかを理解する必要があります。
仕事のもう1つの部分は、クライアントが表示できるもの(ui、機能)によって作業を判断することが多く、表示できないもの(コードベースの状態)について教育を受ける必要があることを理解することです。
...エンタープライズクライアントに複雑な問題を解決するためにさえ、超単純なアーキテクチャを推奨するのは間違っているでしょうか?
絶対違う。
クライアントの視点から
上記のように、それはクライアントに大きく依存します。また、どのソリューションがクライアントに適しているかを正確に判断できるかどうかにも依存します。常に望ましい値に達すると認識されるコストが存在しますが、コンサルタントとして、クライアントの適切な期待を設定するのはあなたの仕事です。場合によっては、その認識を満たす必要があります。他の人では、それらを修正することがあなたの最善の利益になります。結局のところ、あなたはあなたのクライアントの専門家でなければなりません。そうでない場合は、その専門家になるための知識が必要です。それは彼らがあなたに支払うものです。
開発者の観点から
使用するアーキテクチャの選択で最も難しいのは、多くの場合、特定のニーズを満たすためにテクノロジを利用するために必要な作業量を正確に見積もることです。これは、クライアントの期待に応えられないプロジェクトに非常に迅速につながる可能性があります。あなたが言及するこれらの「複雑な」コード片を使用すると、一部のプロジェクトが実際に高速化されることを理解してください。一部はそうではないことも理解されています。 あなたは、あなたまたはあなたのチームが知っていることに基づいて、その測定値を提供する必要があります。
エンタープライズソリューションを定義するのは複雑ですか、それとも信頼性、同時ユーザー数、メンテナンスの容易さ、またはこれらすべてですか。
詳細は異なる場合がありますが、一般に、エンタープライズソリューションは、幅広い混合ユーザーに適用されるソフトウェアソリューションです。同時使用ユーザーの数は、多くの場合は要因ですが、そうでない場合もあります。ユーザーの総数は、多くの場合さまざまなビジネスロールに属しますが、ソリューションが「エンタープライズ」であるかどうかに関する最大の決定要因の1つです。
多くのエンタープライズソリューションは非常に複雑ですが、非常にシンプルなものもあります。企業は信頼性の空気を与えます(そして確かに特定の基準に留めるべきです)が、ソリューションが異なれば、信頼性のレベルも異なります。
メンテナンスのしやすさは、すべての開発者(独立者またはチームメンバー)が努力することだと私は思うが、必ずしも簡単に達成できるとは限らない。重要なのは、「簡単」ではなく、しっかりとしたガイドラインのある保守手順があることです。理念、方法論、(ビジネス)環境活動、およびコードの複雑さ。
すべての場合において、コードを実際にスワップ可能または再利用可能にする必要はありませんでした
多くの場合、そうする必要は特にありません。ただし、これは常に目標です。これを検討してください... Webページからカレンダーにアクセスしたり、カレンダーを表示したりする必要があるクライアントがあるとします。独自のコードを再利用可能にすると、別のクライアントが同じことを要求したときに、すでにいくつかの作業が完了しています。そうしないと、もう一度やり直す必要があります。多くの場合、すべてのクライアントの問題は、将来別のクライアントが必要とする問題です。言い換えると、一緒に仕事をするすべてのクライアントは、将来のクライアントの仕事のコスト(必ずしも製品のコストではない)を削減できる可能性があるはずです。
要件が変更されたため、テストが実際に最初の反復を超えて維持されることはありませんでした。
ここでは、テスト方法論が十分に抽象化されていなかったと主張します。私は最近、独自の単体テストを直接実行するコードを使用しました。プロジェクトのニーズに対応するカスタムのassert
およびexpect
関数が作成されました。ユニットテストが必要なときはいつでも、コードを調整することなく適用できます。実際、コードはアサートとともに積極的に配布され、まだそこにあることを期待しています。作業コードの一部としてこれらのチェックを行いました。
...締め切り、ビジネスのプレッシャーなど...
多くの場合、余分なビジネスプレッシャーとコーディングプロセスを妨げる期限が、クライアントではなく開発者の責任であることに気づきました。これは常に当てはまるわけではありませんが、多くの場合、ビジネスのプレッシャーは、クライアントの期待に応えられないという認識によって引き起こされます。締め切りがコードの妨げになる場合、多くの場合、開発者が使用可能な機能コードに必要な作業量を正確に測定できなかったことが原因です。つまり、スケジュールを立てる(クライアントはそれを期待する)、測定する(将来のクライアントはそれを期待する)、それらを実行します(ユーザーはそれを必要とします)、そしてそれらのために支払いを受けます(あなたの契約それを要求する必要があります)。
この質問の多くは信じられないほど主観的なものです。建築の複雑さの複合コストに関するデータを提示することが重要だと思います。本当に興味深い ケーススタディ MITからのスローン
基本的に、すべてのコードベースが(A)開発者の生産性を高めるためのシンプルさと(B)新しい機能が追加されたときに機能が損なわれないようにするための見通しとの間を行き来するために努力すべきいくつかの幸せな媒体があると思います。
ケーススタディは、複雑度の高いコア(ユーティリティや高度な抽象化など)と複雑度の低いペリフェラル(依存関係の少ない新しい機能を考える)を備えたモノリシックコードベースを持つこの1社に関するものです。周辺とコアの間で、開発者の生産性は50%減少し(異常なもの)、欠陥は2.6倍に増加しました。
抽象化によって自動的に複雑さが増すというあなたの発言には完全に同意しません。抽象化は、今日ではマシンコードに解決する必要がない主な理由です。
抽象化に伴う問題は、エンドユーザーに複雑さを隠すのではなく、内部の仕組みに焦点を合わせる傾向があることです。抽象化はロジックを分離し、再利用性を促進する必要があります。さらに、テストは建築設計に挑戦する優れた方法だと思います。これは主に、ユーザーの視点からコードを確認する必要があるためです。
時間の不足についてあなたが言及した問題は、悪いデザインの主な原因です。通常、優れた設計はすぐには実現されませんが、反復と改良によって実現されます。通常、お客様から要件を抽出する方法は、ユーザーストーリーです。このようにして、顧客はシステムを何にどのように使用したいのかを考えることができます。さらに、アーキテクトがシステムの意図を認識している場合は、適切な設計決定または抽象化手法を選択して、システムに柔軟性を追加できます。彼らがクールでニースだからではありません。
複雑なソフトウェア開発手法に関するあなたの疑問に関連することができます。あなたが挙げた理由から、できる人はたくさんいると思います:新しいシステムの最初の作成にオーバーヘッドを追加しますが、常に即座に表示されるわけではありません利点。
それは明らかにそれらが存在しないことを意味しません、すべての概念には理由があります、ほとんどの場合良いものです。全体として、プロジェクトを完成させるために必要な作業を削減し、後でそれを強化する必要があります。
もちろん、理論的には、これらすべての理論的な利点を学んだことは間違いないでしょう。そして、それもまた正当な理由があるかもしれません。概念の権利を使用することは、それが使用される理由を理解することほど簡単ではありません。経験を持っているかもしれませんが、いつ抽象化するか、そうでないかを決めるのに、クライアントはまだそうでないかもしれません。
プロジェクトのすべての可能な時点で概念を使用すると、多くの時間がかかる可能性があり(そのことについての簡潔な文についてはTelatsynsの回答を参照)、概念を適切な場所で使用しても、十分な経験がない場合は費用がかかる可能性があります。 。あなたが言ったように、それらは単純な概念ではありませんが、あなたの状況に合わせる必要がある本当に複雑なものもあるので、理論的理解はそれを速く正しく使うには十分ではありません。
そして、これらの理由から、クライアントが概念から離れることに気付かずにクライアントがテストと抽象化を放棄して、単純な作業を再開しても、驚くことではありません。
ソフトウェアエンジニアリングの大きな障壁について、この記事をお勧めします。 ソフトウェアエンジニアリングの専門知識の7つの段階 このページのどこかで偶然見つけましたが、非常に興味深い考えや経験を表しています。