Mukai Systems

Ghost of Tsushimaの成功の秘訣に迫る——「ルールズ・オブ・プログラミング」

Description

本書は、大ヒットゲームGhost of Tsushimaを開発したことなどで知られるゲームデベロッパーのSucker Punchが、現場で用いているプログラミングのルールをまとめたものだ。著者によると、これらのルールが自社の成功要因なのだという。

ルールは21からなる。

ルール1:できるだけ単純であるべきだが、単純化してはいけない

最も優れたコードとは、最も単純なコードのことだ。

-- P2

本書は、コードの単純さにもっとも重きをおいている。この哲学は本書の全体にわたって繰り返し主張される。

ルール2:バグは伝染する

バグは放置しないで早めに直しましょうねと。

いわゆる割れ窓理論だ。

自動テストについて少し否定的なスタンスを明示しているのが興味深かった。Sucker Punchで扱うプログラムは、自動テストで扱いにくい事象——特定のイベントでコントローラーは振動するか、非可逆圧縮な音声コーデック復号がどれくらいうまくいっているか。——が多いからだという。

ルール3:優れた名前こそ最高のドキュメントである

コードは書く時間よりも読む時間の方が圧倒的に長いのだから読みやすいようにコードを書きましょうねと。

そりゃそうですね。

ルール4:一般化には3つの例が必要

似たような処理が二回現れたら一般化を検討するプログラマーは多いかもしれないけれど、一般化はもう少し後に検討しなさいと。Knuth先生の早すぎる最適化に関する格言はよく聞くが、早すぎる一般化についてはやや斬新な印象。

異論もありそうだけど、個人的には本書の具体例のような誤った一般化を沢山見てきたので同意。

ルール5:最適化に関する教訓その1は、「最適化するな」

「最適化するな」というのは少々過激に聞こえるけれど、「本当に必要なときのみ最適化しなさい。」という意図だと思う。

200万行からなるGhost of Tsushimaで最適化が必要だったのは20~30箇所だけだった。という事実はかなり説得力があった。なぜなら、彼らの多くのプログラムは、フレームレート内(つまり、1/60秒)に収めなければならないという強い制約があるからだ。

ルール6:コードレビューが役に立つ3つの理由

まぁ、そうだよね。要点は次のとおり。

  • バグを見つけられる。
  • 誰もがコードの理解を深められる。
  • 人に進んで見せたくなるようなコードをみんなが書く。

-- P109

ルール7:失敗が起こる場合をなくす

安全な呼び出しを後押しするようなAPIを設計しましょうねと。これは名言。

そして、チームにいる他のプログラマーに対し、ある機能を公開したら、やつらはその機能を間違った使い方で使う。必ずだ。

-- P111

具体例として、initializefinalizeが呼び出し側の責任となっているようなAPIが挙げられていたが、ある程度経験を積んだプログラマーならこのようなAPIで痛い目を見たことがあるはずだ。

他にも大量のパラメータを持つ関数などについても言及していた。

ルール8:実行されていないコードは動作しない

デッドコードを再び利用する場合は動作しないと仮定すべきだし、そもそもデッドコードは削除しなさいねと。

「敵と味方を判別する」というコードを例に、段階的な仕様変更(敵の服を着ている場合には敵から敵と見做されないようにするとか)を経て、過去に正しかったデットコードが、誤って使用されるという具体例が秀逸だった。

デッドコードをそのままにしておくのは論外かもしれないが、過去のバージョンからコードを参考にするような場合にもこの議論は当てはまることに注意。

ルール9:集約可能なコードを書け

読みやすいコードにするためには、適切な変数名をつけることによって認知的負荷をさげたり、関数を定義して抽象化をしたり、共通知を用いて長期記憶の利用を促したりしましょうね。という話。

平均的な人間は短期記憶に保持できる情報は7±2であるという、マジカルナンバー7という理論がある。したがって、読みやすいコードは短期記録を消耗しないようなコードでなければならないというわけ。

プログラマー脳でもそんなことが主張されていた気がする。

https://www.amazon.co.jp/dp/4798068535

ルール10:複雑性を局所化せよ

タイトルのまま。

複数人からなるステルスゲームで、自分が他人から見られているか判定するというプログラムを例に、段階的な仕様変更(自分が盲目状態の場合や、天候が霧の場合の特殊処理)によって単純だったコード全体が複雑になっていく。この状態から複雑さをどうやって局所化できるのかという具体例がよかった。

ルール11:2倍良くなるか?

プログラムを扱っていると、最適ではないものの小さな変更で済む場合と、最適ではあるものの大きな変更が必要な場合のどちらか一方を選択しなければならない場面に遭遇することがある。このようなとき、2倍よくなるなら大きな変更を、そうでなければ小さな変更を行うようにしましょうねと。

「どちらか一方の戦略のみ好んで選択する人がいるが、問題ごとに正しい戦略をとりましょう。」というのは理解できるが、「2倍よくなるなら」という条件はやや疑問。

