ソフトウェアの複雑さとの戦い

1. 研究開発効率とは何ですか?

研究開発の有効性について話すとき、私たちは何を話しているのでしょうか? この問題は、実際の研究開発効率が予想よりもはるかに低いという問題があるから提起され、議論されています。会社が設立されたときは、設立から立ち上げまでアイデアを完成させるのに 1 人で 2 時間かかりますが、会社が数千人規模に成長すると、同様のことを実行するには複数のチームが必要になり、完了までに数週間かかることがよくあります。これにより、はっきりとしたコントラストが生まれ、このコントラストによって生じる印象は、ソフトウェア エンジニアリングを深く理解していない人にとっては理解しがたいものですが、多くの場合、これについてはどうすることもできません。

注意深い読者は、前の記事で「効果」という言葉と「効率」という言葉の両方を使用したことに気づくでしょう。有効性は製品の経済的パフォーマンスを測定するためによく使用されますが、効率性はビジネスの応答性の向上、スループットの向上、コストの削減のみを指します。

ここでの定義は Qiao Liang 氏の教材「How to Build a High-Performance R&D Team」を引用していますが、この記事では製品開発手法については触れていないため、以下では「効率」に焦点を当てます。

1910 年代、初期のインターネット実践者が簡単な Web サイトを開発したとき、Linux、Apache、MySql、および PHP (Perl) の使い方を学ぶだけで済みました。このテクノロジには、LAMP という覚えやすい名前が付けられています。しかし今日、大規模なインターネット企業で働く開発者は、分散システム、マイクロサービス、Web 開発フレームワーク、DevOps パイプライン、コンテナーやその他のクラウドネイティブ テクノロジーなど、桁違いに増加したテクノロジー スタックを理解する必要があります。 。これだけの複雑さならまだしも、これらは業界標準の技術なので、開発者の学習能力によってすぐに使いこなすことができます。気が遠くなるような複雑さは、大規模なインターネット企業が 1 つまたは複数のソフトウェア システムを持っていることです。これらのソフトウェア システムの規模は 100 万行を超えることがよくあり、品質は良いか悪いか (ほとんどの場合悪い)、開発者はこれらのシステムに基づいていなければなりません動作します。このとき非常に高い認知負荷を背負わなければならず、ソフトウェアを改変する際には本来の機能を破壊する大きなリスクも伴い、リスクの増大は必然的に速度の低下を招くことになる。

したがって、研究開発効率の大幅な低下の主な要因の 1 つは、ソフトウェアの複雑さの指数関数的な増加です。

2. 本質的な複雑さと偶発的な複雑さ

Fred Brooks は、古典的な本「The Myth of the Man-Moon」の記事「No Silver Bullet」でソフトウェアの複雑性について素晴らしい議論を行っており、ソフトウェアの複雑性を本質的な複雑性 (Essential Complexity) と偶発的な複雑性 (Accidental Complexity) に分けています。ここでの必須と偶然という 2 つの単語は、アリストテレスの「形而上学」から来ています。アリストテレスの見解では、本質的属性はオブジェクトが持つ必要がある属性であり、偶然的属性はオブジェクトが持つことができる属性です (また、それを所有する必要はありません)。たとえば、電子商取引ソフトウェアには取引や商品などのビジネスの複雑さが必然的に含まれるため、これらを本質的な複雑さと呼びます。また、同じ電子商取引ソフトウェアは、コンテナ テクノロジに基づいて (またはそうでなく) 実装することも、Java に基づいて作成することもできます。 (またはそうでない)、したがって、コンテナーテクノロジーまたは Java テクノロジーによって導入される複雑さを、偶発的な複雑さと呼びます。

フレッド・ブルックスが述べたソフトウェアの本質的な複雑さは、問題領域自体から生じる複雑さを指し、問題領域の範囲を縮小しない限り、本質的な複雑さを取り除くことはできません。偶発的な複雑さは、Java の選択、コンテナの選択、中間プラットフォームの選択などのソリューションによって引き起こされます。

