10xプログラマー、それは「一流のプログラマーが普通のそれと比べて10倍の生産性をもつ」というソフトウェアエンジニアの世界における神話です。

「多くの人が毎日のように使うものを創れるようになりたい」

そんな想いからこれまで、Gunosy、Mercari、LINEなどでの開発を行ってきましたが、最近一人のエンジニアとして今後進むべき道について見つめ直す機会があり、「良いエンジニアとは何者なのか」について自問する時間がありました。

その過程で、Redisの作者Salvatore Sanfilippoによる「The mythical 10x progrmmer」と出会い、読んでみると非常に為になることが多かったので、本人に是非翻訳させて欲しいと申し出たところ、「Sure!」と快諾して頂いたため、僭越ながら共有させて頂きます。

10xプログラマーという神話

10xプログラマー、それは「一流のプログラマーが普通のそれと比べて10倍の生産性をもつ」というソフトウェアエンジニアの世界における神話です。

ここで言う「普通」というのは、自身の仕事を十分にこなすことが出来るが10xプログラマーのもつ魔法のような能力を持っていないプログラマーを指しています。より正確に定義するのであれば、「普通のプログラマー」とは、その分野のプロフェッショナルであるプログラマーの中で平均となる生産性を持つもの、と定義するのが良いでしょう。

そのような獣（beast）が存在するか否かに関しては、プログラマーのコミュニティの中でも意見が二分しており、「10xプログラマーなんてものは存在しない」と言う人がいる一方、「探すべきところを知っていれば100xプログラマーでさえ存在する」と言う人もいます。

プログラミングを「線形」な分野として見るのであれば、10xプログラマーの存在が不合理に見えるのは明白でしょう。あるランナーが他の選手よりも10倍早く走ることが出来るのか、ある作業員が他の人と同じ時間で10倍の建設を行うことが出来るのか。しかしながら、プログラミングというのは非常に特殊な意味で「デザイン」の分野です。プログラマーがアーキテクチャの設計に参加していないとしても、実装を行う際にはその実装に関するサブデザインが必要です。

プログラミングの設計と実装が非線形な能力である場合、コーディング、知識、無駄の判別などの能力も線形的ではなく、相乗的に機能することでプログラムは作成されます。プログラマーがプログラムの設計と実装の両方を担当できる場合、この現象はより顕著です。

達成すべきタスクが「目的指向」であればあるほど、潜在的な10xプログラマーは、少ない労力で自らの能力を活用することが可能です。一方、目的を達成するために使用するツールや実装方法に関するガイドラインが厳格だと、10xプログラマーは自らの能力を十分に発揮することが困難です。

彼らは、そのような「ローカル」な設計でも優れた仕事を行うかもしれませんが、例えば、到達可能な目的がほぼ同じだがコストが大幅に削減される場合に特定の仕様を完全に削除するなど、目的を達成するための方法を大きく変更することは出来ません。

プログラマーとして働いていた20年の間、私はRedisやその他のプロジェクトを通し、同僚として働く多くのプログラマーたちを見てきました。それと同時に、多くの人々は私のことを非常に実装の速いプログラマーだと信じています。私がワーカホリックではないことを考えると、私は自分自身を生産性の高いプログラマーの参考とすることが出来るでしょう。

以下は、プログラマーの生産性において、最も大きな違いを生み出すと私が信じている資質のリストです。

- 素朴なプログラミング能力

- パターンマッチング

- 集中

- 設計の妥協：90%を得る為に5%を倒す

- 単純さ

- 非完璧主義

- 理論的な知識

- 低レイヤーの理解

- デバッグスキル

素朴なプログラミング能力

プログラマーのとって最も明らかな短所あるい長所の一つは、プログラムの一部を実際に実装するというサブタスク、つまり関数やアルゴリズムを扱うことです。驚いたことに、私の経験では、何かを実際に実装する為に基本的な命令型のプログラミングを効率的に使用する能力は思ったよりも普及していません。時折、私は、チームにおいて、単純なソートアルゴリズムさえ知らない非常に無能なプログラマーが、大学卒で理論的には非常に有能だが実装力は不足しているプログラマーよりも多くの仕事をこなしているのを目にしたことがあります。

パターンマッチング

経験から言うとこれは、多くのよくあるタスクに対する、これまでに検討された一連の解決策を意味します。経験豊富なプログラマーは結局のところ、様々なサブタスクを効率的に処理する方法を知っています。これは、多くの設計作業を省くことができ、特に、単純さの最大の敵の1つ、設計上のミスに対する極めて強力な武器となり得ます。

集中

コードを書くのに費やした時間は、質を見ない限り生産性とは無関係です。集中の欠如は、内的要因と外的要因によってもたらされます。

内的要因とは、怠慢、運動や幸福の欠如、貧しさや睡眠不足、プロジェクトに対する関心の欠如などです（好きではないことをうまくやることは出来ません）。

外的要因とは、頻繁な会議、職場がない環境、同僚による頻繁な妨害などが考えられます。

