14 ポイント 投稿者 GN⁺ 2025-06-26 | 1件のコメント | WhatsAppで共有
  • 1982年、AppleのLisaソフトウェアチームはソフトウェアのリリースに向けて、各開発者の週ごとのコード行数を追跡する方針を導入した
  • Bill Atkinsonは、コード行数はソフトウェア生産性の誤った指標だという考えを示した
  • 彼はQuickdrawのリージョン計算エンジンを全面的に書き直し、約2,000行のコードを削減し、性能を6倍向上させた
  • Atkinsonはコード数を報告する管理フォームに**-2000**と記入した
  • 最終的に管理者はBillに、そのフォームの提出をもう求めなくなった

1982年のLisaソフトウェアチームとコード行数追跡方針

  • 1982年初頭、Lisaソフトウェアチームは今後6か月以内のソフトウェアリリースを目標に集中的な取り組みを開始した
  • 一部の管理者は、各エンジニアが毎週書いたコード行数を追跡することが進捗に役立つと判断した
  • そのため、毎週金曜日にエンジニアが書いたコード行数を記録して提出するフォームを導入した

Bill Atkinsonの生産性指標に対する見解

  • Quickdrawとユーザーインターフェースを設計したBill Atkinsonは、コード行数がソフトウェア生産性の基準にはなりえないと考えていた
  • 彼は、プログラムをできるだけ小さく、速くすることが目標だと強調した
  • コード行数の計測は、かえって雑で非効率なコードを助長しかねないという問題意識があった

Quickdrawリージョンエンジンのリファクタリングと最適化

  • Atkinsonは最近、Quickdrawのリージョン計算エンジンをより単純で汎用的なアルゴリズムで全面的に書き直した
  • 最適化の結果、リージョン演算の速度を最大6倍まで向上させた
  • この過程で、2,000行に相当するコードも自然に削減された

-2000行のコード報告と管理者の反応

  • 最初の週の管理フォームを記入していた際、Atkinsonはコード行数の欄に**-2000**と書いた
  • 管理者たちがこの数字にどう反応したのかは明確ではない
  • 数週間後、Billはもうフォームを提出しなくてよいと言われ、それを喜んで受け入れた