さらに、これら 2 つの複雑さは、いわゆる問題空間 (問題空間) と解決空間 (解決空間) から理解できます。問題空間とは、現実の初期状態と望ましい状態、および一連の制約規則です (私たちはそれをビジネスと呼ぶことが多いです)、ソリューション空間はエンジニアによって設計および実装され、初期状態から望ましい状態までの一連のステップが行われます。経験の浅いエンジニアは、問題を十分に理解せずに急いでコードを書くことがよくありますが、これは問題空間と解決空間の理解が不足しているためです。近年、ドメイン駆動設計が多くのエンジニアから賞賛されています。その主な理由は、は、誰もが問題領域に注意を払い、本質的な複雑さに直面するように導きました。Eric Evans の 2003 年の著書『ドメイン駆動設計』の副題は「ソフトウェアの中心部の複雑さへの取り組み」ですが、これは偶然ではないと思います。

「神話上のマンムーン」は 1975 年、今から 47 年前に書かれました。ブルックス氏は、ソフトウェアの本質的な複雑さは本質的に軽減することはできないと信じています。また、高級プログラミング言語の進化と開発環境の発展によっても、それは実現できないと考えています。 , 場合によっては、複雑さが大幅に軽減されることがあります。彼の結論の前半は正しいですが、後半は間違っています。今日、より高度なプログラミング言語、より機能豊富なフレームワーク、より強力な IDE がありますが、これらのツールを学習することが不可欠な作業になっていることに誰もが徐々に気づいています。小さな負担。

3. 複雑さの爆発

ソフトウェアが死なない限り、それを使用する人々とそれを保守する開発者がいる限り、その複雑さはほぼ確実に増加し続けるでしょう。ソフトウェアの存続と発展は商業的な成功を意味し、時間が経つにつれてソフトウェアを使用する人が増え、機能が追加され、その価値がますます高まり、企業に継続的な利益をもたらします。先ほど説明したように、ソフトウェアの本質的な複雑さは、実際には問題空間 (またはビジネス) によってもたらされるため、ソフトウェアに機能を追加するほど、ソフトウェアに本質的に複雑さが必然的に含まれるようになります。さらに、解決されるすべての問題は解決策に対応しており、解決策の実装には必然的に新たな偶発的な複雑さが生じます (たとえば、支払いを実現するには、三者間の支払いシステムを接続するための新しいプロトコルを実装する必要があります)。ソフトウェアの複雑さは、商業的に成功している企業が直面しなければならない嬉しい悩みです。

ブルックスの時代と異なるのは、今日のソフトウェアが人間の生活のあらゆる側面に浸透していることです。ある程度の規模のインターネット ソフトウェアは、数百万または数千万のユーザーにサービスを提供します。アリババのダブル11は2020年にピークに達し、毎秒58万3,000件のトランザクションが発生し、Netflixは2021年第4四半期に2億2,000万人の加入者を獲得し、TikTokは2021年9月に月間アクティブユーザー数が10億人を超えたと発表した。これらの驚くべきビジネスの成功の背後には、複雑なソフトウェア システムが不可欠です。これらの複雑なソフトウェア システムはすべて、スケーラビリティに関する大きな課題に直面する必要があり、1 人にサービスを提供するシステムと 1 億人にサービスを提供するシステムとでは、複雑さには大きな違いがあります。

本質的な複雑さは 1 つの側面であり、結局のところ、ユーザーが増えれば機能も増えることを意味しますが、ここで偶発的な複雑さを無視することはできません。最も典型的なのは、分散システムによって導入される偶発的な複雑さです。このような多数のユーザーをサポートするには、システムは数万台のマシンを管理でき (スケジューリング システム)、ユーザー トラフィックを管理でき (負荷分散システム)、異なるコンピューティング間の通信を管理できる必要があります。ユニット (サービス ディスカバリ、RPC、メッセージング システム) は、サービス (高可用性システム) の安定性を維持できる必要があります。ここでの各トピックは、数冊の書籍で拡張および説明されており、開発者が最初にこの知識を習得した後でのみ、大規模ユーザーにサービスを提供するのに十分な拡張性のあるシステムを設計および実装できます。