集中を改善して邪魔を排除することがプログラミングの生産性に良い影響を与えるのは自然なことでしょう。場合によっては、集中する為に極端な対策が必要な場合があります。例えば、私は時々メールに目を通すだけでほとんど返信することはありません。

設計の妥協：90%を得る為に5%を倒す

プロジェクトにおいて本質的ではない目標が、設計において非常に大きな複雑性をもたらしていること、または、別のもっと重要な目標を達成することを困難にしていることを積極的に認識しようとする努力をしない場合、複雑さが発生してしまいます。設計者にとって、簡単には解決出来ない全ての部分、つまり工数とリターンの間に比例関係がないことを認識することは非常に重要です。

アウトプット最大化の為に実行されているプロジェクトは、重要かつ妥当な時間内に実装できる側面に対して正確にフォーカスが当てられています。

例えば私は、メッセージブローカーであるDisqueを設計したとき、単に、メッセージにベストエフォートの順序付けを提供することで、可用性、クエリ言語、およびクライアントとの対話性、単純さ、およびパフォーマンスなど、他のすべての側面が大幅に改善されるということに気が付きました。

単純さ

単純さが何か理解する為には、複雑さがどの程度頻繁に生まれるかをチェックするのが良いでしょう。私は、複雑さを生み出すのは二つの主要な要素があると信じています。それは、設計の妥協をしようとしないこと、それと、設計作業におけるエラーの蓄積です。

設計において誤った方向性に進めば進むほど、私たちは最適解からどんどん離れていくことになります。初期の設計エラーは、誤った手法を用いている限り、同じシステムを再設計したものに辿り着くことはありません。むしろ初期のエラーを対処する為に、別の複雑な解決策を設計することが必要になります。プロジェクトは全てのステップで、より複雑になり、より非効率となっていきます。

単純さを実現する方法は、小さな「プルーフ・オブ・コンセプト（PoC : Proof of Concept）」を繰り返すことです。プログラマーは、頭の中で単純な設計を検討を繰り返してから実装することで、最も実行可能かつ直接的なアプローチから始めることが可能です。その経験と能力は、設計を改善し、解決されるべきサブデザインのための賢明な解決策を見つけることを可能にするでしょう。

しかしながらどのような場合であっても、複雑な解決策が必要とあるときがしばしば存在します。どのようにしたら複雑さを避けることができるのか、長い時間をかけて熟考を重ね、全ての異なる選択肢を考えても、それ以外の可能性が見つからない場合にのみ、複雑な解決策を選択する、ということが重要です。

非完璧主義

完璧主義には二つのタイプがあります。出来る限り最高のパフォーマンスを出すプログラムを目指そうというエンジニアリングの文化と、個人的な特性です。どちらの場合であっても、完璧主義は、プログラマーが物事を早く実現する最大の障壁の一つです。

完璧主義と外部からの評価に対する恐れがあるプログラマーは、心理的または自明に測定可能なパラメーターに従ってのみ設計を洗練するため貧弱な選択をしてしまう、という設計のバイアスをもたらし、堅牢性、単純さ、時間内に完成させること、などが考慮されにくくなります。

理論的な知識

複雑な問題を扱うとき、データ構造に関する知識や基本的な計算量の限界、あるタスクに特化したアルゴリズムなどの知識を持っていることは適切な設計を見つけるのに大きな影響力を持ち得ます。

全ての分野でスーパーエキスパートになることは、必須ではありませんが、少なくとも一つの問題に対して多数の潜在的な解決策を認識することが出来ると良いでしょう。

例えば、ある程度のエラー率を受け入れるという設計の妥協をし、確率的な濃度の推定値を用いることは、ストリーム内の一意の項目を数えるために複雑で低速でメモリ効率の悪い解決策を避けることを可能にしています。

低レイヤーの理解

高級言語を使用している場合であっても、プログラムにおける問題のいくつかは、コンピュータが特定のタスクを実行する方法についての誤解から生じます。 使用されるツールやアルゴリズムに根本的な問題があった場合、そのプロジェクトを最初から再設計して再実装する必要性にさえつながるかもしれません。

Cの持つ優れた能力を把握し、どのようにCPUが動作するのかを理解すること、またカーネルがどのように動作してシステムコールがどのように実装されるかを理解することは、プロジェクトがあとで予期せぬ事態に陥ることを救うことが出来るでしょう。

デバッグスキル

バグを見つける作業は、簡単に時間を溶かしてしまいます。合理的な一連のステップを通じて徐々にバグの状態を把握しバグを修正するのが得意であること、また、バグを含むことがない単純なコードを書くという振る舞いを身に着けることは、プログラミングの効率に大きな影響を与えます。

最後に

上記の資質が、プログラマーの生産性に10倍以上の影響を与えうるというのは驚くべきことではありません。 これらの資質を組み合わせることによって、実行可能なモデルから始め、他のものよりも数倍単純になる可能性がある優れた設計を実装することが可能になるでしょう。

私は、このような単純さを強調した手法のことを

「opportunistic programming」

と呼んでいます。

基本的にすべての開発ステップにおいて、ユーザーに対して、最小限の労力で最大の影響を与える機能と実装を選択するべきでしょう。