1件のコメント

 
GN⁺ 2025-06-26
Hacker Newsの意見
  • 私が最高のコミットとして覚えているのは、約6万行のコードを削除し、すべての状態をメモリに保存していた「サーバー」全体を、軽量な約5,000行のロジックに置き換えた経験

    • このコードは他のサービスに自然に統合できるほど十分に軽く、メモリ状態も不要だったという点で、アルゴリズム上の快挙だと思う
    • 特定のツリーを対象とする guided subgraph isomorphism 問題を解けると気づき、そのおかげで一般的な有向二重グラフを一度だけ走査しながら、出発したルートからの経路だけを少量のスタックで追跡して出力グラフ(ツリー)を作れた経緯
    • 「-60,000行コミット」は本当に忘れられない瞬間で、それ以降これほどアルゴリズム的に印象的な仕事はしていないという少し惜しい感想
      • 私は仕事ではスクリプトを多く書き、プログラミングのいくつかの部分には慣れていると感じる趣味プログラマだが、こういう話を聞くたびに自分の知らない世界は本当に広く、一生学んでも足りないのだと改めて謙虚になる
      • もっと多くの文脈を聞きたい。状態を持っていたプログラムをステートレスに変える技術が魔法のように感じられて、ぜひ学んでみたいという好奇心
      • 私はグラフ理論とアルゴリズムに背景のある数学者だが、こういう種類の実務に自分の技術が応用できるのか気になる。もしもっと詳しい内容を共有してもらえるなら、ぜひ具体的に聞きたい
      • 目標グラフがツリーであることはあまり重要ではないように思う。実際には「guided」の部分こそが単一走査を可能にしたポイントだと思う
        • 元のグラフで特定のノードから始め、同型が存在するなら対象ツリーのルートも必ずそのノードに一致すると仮定する
        • 元のグラフを対象ツリーのパターンに従って走査し、不一致なら false、すべて一致すれば true と解釈する問題。ツリーでなくても開始点を明確に指定すれば、この方式はどんな部分グラフにも適用できるという推論
      • 最近の「二分木を反転しろ」みたいなコーディング面接問題の元祖は、まさにこういうタイプのプログラマなのかもしれないというジョーク
        • グラフ理論には興味があるが用語が難しい、という普通の開発者向けにやさしい説明を求める声
  • 大学時代、新入社員でも良いコードを書けるという経営方針の会社で働いたが、結局それは証明されなかった失敗例だった

    • コード内でバグを直しても同じバグが出続けるので分析してみたところ、既存の関数にパラメータを追加せずコピーを作って少しずつだけ修正することの繰り返しだった。その結果、コードベースの3/4以上、数千行の Turbo Pascal を削除した経験
    • プロジェクトの顧客は Energy 部門で、核物質在庫を管理するプログラムだったので、不眠の夜を過ごした記憶がある
      • 既存コードをコピーする利点としては、既存コードの安定性を損なわず、管理者の「貢献度」メトリクスまで満たせるという皮肉な指摘。revert もコピーを消すだけで済むという冗談
      • 私たちのチームにもこういうコード重複をよくやる同僚がいるが、急ぎの要求や声の大きい人たちのために素早く結果を出す習慣なのだと思う。本当は共有関数へのリファクタリングと十分なテストが必要なのに、そこへ時間を投資したくないという根本問題が原因
      • 以前私が担当していた外部委託の開発者たちも似た癖があり、混乱が起きうると指摘したら「そういうときは Ctrl+F を使えばいいですよ」と返された経験
      • その事例はもしかして Blacksburg 地域で起きた話なのか、という興味
      • 私の経験も似ていて、東南アジアの複数の国でほぼ同じポータルを運営する会社に勤めていた。それぞれのポータルのソースが別々の Git リポジトリに保存されており、すべてのポータルに共通で適用すべき機能やバグ修正を、複数のソースコードのコピーへ一つずつ手作業でバックポートしなければならなかったという困惑した経験
        • 「単一リポジトリに全部入れて、機能フラグでポータルごとのカスタマイズはできないのか」と聞いたが、無理だと拒否された
        • 結局2〜3か月で4〜5個のポータルのコードを1つのリポジトリに統合し、機能フラグとフレームワークのアップグレードを適用して、デプロイもスムーズに完了。今ではすべてのポータルに同時にバグ修正を入れられるようになり、繰り返される手作業の苦痛から解放された
  • 関連トピックとして、「-2000行のコード」を扱った Hacker News の人気スレッドを リンク のようにまとめてある

    • 定期的に過去の名作投稿が repost されるのは、新規ユーザーにも既存ユーザーにも有益な伝統だと指摘
      • 私は「-2k lines of code」なら自動的に vote する単純な人間だと自称
        • 生産性の測定基準を単一軸のメトリクスで管理しようとするクライアントには、Atkinson の事例をよく話す。本当の生産性指標は utility 基準であるべきで、それを本当に定量化できるならノーベル経済学賞候補になれると思う
  • 私が担当した Web UI プロジェクトは25万行のコードがあり、バックエンドは含まない数字だった

    • 前任の開発者は頭は良かったが JS は初めてで、すべての状態を DOM のカスタム属性に保存し、addEventListener だらけの構造だった。私は「修道士に JavaScript の本1冊と独房での10年を与えたら、こういうコードが出てくるだろう」と冗談を言うほどだった
    • 数か月かけて Web Components へ構造を変換しながら5万行を削除し、全面書き直しに着手して、現在は同等機能の80%程度までしか到達していないが、全体のコードは軽量な1万7,000行ほどになった(Vue/pinia などのライブラリは除く)
    • まもなく20万行以上を削除することになる予定で、これ以上の経験は今後もうないだろうから、引退したくなるほどだ
      • 私にも似た経験があり、原作者はほぼジュニア同然の実力だったが、会社の創業者で生産性だけは非常に高かった人だった。チーム作業や他人のコードとの協業経験なしに開発していたため、想像できるあらゆるコードスメルが詰め込まれた構造だった
        • 1つの関数が数千行、switch/case/if/else/三項演算子が10段階で入れ子、SQL と JS/HTML/JS埋め込み HTML が混在し、自動テストは皆無だった PHP/Dojo 時代のフロントエンド構造という説明
      • 「80%の機能しか実装されていない軽量コード」という説明そのものが、この比較の盲点を示しているという指摘。全機能の一部しか実装されていないなら、元のコードと同じだけ多くの行数を必要としないのは当然だということ
  • Dilbert の漫画に、無限報酬構造を描いた一コマがあり、ディルバートの上司がバグ1件を直せば金銭報酬を約束すると、Wally が「今日は俺もミニバン1台分はコーディングしないとな!」と言い放つ

    • こういう状況は「Perverse incentive(逆インセンティブ)」と呼ばれ、参考リンク で説明されている
    • 私のマネージャーもこの漫画( 画像 )を休憩室の壁に貼っていた
    • 「ミニバン」とはどういう意味なのか、という現実的な疑問も出てくる
  • dotnet/runtime リポジトリで6万4,000行を削除した実例を共有

    • 従来の C# + WinRT interop サポートをビルトインからソース生成ツールへ置き換えた、思い切った一括変更が必要だった構造変更。 PRリンク 参照
  • LLM が開発者の生産性をどれだけ高めたかという統計を見るたびに、この古典的な話を思い出す

    • AI はコードを削除するのにもかなり向いているという反論とともに、Cursor 関連の コミュニティ で「AI が全部消した」という面白い事例が共有されている
    • 最近では「新規コードの X% を AI が書いています!」が業界のお決まりのキャッチフレーズだという言及
    • 新しい原子力発電所の建設と維持コストまで含めるなら、開発者生産性の数値がどれほど非現実的に誇張されているかがわかる、という皮肉
  • 私は CS 専攻ではなく、仕事をしながら実地で身につけた知識で働いている立場

    • 私たちのプロジェクトの目標は、ライブオブジェクトを人が読みやすい形に再構成すること
      • 最終的な表現は非常に複雑な複数の型を必要とし、初期表現は比較的単純
      • 似たデータノードがある場合、それらを比較して結合し、つまりメソッドに抽出してパラメータを見つけるような処理によって可読性を改善する必要があった
        • 初期には最終型へ先に変換してから比較していたため、型の組み合わせが爆発的に増えて管理がほぼ不可能になり、何年ものあいだエンジニアたちが構造を理解できないほどの複雑性に達していた
      • その後 hashmap ベースのアプローチを知り、同じ骨格を持つノードをハッシュ値で区別して比較・結合し、その後で最終型に変換する2段階構造を適用した
      • 型の状況ではなくデータ中心の抽象化へ切り替えたおかげで、妙なクラス階層も単純な属性として容易に扱えるようになった
      • 要するに、間の抜けた多段デコンパイラ構造ではあるが、処理速度と可読性が大きく改善した経験。状況に応じて万能の銀の弾丸はないが、私たちにとっては「型」が核心問題であり、この解決法が大いに役立ったプロジェクトだった
  • 年末評価を前に、社内モノリシックリポジトリでの自分の統計を見たら、コード純増ではなく純減の人間になっていることに気づいた

    • API コードや型の自動生成コードの削除、旧バージョン API の廃止などが理由だったが、毎日出社してコード削除だけしている気分が妙に愉快だった経験
  • 昔、大規模プロジェクトで PL たちが開発者ごとのバグ件数(直したバグ、作り込んだバグ)をオフラインで手書きし、壁に貼り出していた悲惨な KPI 事例に衝撃を受けた

    • 私は関連プロジェクトだったので巻き込まれなかったが、ある同僚は「デンマーク国旗から十字部分だけを切り取り、赤い共産国旗のような配置に縫い直して返した」ことで官僚的な『作家リスト』から追放された Lars von Trier 監督の逸話に着想を得て、自分のバグ件数の行を切り取って貼り直し、公然と反発した。翌日、その一覧は二度と姿を現さず、私にとっては大切な思い出になっている
      • 「私はこのリストに載りたくないんですからね!」という同僚の単純で率直な返答が、この状況全体をよく要約している
      • 国旗とリストをどう視覚化したのか想像しにくい、という実際的な難しさも共有されている