分散システムによってもたらされる複雑さと比較して、チームの拡大によって複雑さが急激に増大する可能性が高くなります。成功した製品のソフトウェア開発チームは数百人規模になることも多く、中には1000人、2000人規模に達するチームもあります。会社に厳格かつ明確な人材採用基準がなく、従業員が入社した後に厳密な技術仕様トレーニングがない場合、全員が異なるスタイルと異なる長期および短期目標を持つコードをコード ウェアハウスに提出すると、ソフトウェアの複雑さは急激に増加します。

たとえば、チーム メンバーが個人的な好みに基づいて、すべて Java であるシステムに NodeJS コンポーネントを追加します。そのメンバーがチームを離れると、このコンポーネントは NodeJS に詳しくない他のメンバーにとって単なる複雑さになります。

たとえば、チームの新しいメンバーがシステムに詳しくなく、システムの他の部分に影響を与えずに機能をリリースしたいと考えている場合、自然にどこかにフラグを追加し、必要なすべての場所に if 判定を追加します。新しい問題空間に合わせてシステム設計を適応させるのではなく、変更しました。

たとえば、システムの異なるモジュールで同じドメインの概念に対して、異なる人が異なる名前を使用すると、核となる意味はまったく同じですが、異なる属性が追加されるため、理解に多大なコストがかかります。

同様の複雑さはソフトウェアに固有のものではありませんが、時間の経過とともに蓄積され、開発者に多大な認知的負荷を与えます。ソフトウェアが長期間存在する場合、現在の開発チームの規模に加えて、これまでそのソフトウェアにコードを提供してきたすべての人々も考慮する必要があります。プログラマーが「祖先のコードを見ると、そうすべきではない」と考えるのも不思議ではありません。触ってよ!」 そんなふうに誰かをからかうと、あなたはわざとらしく微笑むでしょう。

私は、Ruby や Scala など、メタプログラミング機能を備えたさまざまな強力なプログラミング言語を学び、これらの機能を使って興味や創造性を解き放つことが好きです。しかし、特定のチーム規模の運用環境でこれらのプログラミング言語を使用することには躊躇しています。コード スタイルをレビューして制御するために多大な努力を払わない限り、10 人で作成したコードは、 10 のスタイルでこの複雑さの成長は悲惨なものでした。逆に、Java のような柔軟性の低い言語を使用すると、全員が一貫性のないコードを書くことが難しくなります。

チームの拡大は別の問題も引き起こすことになりますが、大規模なチームでは、主要な関係者の目標がソフトウェアの複雑さに影響を与える重要な要素となります。私は個人的に、単純な解決策が解決策の領域に明確に配置されている多くのケースを見てきましたが、このため、当事者は次のような複雑な解決策を選択する必要がありました。

  • 当初の計画ではシステム A を直接変更するだけでしたが、システム A を担当するチームに問題を解決する意欲がなかったため、他のチームが回り道をしてシステム B、C、D を変更して問題を解決する必要がありました。
  • 当初の計画ではシステム A を直接変更するだけでしたが、システム B の責任者や上司からの圧力により、A、B を変更したり、C を同時に導入したりする計画に発展する必要がありました。

さらに、さまざまな理由により、完全に仮説的な問題 (つまり、実際には存在しない本質的な複雑さ) が提起され、その後、そのソフトウェア システムがしばらく使用されることがあります。最終的に、個人またはチームの目標は達成されますが、ソフトウェアは追加の価値を提供しないため、複雑さの増大は止まりません。

したがって、ソフトウェアに価値があり、ユーザーが存在し、開発者によって保守されている限り、機能は追加され続け、商業的に成功するソフトウェアには必然的にユーザー数の増加と研究開発チームの成長が伴います。これら 3 つの要因は今後も促進されます ソフトウェアの複雑さが爆発的に増大するにつれて、当然のことながら、研究開発効率はますます低下します。ソフトウェア エンジニアリングが解決する必要がある中心的な命題は、研究開発効率が急激に低下しないように複雑さをどのように制御するかということであり、これはソフトウェアの複雑さとの戦いです。

4. 間違った対応方法

