ハクソク

世界を動かす技術を、日本語で。

自分が関わっていないソフトウェアは設計できない

概要

  • 大規模ソフトウェア設計においては、現場エンジニアの具体的知識が不可欠
  • 一般的な設計アドバイスは既存システムにはほとんど役立たない
  • 設計議論は個別の詳細や現状コードベースを中心に展開
  • アーキテクト職の抽象的設計は現場で実装困難な場合が多い
  • 新規プロジェクトや全社方針には一般論が有効な場合もあり

大規模ソフトウェア設計と現場エンジニアの役割

  • 大規模システム設計には、日々そのシステムに携わるエンジニアの現場知識が必須
  • 具体的なコードの理解がなければ、有効な設計判断は下せない現実
  • 一般的な設計原則やパターンよりも、現状のコードベースの把握が重要
  • 一貫性の維持が「良い設計」よりも大切なケースが多い
  • 実際のコードベースは複雑で予測困難な影響が多発
  • 安全な変更を行うには、実装選択肢が大幅に制限される傾向
  • 大規模コードベースは常に複数設計の中間状態で存在
  • 理想的な設計目標よりも、変更後の全体像が重視される

一般的なソフトウェア設計アドバイスの限界

  • 一般論の設計アドバイスは、既存システムの現場課題にはほぼ無力
  • **「問題に対する設計」**は、ドメイン理解はあっても既存コードに疎い場合の助言
  • 設計本やブログで語られるのはほぼこのタイプ
  • 現場では具体的要素が一般的要素を圧倒
  • 現状のコード把握こそが最優先事項

具体的な設計議論の実態

  • 有用な設計議論は、システム詳細を深く知る少人数で行われる
  • 議論内容は抽象的原則ではなく、具体的なシステム事情に集中
    • 例:「この新機能をサブシステムAに入れられるか?」「Bの情報がCのコンテキストにないから無理」「Dを書き換えずにEを分割すれば…」など
  • 設計哲学よりも具体的な誤解の指摘が重要
    • 例:「Cは最近リファクタされてBを渡せるようになった」など

一般的設計アドバイスが役立つ場面

  • 新規プロジェクト立ち上げ時は、具体的制約がないため一般論が有効
  • 複数の具体案で迷った時の「タイブレーク」に一般原則が使える
  • 会社全体の方針決定時(例:クラウド利用、k8s導入、AWS vs Azure選択)に有用
    • ただし、この場合も具体的制約を無視すると失敗リスク大
    • 例:クラウドで独自ハード依存不可、自社DCでグローバル展開不可など

アーキテクト職と抽象設計の落とし穴

  • 抽象設計を専門とするアーキテクト職は、現場実装と乖離しやすい
  • 実装担当エンジニアが抽象設計を現実のシステムに落とし込むのは困難
  • アーキテクトは成果の責任を負わず、功績だけ主張しやすい構造
  • 現場で実装可能な設計を考えるエンジニアこそが真の設計者

まとめ・提言

  • 大規模既存コードベースでは、設計議論は具体的・現場的な内容が中心
  • 現場貢献者でないと有用な設計は困難
  • 抽象的なアーキテクト職は、価値提供が限定的
  • 設計者は実装責任も負うべきという主張
  • 現場で苦労する設計者が正当に評価されるべき

ソフトウェア設計の純粋系・非純粋系について

  • 純粋系ソフトウェア工学:単一目的ライブラリや宇宙探査機向けソフトなど、妥協なく設計できる領域
  • 非純粋系ソフトウェア工学:ビジネス要件に応じて妥協や変更が頻繁な領域
  • 両者の違いを理解しないと、設計議論で誤解や衝突が生じやすい
  • AI開発や大企業外部人材の適応失敗もこの違いが一因

参考

  • 記事内容のさらなる詳細や関連投稿は、原文や著者のブログ参照

Hackerたちの意見