ルール12:大きなチームには強い規則が必要

他人の書いたプログラムが読みにくいと感じたことがあるプログラマは少なくないだろう。プログラムには書き手のスタイルや哲学が自然と包含されるため、それが異なるということは、異文化と交流するような体験になるからだ。

そこで、チーム全体が同じ文化を醸成すればこの問題を解消できるというのが本書の主張。Sucker Punchでは変数の命名方法や中括弧の位置や使っていい言語機能まで細かくルールを規定しているとのことだ。

ルール13:雪崩を起こした小石を探せ

バグは観測される箇所とその原因はしばしば異なる。という話。

観測された場所でその場しのぎの修正を行う人がいるが、根本原因を直さなければならない。

他にも、純粋関数はデバッグしやすいとか、不具合を再現可能なログを出力しておくことの有用性などについて言及している。

ルール14:コードには種類が4つある

問題の難易度(簡単か難しいか)と、解法の複雑度(簡潔か複雑か)の組み合わせによって、コードは4種類に分けられる。という話。

偉大なプログラマーは難しい問題を単純に解くのに対して、平凡なプログラマーは簡単な問題を複雑に解いてしまう。

ルール15:雑草は抜け

誤ったコメントや、規則に従わないコーディングスタイルなど、コンパイル結果に影響を及ぼさないような小さな問題はプロジェクト内に絶え間なく存在し、知らぬ間に増殖していく。このことを雑草になぞらえ、雑草は見つけしだい修正しましょうねと。

ルール16:コードから先に進むのではなく、結果から後ろ向きにたどれ

問題を解決する際に、技術から解法を導くのではなく、望ましい結果から技術が決定されるべき。という話。

これはありがちだなぁ。

ルール17:大きな問題ほど解決しやすいこともある

視点を大きく変更することによって、解法を単純にすることができることがある。という話。

特定の解法のほうが一般的な解法よりも優れている場合が多い(ルール4参照)としつつ、問題を俯瞰して一般的な解法を用いたほうがよいことも稀にあるとのこと。

ルール18:コードに自らの物語を語らせろ

コードは自己説明的であるべきだし、そうでない場合には良質なコメントが必要だと。

ルール3をコメントについて補足したような内容になっている。大前提として、コメントはプログラムによって無視されるという意味で、本質的にはデッドコードである。このことは、ルール8が適用できることを意味し、書いたときには正しくとも読むときには誤っていることがありうるということだ。また、「何も情報を追加しないコメントは悪である。」といった、よく言われるコメントについての考察も含まれている。

ルール19:作り直しは並列で行うこと

システム全体に影響があるようなAPIの変更など、大きな修正を行う場合は、新旧どちらも利用可能な状態にして段階的に移行したほうがよい。という話。

最初に、フラグを有効にした場合にのみ新APIが有効になるように変更。次に、新APIを実装。最後に新APIを呼び出すように修正して旧APIを削除。という具体例が示されていた。このような手順によって、段階的に安全な変更を行えるというわけだ。

これがもし、新API書き換え終了後に基幹ブランチにマージするという手順では、基幹ブランチの変更に追従するのが大変で、競合を解決するのに永遠に時間が奪われてしまう。

ルール20:計算をやっておけ

タイトルのままと思わせつつ、原著の「do the math」は、「頭を使え」のダブルミーニングになっているとのこと。

「手作業の自動化はそのコストが割に合うか考えてからやるべきだ」という主張はもっともだけど、自動化はそれ自体の楽しみと完成後に悦に浸るためにやるものじゃない?笑

あらかじめ非機能要件の見積もりを行わなかったために、高水準な開発環境ではうまく動作していたゲームが、リリース後に家庭用ゲーム機で動作しなくて痛い目を見てしまうとか怖すぎる。

ルール21:とにかくくぎを打たなきゃいけないこともある

退屈な作業をスキップしちゃいけない。という話。

退屈なことをそっちのけで楽しいことを優先してしまいがちだが、優先度は面白さで決めてはならない。耳が痛い。

Conclusion

21個のルールをすんなり読み進めてくれることがありませんように。というのが著者の目論見とのことだが、良い意味で失敗しているように思える。どれも教科書的な内容で突飛なことはないからだ。

基本的にルールは言語に依存しない内容だと考えてよいが、具体例はすべてC++で書かれている。多くはないものの、テンプレートや解法済みメモリの参照を早めに検知する仕組みなど、C++ならではの話題がある。巻末にPythonとjavascriptプログラマーのためのC++の読み替え指南があり至れり尽くせりだが、所詮はおまけ程度なので過信はしないほうがよい。

最近読んだ技術系の文書ではダントツで面白かった。翻訳本だが、原著よりも訳注が充実していたのもよかった。

Thank you Sucker Punch! I know the rules.

More info

See also