継続的な効率の低下に直面して、研究開発チームのマネージャーは何かをしなければなりません。残念なことに、多くの管理者は効率の低下がソフトウェアの複雑さの増加によって引き起こされているということを理解しておらず、複雑さが爆発的に広がる原因を冷静に考えることができず、その結果、多くの管理者が表面的であることがわかります。 . 対処法はあまり効果がなく、逆効果になる場合もあります。

最もよくある間違いは、変更できない期限を設定して、開発チームに機能の提供を強制することです。しかし、数え切れないほどの経験から、ソフトウェア開発とは、品質、範囲、時間の三角形のトレードオフを模索することが重要であることがわかります。研究開発チームは、残業をして休暇を犠牲にすることで短期的にはある程度の時間を得ることができますが(長期の残業は実際には有害です)、この時間制限が厳しすぎると、必然的に要件の範囲とソフトウェアの品質が犠牲になります。要件の範囲が縮小不可能な場合、犠牲にできるのは品質だけです。実際には、短期間に多くの偶発的な複雑さがシステムに注ぎ込まれることを意味します。

もう 1 つのアプローチは、既存のシステム テクノロジを「より高度な」テクノロジに置き換えることです。たとえば、Java のマイクロサービス システム テクノロジを使用して PHP + Golang システム テクノロジを置き換えたり、商用製品の成功をサポートしてきたミドルエンド テクノロジを使用したりします。あるいは、自社で構築したオープンソース サービスをクラウド製品に置き換えるという単純な場合もあります。これらのアプローチの背後にある基本的なロジックは、「より高度な」テクノロジーは成功したビジネス シナリオで証明されており、したがって既存の問題の解決に直接適用できるというものです。

しかし実際の状況では、意思決定者は、現在の問題が「より高度な」テクノロジーによって解決できる問題であるかどうかを無視することがよくあります。既存のシステムがサービスを提供するユーザーの数が急速に増加し、スケーラビリティが深刻な問題に直面している場合、答えは「はい」です。既存のシステムの安定性に懸念があり、利用できないことが多く、ユーザー エクスペリエンスに深刻な影響を与えている場合、答えは「はい」です。確かにそうです。しかし、既存のソフトウェア システムが研究開発効率の低下という問題に直面している場合、「より高度な」テクノロジはほとんど役に立たないだけでなく、新旧テクノロジの切り替えによりシステムが偶発的に複雑になることもあります。

5. 正しい技術戦略

先ほど、ビジネスの複雑さの増大、分散システムのサイズの増大、チームのサイズの増大、主要な利害関係者の目標などの要因など、複雑さの増大につながるいくつかの核となる要因について説明しました。それらの中で、分散システムによってもたらされる偶発的な複雑さは、最も簡単に排除できます。この観点をよりよく理解するために、ワードリー マップについて簡単に紹介します。

Wardley Mapは技術戦略の分析を支援するツールです。マップ形式で表示されます。マップ内の各コンポーネントはソフトウェアモジュールとして理解できます。縦軸は値の方向です。上に行くほど、それに近づきます。」はユーザー価値、横軸は進化の方向で、右に行くほど成熟した商品に近づきます。

たとえば、上の図では、コンピューティングは、今日多くの成熟したクラウド コンピューティング企業によって提供されているコンピューティング リソースですが、図のコンテキスト ビジネスのユーザー価値とは大きく異なります。バーチャル フィッティング (仮想フィッティング) は、ユーザーが適切な服を購入したかどうかをより確信できるため、ユーザーの価値に非常に近いものですが、このテクノロジーは明らかにまだ成熟した製品ではなく、単なる自社開発のモジュールです。そこからオープンな商品化の段階に到達します。

何百万、何千万ものユーザーをサポートする分散システムを設計および開発することは非常に困難であり、システムに多くの複雑性が導入され、この複雑さを管理すること自体が大きな課題となります。幸いなことに、Alibaba、Amazon、Google、Microsoft を含む今日のクラウド ベンダーはいずれもこの分野で豊富な経験を有しており、長年の蓄積を通じてこの経験を商用製品を通じて市場に提供してきました。

