コードが読めるソフトウェア開発者
僕はコードを読むのは得意な方だけど、それが過ぎてコードを書かなくてもシニアソフトウェア開発者になってしまった。実はコードをちゃんと読めるソフトウェア開発者って希少価値が高いのではないか、と思ったので自分がどんな感じでシニアになったのかをまとめてみた。似た様な人の参考になれば幸いだ。
同意。僕は未だ書く方はほとんど機会なく成果もないけど、コードを読み尽くして、負荷試験や本番で挙動を把握し続け、メトリクスでとことん確かめていった結果、Sr. Engineer になれた。 https://t.co/KXtMdEaRr8
— Ryosuke Iwanaga (@riywo) April 16, 2021
コードを書かなくてもシニアソフトウェア開発者になれた
僕は今 Amazon の Sr. Systems Development Engineer という職種で働いている。いわゆるソフトウェア開発職で、シニアとついているのでチームやチームを跨いで技術的に引っ張っていく、Tech lead の様な存在だ。だが、約 2.5 年前に働き初めてから昇進するまでの間、僕はバリバリとコードを書くことはしていない。一般的にソフトウェア開発といえばコードを書きまくって新機能追加や改善を行なっていくものと思われているかも知れないが、必ずしもそうではないし、書いていなくてもシニアになれた(もちろん作ったものも少しはあるんだけど、インパクトは全然小さい)。
僕が評価されたポイントの一つは、深くて幅広い理解力を元にプロジェクトを適切に分解して完遂できたという点だ。去年 1 年間やっていたプロジェクトがその端的な例なので紹介すると、既存システムを設定値の変更(例えばスレッド数)とキャパシティ増強でスケールさせるという、ここだけ一見すると 1,2 週間で終わりそうなものだ。だが、システムは 10 を超えるマイクロサービスで構成されていてオーナーは多数のチームにまたがっており、一つの設定値変更がどこにどういう影響を及ぼすかはそれほど自明ではなかった。そこで僕がやったのは、各種文書の作成とシステムの理解、メトリクスの収集に負荷試験、そして緻密な実行計画の作成だ。文書の作成は「質の高い技術文書を書く方法」で書いたようなことをやったけど、システムの理解のためにはコードの深い読み込みが不可欠だった。メトリクスや負荷試験はシステムの挙動を正しく見極めるためのもので、実行計画は変更を安全に完了するために徹底的に調べてあらゆる不安要素に対応した文書を仕上げた。
ご覧の通り、このプロジェクトに関連して僕がコードを書いた部分はほぼ無い。だが、他人が書いたコードを理解して挙動を正確に把握できたことが非常に重要な要素であったし、それが評価されている。1 年前には全く知らなかったシステムについて、少なくともスケールに関連する部分は一番詳しい人になった。僕からすると、こんなの全然創造的でもないし、コード読んで理解するだけだから時間かければ誰でもできるのでは?と思ってたんだけど、実際やっていく中で、他人が書いたコードを深くまで理解できる人はそんなにいないんだな、ということに気づいた。
もしあなたが僕と同じ様にコードを全然書いていなくて、このまま開発者としてキャリアを積んでいけるのか不安に思っていたら、こうした素養がある人は僕の肌感覚ではむしろコードをバリバリ書ける人よりも少ない様に思うので、自信を持ってその能力を発揮し続け、書くことしかできない人たちを圧倒してしまえばいいのではないか。1
コードが読めると何がいいのか
この経験を経て、僕は新しいものを作れることだけが開発者として重要だとは思わないようになった。ソフトウェアの本質でもあり僕が最も愛している部分は、運用しながら高速に改善できるという点だが、前提として運用できていることが重要だ。既存のコードを深く理解できなければ、適切な運用もできないし、トラブルシューティングもままならない。コードが読めるということはこの運用部分に大いに貢献できるということであり、それは守りではあるが攻めた守りでもある。
それから、コードを書く方にもいい影響がある。僕は天才プログラマーではないので、そういう人がどうやってコードを書いているのかはわからないが、少なくとも僕は見たことのないコードは書けない。でも、裏を返せば見たことのある(そして理解した)コードなら書ける。コードをたくさん読めば読むほど、いいコード・悪いコードとたくさん出会えて、自分の中の引き出しを深く広くしていくことができる。読みながらデザインパターンを吸収していくような感じだ。こういうタイプの人にとっては、読むこととはすなわち書くことだ。なので僕は喜んで読むし、そうすることで読みやすいコードというのも頭の中にイメージできるようになってくる。
けれども、世の中の人はそうでもないらしく、コードを読もうとしない人は多い。昨今は OSS として広く使われているもの(Linux とか)や、サービスとして熟練されていてドキュメントが充実しているものを使うことが多いので、検索すればいくらでも情報も引っかかるし普通の使い方をしていればそうそうおかしなことになることもない。そうすると、その前提を社内のコードにも当てはめがちだ。しかし、社内のコードというのは Linux 等と比較すればユーザも少ないしドキュメントを充実させることが直接的に利さないので、例えばコメントに書いてあることと挙動が違ったりもする。だが、コードを読めば 100% の自信をもって理解できる部分が多い(もちろん読み切っても理解できないものは存在する)。
つまり、人が読もうとしない様な部分こそ差別化できる要素であり、むしろそこを積極的に読んで完全な理解をしてしまうという戦略もとれる。僕は無意識に昔からそういう方針だったみたいで、みんなが触っているような部分は必要になったら聞けばわかるのでスルーして、一方で 10 年間触れられず熟成しきった様な部分や、フレームワークの中身、初回起動時にしか走らない様なコードを、求められていなくても理解しておくことで、時に他のチームのコードだけどそのチームの人よりも詳しい、みたいな状態をも生み出すこともできる。彼らはそんなの理解したくなくて自分の興味のある範囲でコードを書きたかったりするので、お互いにハッピーな状態でもある。
これの一種の派生系が、ビルドおじさんとかデプロイおじさん(ビルドやデプロイに属人的に詳しい人)みたいなやつで、ビジネスロジック外のビルドやデプロイの仕組みというのは、ほとんどの人にとっては正しく動いていて当たり前程度の理解しかなくて、それ故に何か問題が起こると全く対応できず、そういった一部の詳しい人にしか対応できなかったりする。僕はほとんど趣味みたいなレベルでいつもビルドロジックとかデプロイロジックを読み込んでいる(これはドキュメントの読み込みや挙動確認も含め)ので、なぜか知らない間に詳しい人認定をされてしまうけど、実際今も自分と同等かより詳しいと思える人はチームには 1,2 人しかいない。
ところで、コードリーディングは孤独な作業だ。一緒に画面を見ながら複数人で読むことはあまり効率よくないし、ある程度完結する前だと途中から誰かに引き継ぐのも難しい。なので、そういう孤独で集中を要する作業が苦手な人には結構辛いのかも知れない。幸い、僕は孤独な作業の方がむしろ好きなので、似た様なタイプの人はコードを読むのに向いているのかも知れない。
どうやってコードを読むか
最後に、どうやって読むか。これも人によりけりなので僕のケースだけど、状態遷移をもったエンティティに着目するのはおそらくどんなケースでもある程度有用ではないかと思う。なぜなら、計算機の本質はチューリングマシンにもあるように状態遷移だから、とか適当なことを思いついた。なんにせよ、規模の大きいコードを読む際にはまず状態を持った重要なコンポーネントに注目して理解を進める。どういう状態があり得るのか、誰がどういうタイミングで遷移させ、誰がどういうタイミングで状態を見ているのか。分散システムや並列・並行プログラミングではこれらのタイミングが微妙な race condition を見極める時に肝になってくるし、ロジックを順番に読むだけだと中々見えてこない部分なので、これを正確に文書化できると助かる人はかなり多いはずだ。
あとは入り口が重要で、サービスの起動ロジックから読み始める(main 関数から始める)ような読み方は、起動ロジックに興味がある時以外はやらない。大概何か知りたいものがあるはず、例えばエラーログの原因とか。であれば、まずはそのログを吐いている箇所から始める。これはまぁ大体誰でもやるけど、その入り口をちゃんと覚えておいて、何がどういう風に遷移してそこに至ったのかを読み解いていくのは意外と難しい。例えば Interface を多用していると、どの実装を使っているかを正しく把握しないといけなくて、そのために結局起動ロジックまで戻ってきたりもするので、初めに思っていたより複雑になることがある。僕は読みながら重要な関数呼び出しの行をメモして繋げていくことが多い。そうすることで、あとでまとめて他人にも共有しやすい。
こうやって読んでいる時は脳内でスタックマシンを動かしている様な感覚で、少し集中してやらないと難しい。コードを書いている時よりもビルドやテストの待ち時間とかが無い分だけ、集中力が必要な気がする。適切に手元のメモに吐き出せるといいんだけど、深くまでたどらないと正解が分からなかったりして、この辺はまだ上手いやり方が分かってない。とにかく集中して脳みそをフル回転する感じで今はなんとかやっている。
そして、コード以外に利用できるものを利用するのも大事だ。例えば古くて一部間違ってるけど大まかには通用するドキュメントや、不完全だけどそこそこ書いてあるコメント、変更履歴およびその際のディスカッションや関連リソース、もちろん必要に応じて人にも確認する。
コードを書かないソフトウェア開発者
振り返れば、10 年ほどこの業界にいるけど、バリバリと書いていたのは 1 年弱くらいだ。あとは、オペレーションとして他人が書いたコードをメンテナンスしたり、アーキテクトとして他人が作ったサービスをお客さんに使ってもらう手助けをする仕事だった。3 年前に、僕はもう他人の書いたコードでご飯を食べるのは御免で自分のコードを書きたくてソフトウェア開発者に転向したんだけど、結局コードを書かないことが自分の強みなのは変わらず、一方でそれが意外と希少な能力なんだと分かった。
もちろん僕もコードは書いてるけど、僕の出すコードレビューは、設定変更 1 行に対してその背景やテスト結果の説明に 100 行かける、みたいなのが多い。これでコードを書いてるとはあまり言えないし、コーディング試験には本当に役に立たない。でも、たかが設定変更でも前述のプロジェクトの様に 1 年かけることだってあるし、開発者のあり方としてまぁこういうのもありなのではないか。本当は僕だってキラキラした機能開発のタスクをやりたいけど、比較優位でこういったコードを書かないタスクを僕がやるのが全体で見ると効率がいい。
人によっては、こんな地味なソフトウェア開発なんてやりたくないって人もいるだろう。別にそれでいい。けど、ソフトウェア開発はチーム戦になることがほとんどで、それぞれの得意分野を活かして戦うのがベストだ。みんながみんな新規開発ばかりするのではなく、こういった地味な運用を支える業務(時に気が狂いそうになる程の手作業の連続)だって、立派なソフトウェア開発であり、それらの多くは他人の書いたコードを正確に理解している人によって支えられている。
とはいえ、僕個人はまだ仕事でコードを書きたい気持ちはある。コードを書かなくてもここまでこれたので、これでコードを書ける様になればもっと強くなれるのかなという甘い計算もしている。いい機会が見つけられることを祈る。
こんなところで、おしまい。似た様なことをしていて自分の能力に不安を感じている人がいたら、何かの参考にはなるのではないだろうか。
Footnotes
-
なお一つだけ問題があるとすると、面接のコーディング試験は辛い。全然書いてないからこれはどうしようもなくて、面接前に改めて特訓するか、コードを読む能力を正しく評価してくれるところを探すしかない。現実的には、社外から採る場合にはコーティング試験での足切りは必須になってしまうので、諦めて対策をするしかないのが現状だ(僕はこれはあまりいい状態だとは思ってないけど、他にいい採用手法は思いつかない)。僕自身は未だにそこを妥協できないので、対策をするよりもコードを書く機会を探していこうと思っている。 ↩