- コードとして見える成果物は、その日の作業全体ではなく、読解・調査・デバッグ・検証・判断の末に残る純粋な結果物に近い
- 長年にわたりプログラマーたちに投げかけてきた非公式な質問では、6時間分の変更を diff だけ見て再入力するのに最も多かった答えは約30分だった
- この比率は科学的研究ではなく、アンケートと diff の観察に基づくものだが、プログラミングを1/12が動作、11/12が思考と見る実用的な基準になる
- ソフトウェア開発は工場的な製造よりも設計作業に近く、最初の設計後の複製は機械がほぼ 0 に近い限界費用で行う
- 管理やプロセスがタイピング時間を増やす方向に最適化されると見当違いな効果を生み、思考の質を高める環境と協業のやり方のほうが重要である
6時間の作業を再入力するのにかかる時間
- 前提は、会議や割り込みがほとんどない良い日に、プログラマーが6時間の真剣なプログラミングをしたという状況である
- 退勤前に diff を出力していたが、夜のうちにバージョン管理システムが壊れ、前日のバックアップに復旧されたことでその日の作業が消えてしまう
- 質問の核心は、diff を渡されたプログラマーが、その6時間の作業をコードベースに再入力するのにどれくらいかかるかという点である
- 長年にわたり、カンファレンス、顧客先、同僚、初対面のプログラマーにこの質問を投げかけてきたが、最も多かった答えは約30分だった
- 6時間には30分が12回入るため、この観察はプログラミングが1/12が動作、11/12が思考だという表現につながる
比率の性格と限界
- この数値は厳密な科学研究から出たものではなく、良い記録を残した公式調査でもない
- 目的はプログラミング活動の統計的・数学的法則を見つけることではなく、合理的な質問に対する合理的な答えを見つけることにあった
- どの会社も、1日の作業全体を実際に削除してこの仮説を証明または反証しようとはしなかったため、根拠は推定と日々の diff 観察にとどまっている
- 多くの changelog と diff を見た結果、良い日の純粋な変更量はおおむね30分 ± 10分程度に見えた
タイピングはボトルネックではない
- 「タイピングはボトルネックではない」という言葉は、ずっと以前からステッカーやソーシャルメディアで繰り返されてきた
- 一部のプログラマーにとってはタイピング自体がボトルネックになりうるが、速いコード生産の核心は通常、タイピング速度やツール習熟だけではない
- Quora の「How do programmers code so quickly?」という長文で、ある回答者は筋肉記憶、ツール習熟、デバッグ能力、タイピング能力、情報検索能力に言及していた
- しかし、速いコード生産においてタイピングとツールは補助手段に近く、何をすべきかを判断する時間のほうがより大きな比重を占める
ソフトウェア工場と設計作業の違い
- 物理的な製品生産では、目に見える作業の大半は動きであり、鉄を転がし、打ち抜き、押し、フライス加工し、配置し、組み立てる行為が作業のように見える
- 現代の工場は CNC 機械のように、抽象モデル、つまりデータに基づいて正確な動きを行い、人間は機械を直接手作業する代わりに管理する
- ソフトウェア側の工場はすでに完成しており、利用者は「copy」や「download」ボタンを押してbit-perfect copyを得る
- 最初のモデルが存在すれば、その後の複製の限界費用は事実上 0 に近く、ソフトウェアは知的財である
- Uncle Bob Martin は、ソフトウェア開発は製造作業ではなく設計作業であり、最初の設計後の複製は機械がほぼ 0 コストで行うと語ってきた
- プログラマー、テスター、PO、Scrum Master、ソフトウェア管理者は、顧客やコミュニティが使う複製物の基盤となるデータモデルを設計している
知的作業は観察しにくい
- 産業時代的な発想は、ソフトウェア開発を工場のように見ようとし、開発者は実際のプロセスに害があっても物理労働のように見せるよう圧力を受ける
- 知的活動は観察と測定が難しく、80%完成したアイデアには物理的な形がない
- 実験、proof-of-concept コード、メモはありうるが、物理的作業のように正確な完了率を示すことはできない
- 製造中の椅子は50%地点でおおよそ50%完成しているように見え、完成すれば完成品のように見える
- 椅子の設計は70%以上進むまで紙の上に存在しないこともあり、設計が終わる前には本当に70%完了なのかも分かりにくい
30分の変更が6時間の仕事を意味する理由
- 30分というのは、その日ずっと書いては消し、編集し、作り直したコードの純粋な結果物を再現する時間であって、投入された努力の総量ではない
- プログラマーは欠陥やセキュリティ脆弱性を避けるため、コードを書いている間ずっと評価し、仮説を立てている
- コードのテキストには、実行時にプログラムが何をすべきかしか入っておらず、なぜその方法を選んだのか、システムの他の部分にどんな影響を与えるのか、どんな誤りを入れて後で取り除いたのかは、たいてい残らない
- 実際の作業の大半は変更そのものではなく、どう変更するかを決めることにあり、既存コードを理解する必要があるため、汚れたコードや設計が表に出ていないソースではより時間がかかる
- プログラマーの成果物は共有コードベースに統合されるため社会的文脈を持ち、他のプログラマー・テスター・運用担当者が作業を理解できるよう助けることも、コードには現れないコストと利益を生む
コード行数は進捗の尺度ではない
- 6時間の知的作業は、読解、調査、判断、確認、検証、レビューを経て、コードベースの30分分の純粋な変更に変わりうる
- これは追加されたコード行数を意味するものではなく、バグ修正と機能追加をしたのに、週末のコード行数が週初より減っている場合もある
- チームの上位管理者が SLOC を進捗指標のように報告していることを知らないまま、何週間も負のコード行数を記録して問題になったことがあった
- プログラマーが実際にしていることは、読解、学習、理解、推測、調査、デバッグ、テスト、コンパイル、実行、仮説の設定と反証に近い
- 多くの作業は結局、考えて決めることとして残る
少なく書くことが速い開発かもしれない
- Quora の回答のひとつでは、キーボードの上で指が動く様子は見えるが、ユーザーと話し、同僚と問題を議論し、調査し、考える時間は見えないと述べていた
- 別の回答者は、顧客が「requirements」や「must have」と呼ぶ不要な考えを取り除くのを助けることが、解決策の提供を最も大きく加速させると述べていた
- さらに別の回答者は、優れた開発者はキーボードに触れる前に要求を理解し、適切な解法を構想することで作業の90%以上を行っていると述べていた
- 何を書かないかを知ること、より少なくやること、より小さなステップで進めること、最初に何をするかを把握することが、繰り返し現れる答えだった
- より多くタイピングしたり、より多くコピー&ペーストしたりする人は、思考や理解が不足しているかもしれず、その結果として誤りや、他のプログラマーが理解・修正する負担を増やす可能性がある
プロセスは思考のために設計されるべきだ
- プログラミングが1/12の動作と11/12の思考なのだとすれば、人々に時間の11/12のあいだタイピングするよう圧力をかけるべきではない
- 必要なのは、思考の質を高める材料、環境、プロセスである
- 逆をすると、システムを間違った効果に合わせて最適化してしまう
- ソフトウェアについて一緒に考え、判断をより簡単に下せるようにシステムを意図的に作るとき、生産性は高まりうる
- 業務の中で学習を実験しながら、思考が最適化されるシステムをどう作るかを考えるべきである
1件のコメント
Hacker News のコメント
記事中の「本当に優れた開発者は、キーボードに触れる前に作業の90%以上を終えている」という言葉は、ときには正しいが、人が頭の中に多くの制約や概念を同時に保持できないという事実を見落としていると思う
何も書かずに純粋に考えるだけで扱える範囲は非常に限られているので、可能なアプローチが一つでも思い浮かんだら、完全に仕様化された設計へ磨き込む前に、ほぼすぐキーボードに向かうことが多い
実際にコードを書いて複数のアプローチを試してみると、最初に最高だと思った解法が、あまり有望でなさそうに見えた解法よりはるかに悪いことがよくあり、動く具体的なコードほど問題をよく浮き彫りにするものはない
結局、コーディングはアイデアをコードとして具現化して検証するプロセスであり、最初のイテレーションは捨てるというプロトタイピングの観点と同じく、コードを書くことも思考プロセスの一部と見るべきだ
伝説のように、Git について1か月ほど考えたあと6日で完成させ、7日目に休んだ、というような話だが、普通の人、とくに私の場合は、何を書くかを考え、書き、テストし、また考え、一部を直す、という相互作用に近い
結局、最終的に動くバージョンへ到達する過程は、ある程度芸術に近い
大まかなアイデアをつかんだら、問題が起きる可能性が最も高そうな「粘っこい」部分からコードを書き始める
すべての問題を事前に予想することはできないので、実際にぶつかってみる必要があり、このやり方では多くの作業を捨てることになりがちだ
正しい方向に進んでいるという確信が持てるまでは、ほとんどドキュメントを書かない[0]。そうすることで、私が Concrete Galoshes[1] と呼ぶ状態を減らせるからだ
[0] https://littlegreenviper.com/miscellany/evolutionary-design-...
[1] https://littlegreenviper.com/miscellany/concrete-galoshes/
それを身につける唯一の方法は、多くの実践的なコーディングと能動的な学習であり、同じ技術スタックを繰り返し使い続けるという意味でもある
同じスタックにとどまって問題そのものに集中するやり方は好ましいが、ここで言う「優れた開発者」は、ツール選びという面ではかなり一次元的である可能性が高い
年齢を重ねるほど、ミクロな判断よりアーキテクチャが重要だという点があまりにも明らかになる
ミクロなものは最適化できるが、マクロな判断はたいてい恒久的だ
テストの中でコードを設計し、実装をある程度導かせることが多い
頭の中で最終結果を想像したうえで、システムにとって良い API だと思える形でテストを書き、そこから出発する
結果としてコードは基本的にテスト可能になり、Red → Green → Refactor を何度も回しながら満足できる状態に到達する
ほかの人もこのように作業しているのか気になる
Jonathan E. Steinhart の本『The Secret Life of Programs』に出てくる説明がいちばん良かった
コンピュータプログラミングは2段階だという内容だ: 1. 宇宙を理解する 2. 3歳児に説明する
自分が理解していないことをするプログラムは書けず、綴りの規則を知らなければスペルチェッカーは作れず、物理を知らなければ優れたアクションビデオゲームを作るのは難しい、という意味だ
良いプログラマーになるには、ほかのあらゆることについて可能な限り多く学ばなければならず、問題の解法は予想外の場所から出てくることが多いので、今すぐ関係なさそうに見えるからといって無視してはいけない
2番目の段階は、3歳児のように世界を非常に厳密に見る機械に、自分の知っていることを説明する作業だ
子どもに「靴はどこ?」と聞くと「あそこ」と答えることがある。質問には答えているが、実は靴を履いて出かけようという意図を推論できていないのだ
子どもは成長するにつれて柔軟性と推論能力を学ぶが、コンピュータは Peter Pan のように決して成長しない
人や問題ごとに合う思考様式は異なり、複数の方法で考え、プログラミングする術を学べば、選べる道具が増える
だから、プログラミングは必ず一つの正しい方法で行われるべきだ、という類の主張は好きではない
「自分が理解していないものをプログラムとして書くことはできない」という言葉も真実ではなく、何かが実際にどう動くのかを理解するためにソフトウェアを書くことは多い
物理モデリングも、現実への完全な忠実さが目標なのではなく、ゲームのユーザー体験と難易度のバランスを探る探索であることが多い
プログラミングは探索的な認知ツールになり得るのであって、思考の大部分が常に先に来なければならないという意味ではない
ジェネラリストや独学者は好きだが、それは良いプログラマーになるための必須の第一段階ではない
子どもたちが「厳密な世界観」を持っているというより、社会的な含意を常に推論できるわけではないのであり、コンピュータも既知の事実から論理的な結論を導くようにプログラムできる
さまざまな年齢の子どもたち、3歳児にも何かを説明したことがあるが、その経験はコンピュータプログラミングとはまったく似ていなかった
この数値は実質的に正しいとかなり確信しているが、まだどの会社も、この実験を証明または反証するために1日分の作業を丸ごと消すことには同意していない
以前、今よりずっと忍耐強かった頃、毎晩すべてのコード変更を確認し、気に入らないものは削除する上司がいた
その上司はバージョン管理は過度に複雑だと信じていて、自宅のネットワークドライブにリモート接続する方式を会社標準にしようとしていた
そのため、翌日出社すると前日の作業が消えていることがときどきあり、結局こっそりSVNをインストールするまでは、前日の作業を作り直すのが非常に上手くなった
エッジケースのテストまで含めても、1時間以上かかることはめったになかった
最初の職場で一種のトラウマができたので、2社目ではすぐにGitリポジトリはあるかと聞いたところ、上司はGitをGitHubと同じものだと思っていて、コードを公開したくないと答えた
その後、より大きな会社に買収されてイントラネットへのアクセス権を得て、その中でGitLabインスタンスを見つけ、ほぼ一人で作業していた自分のコードをそこでバージョン管理し、ドキュメント化し、GitLab Runnerまでインストールした
コードの実行方法も手順ごとに文書化しておき、解雇されるときにコードを引き渡せと言われたので、全部見せて再現方法を教えたところ、上司はかなり感心して感謝していた
ひどい職場で、自分が正しいと思ったやり方を押し通したおかげで、少しは良い影響を残せたのかもしれない
そのGitLabを見つける前は、ネットワーク共有にベアGitリポジトリを作って、そこへpushしていた
善意であっても、管理者がコードやレビューに関与すると、ほぼ常にチームにとって純損失になる
非プログラマーに送るのに良い記事だ
プログラマーにドメイン知識が必要であるのと同じように、プログラマーから何かを引き出そうとする人も、プログラミングを少しは理解している必要がある
ごく小さなdiffでも、デバッグ、設計、学習のために何時間もかかることがある
成果物の量だけを見て感銘を受けないのは簡単だが、誰かに説明を聞くことと、自分で何時間も壁に頭を打ちつけながら突き止めることはまったく違う
性能を100倍改善する1行コミットを見つけるのに何日もかかり、その一方で同期ミーティングでは、なぜチケットが動いていないのかを説明しなければならない、という具合だ
だからこそドメイン知識が核心だ
金融分野で働き、トレーディングデスクに座って複数の取引所を見ながら、さまざまな戦略を実装するコードを書いてきた
ビジネスが何をすべきかを知らなければ、コンピュータが何をすべきかも考えられない
この観点では、コーダーを翻訳者のように訓練することは理にかなっている
私の翻訳者の友人は、複数の言語の文法や慣用句に詳しく、新しい言語も私たちが新しいプログラミング言語を学ぶように身につけるが、製薬業界についてもかなりの時間をかけて学び、今では医療文書を翻訳している
弁護士や会計士も、言語の壁がある職業だ
専門家になれば、法律、会計、ソフトウェアの言語を学ぶが、優れた専門家は専門用語ではなくビジネスの言葉で答える
あまり優秀でない弁護士は、法律用語で起こり得るすべての結果を伝え、判断は任せるが、優れた弁護士は、細かな可能性はいろいろあっても、実務上同じ立場の顧客はこのビジネス目標のために皆Xをしている、と言ってくれる
最初のトレーディングの職場では、あるトレーダーがExcel VBAモジュールを作り、銘柄をざっと調べて取引対象を見つける手順を実行していた
バージョン管理なしでディスクに保存されたファイルだけだったが、新しく来た人が数週間もしないうちにそのVBAモジュール全体を消した状態で保存してしまい、バックアップもITの助けもなかった
そのトレーダーは顔を赤くしたあと落ち着き、そもそもバックアップがあるべきだったし、VBAで何をやっていたのかという現実を受け入れて座り、80年代の端末画面に1文字ずつ表示されるように、全体を再びタイプし直した
良い解決策を作るには、まずそのドメインでの経験が必要だ、というのが私の信条だ
今は新しいドメイン経験を得るためにほとんどの時間を使っており、必要な知識を素早く身につけるためにドメイン専門家の隣に座っている
私のような背景を持つ人よりも、会計関連ソフトウェアを15年作ってきたソフトウェアエンジニアを好み、その人を会計士と30分会話させる方を選ぶ
プログラミングは必ず何らかの一つの方式で機能すべきだという処方箋が繰り返し見られるが、下位分野ごとに作業の種類は大きく異なる
すべての分野に適用できる完璧な単一の方法論を学んだり教えたりしようとするより、複数のアプローチや方法論を収めた道具箱と、それぞれがうまく合う状況を理解する方がよいと思う
そのため、業界をまたいで移転可能な一般的なプログラミングスキルに集中することになる
Bjarne の PPP 本[0]の序盤にも似たことが書かれている
「最高のプログラマーでさえ、というより特に最高のプログラマーは、時間の大半をコードを書くことではなく問題を理解することに費やす。問題の理解には真剣な時間がかかり、かなりの知的努力を要する場合が多い。多くのプログラマーがプログラミングは面白いと言うときに指している知的挑戦とは、まさにそれだ」という趣旨
最近トップページに載っていた[2]新版[1]も買った
[0]: https://www.stroustrup.com/PPP2e_Ch01.pdf
[1]: https://www.stroustrup.com/programming.html
[2]: https://news.ycombinator.com/item?id=40086779
どのデータベースを使うか、どの言語が最高か、コードとデータベースで null を許すか、API の形式、ログ形式といったこと
特に面白いわけでもなく、たまには再検討する必要はあるが、最近の3社で経験したこうした時間の浪費は、ほとんどがすでに解決済みであるべき問題のように感じた
実際、会社が強い考え方を持っていれば、たとえ疑わしくてもはるかに生産的になり得る
Perl、MongoDB、CGI を使うと決まっていたなら、そのスタックにもかかわらず、最近より生産的だったように思う
「プログラミングはほとんど思考だ」は、深い真理のように自分に言い聞かせる文の一つだが、観察としてはあまり生産的ではない
プログラミングが思考であるという点は、あらゆる知識労働が思考であるのとまったく同じ意味でしかない
デザインもほとんど思考で、会計もほとんど思考であり、管理も概ね思考
意味のある違いは思考そのものではなく、何について考えるかにある
マネージャーは人の問題をデバッグしなければならないので、人々と多くの時間、つまり会議が必要になる
開発者はコンピュータの問題をデバッグするので、コンピュータと過ごす多くの時間が必要になる
ここには明らかな緊張関係があり、どちらの極端もうまくいかないので、互いの仕事をあまり邪魔しないようにバランスを見つける必要がある
難解なコードゴルフ的なコードのことではなく、作ったものはすべて保守しなければならないという側面のこと
保守にはあまり関心がなく、テキストが生み出す感情をより気にする小説家とは明らかに違う
「職務中の学習を実験し、思考が最適化されるシステムを作るには?」に対する最高の最適化は、割り込みを減らすこと
研究によれば、割り込みはプログラミングに破壊的な影響を与える
割り込み後に仕事を再開するには10〜15分かかり、プログラマーが1日に得られる割り込みのない2時間のセッションはおそらく1つだけで、編集・検索・理解をしているときが割り込むのに最悪のタイミング
こうした割り込みを追跡して見える化する方法があるのか気になる
[0] http://blog.ninlabs.com/2013/01/programmer-interrupted/
ところが開発者は、終わりのない会議、Slack/Zoom の短い通知や同期の合間に、数時間規模のコーディング作業を終えることを期待される
たまに週末に家で仕事をしなければならなかったとき、割り込みのない週末の作業品質が、慌ただしい平日よりはるかに良いことを実感した
誰にでも合うわけでも、あらゆる場合に合うわけでもなく、残りの20%は日中に働く人たちとの調整だが、何時間も続く良い無割り込みセッションから得られる生産性は比較にならない
繰り返すが、誰にでも、おそらく大多数に合うやり方ではない
家では誰も邪魔しないし、割り込みが来てもいつ反応するかを自分で決められる
特に難しい問題に取り組んでいるときに10〜20分ごとに割り込まれるなら、もうやめた方がよく、そうでなければ後で頭痛の種になるひどいコードを作る可能性が高い
プライバシーを尊重するよう設計し、Web ブラウザーを使ったという事実は記録するが、それが社内イントラネットなのか fb.com なのかといった具体的な URL は記録しなかった
時々ポップアップでユーザー自身に生産性を評価してもらい、自由記述でコメントを残せるようにし、人々が超人のように見せようとして嘘をつかないようユーザー ID とは結び付けなかった
Windows フロントエンドと Scala バックエンドを作り、開発者、弁護士、財務担当者を含むボランティアグループに配布したが、最初のデータ分析の後、面白くなり始めたところで時間と予算が尽き、論文にはできなかった
Rescue Time( https://www.rescuetime.com/
) のような既存ツールも見たが、内部の生産性データを外部クラウドに保存するのは受け入れられないと判断した
良いプログラミングは時にほとんど思考だが、「どんな計画も敵との最初の接触後には生き残れない」という言葉は正しい
実践的なプログラミングは、計画と IDE にコードを載せて試すことの慎重な組み合わせであり、そのバランスはユースケースに合わせて変わるべき
何日もコードを書かないなら、問題空間を完全に把握しているか、単に推測しているだけ
後者なら、考えることはそれほど多くない
2回目はもっと速くなる
思考を「ツールの助けを借りた思考」へ拡張できる、という点には同意する
Peter Naur の Programming as Theory Building を繰り返した表現であり、私がプログラミングの本質を理解するうえで決定的だった
プログラミングとはプログラムそのものを作り出す作業ではなく、世の中の事柄に対する特定の洞察を形成することであり、最終的に出力されるコードは、自分が構築した理論の単なる表現にすぎない