Wardley Map 手法から分析すると、ほとんどすべてのビジネスの左上隅 (直接のユーザー価値に近く、未熟) は自分たちで開発し、複雑さを負わなければならず、正しいソフトウェア アーキテクチャが行われている限り、右下隅の部分 (既製品の場合、直接のユーザー価値から離れた部分) を抽出して、直接購入できます。したがって、現在、資格のあるアーキテクトは、クラウド ベンダーでない限り、データベース、スケジューリング システム、メッセージ キュー、分散キャッシュ、その他のソフトウェアの研究開発に投資すべきではありません。購入することで、研究開発チームはこれらの複雑さをまったく負担する必要がなく、ユーザー規模の拡大を容易にサポートできます。

6. ミクロレベルでの複雑さの制御

適切なテクノロジー戦略は、マクロ レベルでシステムの複雑さを制御するのに役立ちますが、ミクロ レベルではまったく異なるアプローチが必要です。この方法について説明する前に、「Grokking Simplicity」という本から簡単な例を引用したいと思います。(興味深いことに、本書の副題「関数型思考で複雑なソフトウェアを飼いならす」も、複雑さと戦うという意図を表しています。)

2 つの関数 (JavaScript) を見てみましょう。

function emailsForCustomers(customers, goods, bests) {  var emails = [];  for(var i = 0; i < customers.length; i++) {    var customer = customers[i];    var email = emailForCustomer(customer, goods, bests);    emails.push(email);  }}
function biggestPurchasePerCustomer(customers) {  var purchases = [];  for(var i = 0; i < customers.length; i++) {    var customer = customers[i];    var purchase = biggestPurchase(customer);    purchases.push(purchase);  }}

この 2 つの関数は、一見すると何の問題もありませんが、どちらも特定のビジネス ロジックに従って戻り値を用意し、ループを記述し、必要なデータを抽出します。唯一の違いは、前者の関数のビジネス ロジックが後者の機能のビジネス ロジックは、顧客の電子メールを取得することです。ビジネス ロジックは、顧客がこれまでに出した最大の注文を取得することです。ただし、このような単純なコードの場合、軽減できる複雑さはまだあります。これら 2 つの関数を理解して読み取るには、毎回 for ループを理解する必要があります。この複雑さはさらに軽減できますか? 答えは「はい」です。

このユビキタスなロジック、つまり、コレクションの各要素を走査し、各要素に対して何らかの処理を実行し、新しい要素を返し、最後にそれを新しいコレクションに入れるという処理は、map 関数に抽象化できます。この例では、JavaScript が Map 関数をサポートしていると仮定し、上記のコードは次のように記述できます。

function emailsForCustomers(customers, goods, bests) {  return map(customers, function(customer) {    return emailForCustomer(customer, goods, bests);  });}
function biggestPurchasePerCustomer(customers) {  return map(customers, function(customer) {    return biggestPurchase(customer);  });}

言語構文の要素はさておき、map 関数を除くこのコードの残りの部分は関数名です。関数名が適切に命名されている限り、実際には本質的な複雑さとビジネス ロジックを表しています。業界の先駆者である有名な Martin Fowler、Kent Beck、Robert C. Martin は全員、著書の中で名前付けの重要性を強調しています。彼らは皆、コードが意図を明確に伝達できることを望んでおり、ここでの中心的な意図は、問題のドメインが一致しました。

この例のコードは非常に単純で、プログラマであれば誰でも理解できますが、ここでも複雑さを軽減する余地があります。数年間にわたって蓄積されたコードからどれだけ複雑さを排除できるか想像できるでしょう。また、私は何年も前に同僚で年長のプログラマーの教えを思い出しました。彼は、優れたコードは次のとおりであるべきだと言いました。

  • それは動作します
  • 分かりやすいです
  • 変更しても安全です

実際、2 番目の点を達成することはすでに非常に高い要件であり、これにはソフトウェア エンジニアが慎重に設計し、要件を明確に伝え、レガシー システムとの統合を考慮する必要があり、さらに新しいテクノロジ (新しい言語、新しいパラダイム) の使用を自制する必要があります。 )衝動。3 番目のポイントは、実際に単体テストを真剣に書くことを教えてくれます。