著者が「一般的なソフトウェアデザイン」と呼んでいるものは、実装の大まかな方向性を設定するのに役立つよね。だから、ソフトウェア工学の本を読むのが好きなんだ。何かしらの枠組みがあれば、問題を解決するのが楽になるし、みんなが同じ用語を使っていれば、解決策について話しやすい。でも、地図は領域ではないし、道案内をすることと実際に歩くことは同じじゃない。実際の実装は、プロジェクトの初めに描いた計画から逸脱することがある。良い説明は、ノールのプログラミング理論に見られる。彼は、システムの真の知識はそれに取り組んだエンジニアの頭の中にあると言っている。その知識は簡単には移転できないんだ。
> 例えば、大規模なコードベースでは、一貫性が「良いデザイン」よりも重要だ。 でも、これはまさにこの記事が警告している一般的なソフトウェアデザインのアドバイスだよ! その結果、ユーザーが知っていて愛している悪いソフトウェアの慣習が変わらないまま残ることが多い(「一貫して悪い」方が、少なくともいくつかの分野で良いことよりもマシだ!)
その一文にはちょっとイラッとした。でも読み進めると、結局は結果としての一貫性や正確さの方が重要なんだよね。ラルフ・ワルド・エマーソンの言葉を引くと、「愚かな一貫性は小さな心の悪霊であり、小さな政治家や哲学者、神学者に崇拝されるものだ」と言ってるし。
わからないな。うちでは、たくさんのカウボーイエンジニアが自分たちのやり方でやることに決めちゃったんだ。だから、今は誰も好きじゃないランダムな10,000行のReduxコードができちゃった。さらに、95%のコードで使っているクエリライブラリが気に入らないから、他のクエリライブラリをランダムに使っている部分もある。だから、そのコードで作業したいなら、1つじゃなくて2つのライブラリを頭に入れておかなきゃいけない。そう、既存のクエリライブラリは古い。新しいのは確かに良い—孤立しているときはね。でも、両方あるのは悪いものを持つよりもさらに最悪だよ!
さらに、一貫性が良いデザインよりも重要だと言うのは、葉物野菜を食べることが良い食事よりも重要だと言っているようなものだ。
「一貫性を持つ」というのは、非常に広く適用されるルールだと思う。絶対に例外やニュアンスはあるけど、トレードオフを考えると、プログラムを作る人たちは一貫性を深く軽視していると思う。
そう、それは期待のことだよ。一貫して悪いのは、予測可能なソフトウェアで、「良い」部分と「悪い」部分が予測できない形で存在するんだ。
私の読み方もボーイスカウトルールに反してる。つまり、コードベースの一部を改善することができるけど、一貫性がなくなるなら、その改善を避けるべきだということ。これは私が反対する考えだね。「一貫性が「良いデザイン」よりも重要だ」という考えに従うと、海を沸かすようなリファクタリングや書き直しにつながると思う。これは、時間をかけて動作するシステムの反復的なリファクタリングよりも、リスクが高く成功率が低い。
これはソフトウェアの品質だけの話じゃなくて、組織全体のことだよね。安定性があれば、スピードも出せる。安定してれば、開発者は「認証はここ、データベースはあそこ、ABCの扱いはこう」って前提を持てるようになる。期待と違うと、レビューで問題が見えてくる。「あれ、XYZはどこ?」「なんでコンストラクタでデータベースをクエリしてるの?」チーム間のオンボーディングも楽になるし、立ち上がりの時間も短くなる。安定性がないと、いろんな小さな動作の違いが出てきて、組織全体に問題を引き起こすことになる。どのチームも負荷のピークに対応するために余分なスタッフが必要になって、結局多くの開発者が暇になっちゃう。シニア開発者は、どこに問題があるかを正確に予測できない。詳細を知る必要はなくて、どこが難しいかを把握しておけばいい。すべての機能はチーム間の調整が必要で、地元のスタッフが利用可能になるまでキューイングや優先順位付けをしなきゃいけない。最後に、安定性があればバグの種類を一度で修正できる。修正して、みんなを新しいスタイルに移行させるんだ。
最良のシナリオでは、開発者も自分たちが作ったソフトウェアのアクティブなユーザーであるべきだよね。そうすれば、ユーザーに影響を与えるデザインの欠陥やエラーは、開発者にも影響を与えて、(願わくば)それを修正する動機になるはず。
XPで顧客をチームに入れるのが一番良かった点だと思う。ビジネス代表に置き換えるのは、スクラムの元々の罪の一つだね。
> 議論されているトピックは「DRYがWETより良いか?」ではなく、「この新しい振る舞いをサブシステムAに組み込めるか?」という感じだね。無理だ、なぜなら情報Bが必要だけど、それはコンテキストCの中ではそのサブシステムには手に入らないし、サブシステムDを書き直さないとそれを公開できない。でも、サブシステムEをここで分ければ…うーん、なんか聞いたことあるな。ビンゴはみんなの名前を知ってるし、パパイヤとMBSはセッショントークンを生成する。ウィングマンはユーザーが次のステージに進む準備ができてるか確認する。全知の集約者ガラクタスは、宇宙の終わりまでの時間範囲を要求する。EKSは非推奨、オメガスターはまだISOタイムスタンプをサポートしてない。https://www.youtube.com/watch?v=y8OnoxKotPQ
まじで、ISO8601をサポートしてないソフトウェアの数、今日(冗談じゃなく)ひどいよ。例えば、git(互換性があるって言ってるけど、実際はそうじゃない)。
プログラマーにビジネス情報システムを設計させると、こういう状況になるんだよね。システムアナリストにソフトウェアシステムを設計させるべきなのに。
> ソフトウェアプロジェクトのデザインを考えたら、そのプロジェクトの成功や失敗に責任を持つべきだと思う。これは、プロジェクトのソフトウェア開発手法を考えたり選んだりする人にも当てはまるべきだね。スクラムマスターは、リードエンジニアほどの責任感がないと思う。
> 自分が関わってないソフトウェアをデザインすることはできない。30年間ソフトウェア開発をやってきて、デザインやアーキテクチャに対する重要で詳細、一貫した努力を見たことがない。ほとんどのアーキテクトはデザインもアーキテクトもしてない。シニア開発者がデザインしてアーキテクトにフィードバックや承認を求める。これらのシニア開発者は、自分が触れたコードやシステムだけを考慮して機能のデザインをする。平均雇用期間が2年のため、ほとんどの人はシステムの一部しか触れず、それがデザインの深さや正確さに影響する。アーキテクトは大体承認するけど、時々ドキュメントも読まずにやってるんじゃないかと思う。せいぜい、アーキテクトからは一般的なアドバイスや流行りの言葉が飛んでくるだけ。全体的に、彼らは自分の地位に安心していて、あまり気にしてない感じだね。
> 2年、これについてずっと考えてた。2〜3年は長い時間で、50〜100人がメンテナンスしているコードが具体的に何をするのかをかなりよく理解できるし、良い改善アイデアも思いつける。少なくとも1、2個の構造的なアイデアが本番環境に入るのも見ることができる。もしその人がさらに1、2年残れば、さらに洗練するチャンスがあるけど、たいていはピーターの法則に従って昇進する。もし彼らがこれらのアーキテクチャ変更をリードするチャンスがあれば、その会社は技術的に良い道を進む可能性がある。要点には完全に賛成だよ:アーキテクトは通常、より知識のある場所から来るアイデアを整理する中央のスイッチの役割を果たす。彼らの役割は、一貫性を保証し、チーム同士がデザインを妨げないようにすることだと思う。
ジョン・アウスターホウトは、スタンフォードでこのクラスを一つずつ扱ってきて、今では本にまでなったよ。https://www.goodreads.com/en/book/show/39996759-a-philosophy... ビデオの概要はこちら: https://www.youtube.com/watch?v=bmSAYlu0NcY
> 2年で、サブシステムの大部分を書き直すか、全体をクソに変えるのはもう十分だと思う(メンテナがどうかによるけど)。今のソフトウェアはかなり早く進化してる。2年は新しい会社と死にかけの会社の違いになることもある。
ここには二つの極端がある。一つは、この記事が批判している「アーキテクト」。高給取りの専門外の人が役に立たないアドバイスをしてくるのは確かにイライラするよね。一方で、リアルプログラマーは、すでに速い初期化処理を最適化することには喜んで取り組むけど、ビジネスロジックを変えることには躊躇する。最適な面もあるけど、新人(たとえ専門のエンジニアでも)には理解しづらいコードを書くこともある。こういうシステムは詳細が多くて変更が難しいけど、その複雑さは本質的ではない。これは良いエンジニアリングとは言えない。両方の極端を避けることが重要だね。意思決定者は、詳細に対する親密な知識と、それらの詳細を文脈に置くための広い知識の両方が必要だ。
「大規模なコードベースでは、一貫性が「良いデザイン」よりも重要だ」って、これは私の経験とは真逆だ。一つのモジュール内での一貫性には価値があるけど、大規模なコードベースでの一貫性は大きな間違いだと思う(非常に稀なケースを除いて、コードベースが非常に似たモジュールだけで構成されている場合)。異なる要件を持つモジュールは、一つの一貫したコードベースを持つべきではない。テスト戦略、アプリケーションアーキテクチャ、名前付けさえも、異なるモジュール間で異なるべきだ。
ソフトウェアエンジニアは、自分が運転しない車を設計できないよね。今、街中に転がってる何百万トンもの電子廃棄物がその証拠だ。
この記事に同意する個人的なエピソードなんだけど、業界経験がないデザインコンサルタントが来てプロジェクトを台無しにするのを見たことがある。衛星の経験がないVPの友達が、どこにでもランダムな例外を導入する必要があるって言って、Java以外のスレッドや型システムを理解してないのがイライラする。設計レベルで潜在的なバグが導入されるのを見て、最終的な製品の動作に対する配慮が全くないのは本当に腹立たしい。