要件を明確に議論した後、対応するコードと単体テストを作成しました。具体的には、元の数万行のコード ベースに数百行を追加し、元のコード ベースに約 1,000 行を加え、単体テストに 3 ~ 5 個の単体テストを追加し、ローカルで mvn clean テストを実行しました。このプロセスにかかる時間は数分だけで、すべてのテストが成功しました。コードを提出することに非常に自信を持っていましたし、実稼働環境でコードが問題に遭遇する可能性は非常に低いことを知っていました。

この感覚の核となるのは質の高いフィードバックであり、フィードバック時間が短いほど効率は高く、フィードバック時間が長いほど効率は低くなります。ソフトウェア エンジニアは、複雑さを制御することに加えて、タイムリーな品質フィードバックの重要性を理解する必要があります。コード行を作成した場合、品質に問題があることに気づくまでに数時間、場合によっては数日かかります。効率が低いことは想像に難くありません。そのため、組織が単体テストを上から下へ書くことを推奨しているときに、人々の実践で奇妙な現象が見られると、私はよく奇妙に感じます。

  • 低品質の単体テスト: アサーションを記述しないことや、いたるところに print ステートメントを使用し、人々が検証することを要求することが含まれます。
  • 不安定な単体テスト: コードは正常ですが、テストは失敗し、テスト スイートは信頼できません。
  • 非常に長い単体テスト: 実行には数十分から数時間かかります。
  • コードからの単体テストの生成: 申し訳ありませんが、カバレッジ バニティ メトリクスを向上させることを除いて、これは無意味だと思います。

7. ソフトウェア倫理

ソフトウェアの複雑さをミクロレベルで制御し、単体テストを慎重に作成してコード作成の質の高いフィードバックを確保することは、研究開発の効率化にとって重要ですが、時間と労力がかかります。そして、この投資のビジネスへの価値が反映されるまでに長い時間がかかるため、研究開発幹部によって見落とされがちです。

開発者は、コード、ドキュメント、API サービスなどのソフトウェア中間生成物を生成し、これらの中間生成物が徐々に製品に組み立てられ、商品価値を生み出します。ソフトウェア中間製品の品質は、研究開発組織の全体的な効率にとって非常に重要であり、複雑さが適切に制御されているコードとシステムは高品質のソフトウェア中間製品であり、優れたソフトウェア研究開発倫理、またはこれが考慮されることもあります。良好なエンジニアリング文化とは、次のことを意味します。誰もが高品質のソフトウェア中間製品を提供することを誇りに思い、低品質のソフトウェア中間製品を提供することを恥じるコンセンサス文化を形成します。

ソフトウェア開発の中核となる責任の 1 つは、ソフトウェアの複雑さに注意を払い、オープン コード、ドキュメント、コード レビューなどを通じてソフトウェアの複雑さの情報を透明にし、複雑さを増加/減少させるすべての動作を透明にし、次のような人々を奨励し続けることです。複雑さを排除し、動作の程度を高めます。この方法でのみ、ミクロレベルで複雑さを制御する方法を実装できます。

8. システム アーキテクチャが複雑さに及ぼす影響

マクロな技術戦略とミクロなエンジニアリング文化の間には、ソフトウェアの複雑さにも重要な影響を与える重要な意思決定領域があり、私はそれをシステム アーキテクチャと呼んでいます。要件に直面したとき、経験の浅いエンジニアは使い慣れたモジュールで直接解決することを考えますが、経験豊富なエンジニアは最初にシステムのコンテキストを考えます。優れた技術文書作成ガイド「Design Docs at Google」では、設計文書にはシステムコンテキスト図を明確に記述する必要があると強調されていますが、その理由は何でしょうか?

最近、レガシー システムで依存関係リンクの並べ替えと分析を行いました。このシステムは、リソースの仕様、バージョン、依存関係などを含む、運用環境のさまざまなリソースの管理を担当します。並べ替えが完了すると、全体的な構造は次のようになります。この写真はおおよそ次のようなものです。

図の青い部分は制御および実行サブシステム (システム X、Y、Z) であり、コンテナーのスケジューリングの制御、イメージ変更の実行の制御など、比較的明確です。しかし、これは残り (A1、A2、A3、C1、C2、S、E) には当てはまらず、イメージのバージョン、コンテナーの仕様、コンテナーの仕様、存在するかどうかなど、リソースの実行中のバージョンをすべて管理します。 GPU、コンテナのサイズ、数、関連するネットワーク リソースなどが含まれますが、7 つのサブシステムに進化し、実際には非常に複雑になります。ドメインの概念が非常に多くのサブシステムに分散されると、一連の問題が発生します。

  • サブシステムが異なれば、同じ概念に対して異なる名前が付けられ、対話中にさまざまな変換が行われます。
  • 異なるサブシステムは同じエンティティのいくつかの概念を前提としているため、大規模な変更が必要となり、エラーが発生しやすくなります。
  • 運用コストとメンテナンスコストが高くなります。

この複雑さを引き起こした要因を注意深く分析した結果、これは技術戦略の問題でも、ミクロレベルのエンジニアによる低品質のコードの作成の問題でもなく、他のより深い問題であることがわかりました。重要な要因は、これらのサブシステムが異なる時期に異なるチームに属し、さらには異なる部門に属することです。具体的には、各部門の各チームの目標が一貫していない場合、このシステムがさまざまなチームに分割されている場合、残念ながら、システム全体の複雑さを制御する責任があります。このシステムを外部輸出向けに商用化するチーム、このシステムを仮想マシンモードからコンテナモードに進化させるチーム、リソースのコスト管理を担当するチーム、全体の状況を考えるチームがあり、利用可能なアーキテクチャ、しかし、全体的な観点から概念と境界を制御するグローバルアーキテクトがなければ、システムは自然にそのような状態に劣化します。

問題領域にシステム アーキテクチャがない場合、またはそのシステム アーキテクチャが間違っている場合、異なる人々が異なる言語を発明していることがわかります。これは、数十キロメートル離れた 2 つの村が同じ概念に対して異なる見解を持っているようなものです。単語とか発音とか。日常のコミュニケーションにはコンテキスト (表情、雰囲気、環境など) が含まれるため、日常生活では言語の不正確さは問題になりませんが、コンピューターの世界では、言語の不正確さはコード翻訳を作成する必要があることを意味します。間違っているとソフトウェアが失敗し、実行エラーが発生します。これが、ドメイン駆動設計が統一言語と限定されたコンテキストを重視する理由です。しかし、ドメイン駆動設計は方法論であり、その方法を知っていても、システム アーキテクチャの役割がないことを補うことはできません。

この複雑なシステムは、コンウェイの法則の優れた例です。コンウェイの法則では、「設計されたシステムのシステム構造は、組織のコミュニケーション構造を複製します。」と述べられていますが、この文は実際にはやや抽象的です。より具体的な説明は次のとおりです。

「コンウェイの法則は...合理的な社会学的観察です...モジュール A とモジュール B の設計者と実装者が効果的に通信できない限り、2 つのソフトウェア モジュールを正しく接続することはできません。したがって、ソフトウェア システムのインターフェイス構造は、ソフトウェアシステムを生み出す社会構造や組織に対応しています。」

コンウェイの法則によって明らかになった事実は、ソフトウェア アーキテクチャは主に組織の構造とコラボレーション モデルによって決定されるということであり、これは実際にはソフトウェア テクノロジの問題ではなく、組織管理の問題です。したがって、システム アーキテクチャ レベルでソフトウェアの複雑さの問題を解決するには、組織管理の課題に直面する必要があります。主要な問題領域の所有者は 1 人ですか? 異なるチームが同じ問題領域でシステムを繰り返し構築している場合、チームを統合するにはどうすればよいでしょうか? 既存のチームが、存続のために責任を負うシステムの重要性と特殊性を誇張し続ける場合、この問題をどのように特定すればよいでしょうか? エンジニアがアーキテクチャの合理性を理由に、苦労して取り組んできたシステムモジュールを放棄してもよいような、十分な安心感を組織はどのように全員に与えることができるのでしょうか?

管理作業について説明することは、ソフトウェアの複雑さについて説明するこの記事の範囲を超えているようですが、多くのエンジニアは漠然と感じているか、よく考えてみて、これがソフトウェア システムをエレガントで堅牢にする、または問題だらけにする基本的な要素であることに最終的に気づきます。穴があります。

まとめ

私の元上司、郭東梅氏は、かつて QCon のスピーチで優れた建築家の特徴に​​ついて語ったことがありますが、ビジョン、優れた思考力、インスピレーションを与える能力といった誰もがよく理解している特徴に加えて、特に「良心を持つこと」を強調していました。 」 彼はこう言った。

良心を持つことは、建築家が時間をかけて獲得できる最も重要な資質です。良心を持つとはどういう意味ですか?正直になって、正しいことを選択してください。多くの人々は非常に頭が良く、ビジネスを深く理解し、豊富な技術的実践を持っていますが、必ずしも会社や組織にとって正しいことを行うとは限りません。良心を持つことはとても大切で、建築家に良心がなければ会社に多大な損害を与えてしまいます。

ソフトウェアの複雑さは人間の行動によって引き起こされます。ミクロレベルでの品質とエンジニアリング文化に焦点を当てているかどうか、システムアーキテクチャレベルで組織構造とコミュニケーションを客観的な問題領域と一致させるか、企業の利益に沿った意思決定を行うかなどです。技術戦略レベルでは、すべてがここに存在しており、変更することのできない客観的な法則です。これらの法律を認識し、これらの法律に基づいて意思決定を行い(変更や影響を受ける可能性があります)、会社の価値を創造するよう努め、すべてのエンジニアが尊重されるように努めることは、すべてのエンジニア、アーキテクト、および技術マネージャーがとるべき基本的な態度です。守ってください。ソフトウェアの複雑さについて説明するこの記事の本来の目的は、複雑さの背後にある客観的な法則を明らかにしようとすることであり、誰もが現実を認識し、より現実的な態度で思考し意思決定を行い、より価値があり満足のいくソフトウェア システムを作成できるようにしたいと考えています。

参考資料:

  1. ドメイン駆動設計を選択する理由 この記事では、本質的な複雑さとドメイン駆動設計の関係について明確に説明します。
  2. マンムーンの神話 - 「特効薬はない」では、本質的な複雑さと偶発的な複雑さの概念が説明されています。
  3. 「リーン プロダクト プレイブック」 - この本の第 2 章では、問題空間と解決策空間について明確に説明しています。
  4. Wardley Map - テクノロジー戦略を分析するための優れたツール 商用製品を合理的に選択すると、システムの複雑さを軽減できます。
  5. Grokking Simplicity - ミクロレベルで、関数的思考を使用してソフトウェアの複雑さを軽減します。
  6. Google でのデザイン ドキュメント
  7. コンウェイの法則
  8. 複雑さのジレンマに注意: ソフトウェアの複雑さについての考え方

著者|シャオビン

クリックして今すぐクラウド製品を無料で試し、クラウドでの実践的な取り組みを始めましょう!

元のリンク

この記事は Alibaba Cloud のオリジナル コンテンツであり、許可なく複製することはできません。

雷軍氏: Xiaomi の新オペレーティング システム ThePaper OS の正式版がパッケージ化されました Gome App の宝くじページのポップアップ ウィンドウが創設者を侮辱 米 政府が NVIDIA H800 GPU の中国への輸出を制限 Xiaomi ThePaper OS インターフェース マスターが Scratch を使用して RISC-V シミュレータを操作し、正常に実行されました Linux カーネル RustDesk リモート デスクトップ 1.2.3 がリリースされ、Wayland サポートが強化されました Logitech USB レシーバーを取り外した後、Linux カーネルがクラッシュしました DHH の「パッケージング ツール」のシャープ レビュー": フロントエンドはまったくビルドする必要がありません (No Build) JetBrains が技術文書を作成するために Writerside を起動 Node.js 21 用ツールが正式リリース
{{名前}}
{{名前}}

おすすめ

転載: my.oschina.net/yunqi/blog/10120475