バックエンド開発のための本当に読むべき書籍
正直なところ、また書籍のおすすめリストを書くべきかどうか、長い間悩みました。インターネットにはすでにそういったリストが溢れていて、ほとんどが似たような内容を繰り返しているからです。でも、サーバーシステムの開発に携わってきた何年もの間に自分の中で形成されたリストを共有したいと思うようになりました。これは単なる「バックエンド開発者のためのトップ10」ではなく、システムが内部でどのように動作するかについての私の理解を本当に変えてくれた資料たちです。
この記事について
最初にはっきりさせておきたいのは、私はすべてのプログラミング言語について語ることはできないということです。それぞれのエコシステムには独自の特性があり、独自のベストプラクティスがあり、独自の「聖典」があります。でも、Java、Go、Python、その他どんな言語で書いていても通用する普遍的な知識というものが存在します。そして、Rustについては後ほど別に触れます。
書籍のまとめ記事で私がいつも不満に思っていることは何か。それは「24時間でマイクロサービス」みたいな軽量なチュートリアルや、派手なタイトルだけど内容が浅い本が含まれることです。そういった本が速習のために必要なのは理解しています。でも、何年も動き続け、最初の高負荷で崩れないシステムを構築したいなら、もっと深く掘り下げる必要があります。
基礎:アルゴリズムと数学
一番つらい部分から始めましょう。Donald Knuthの「The Art of Computer Programming」です。そう、みんなが知っているあの4巻本です。誰もが言及しますが、実際に最初から最後まで読む人は少ないです。でも、知っていますか。それでいいんです。これは一気に読む小説ではありません。特定の問題に直面したときに何度も立ち戻る方法論の百科事典なのです。
私が最初にソートと探索についての第3巻を開いたとき、こんな基本的なことはすでに知っていると思っていました。でも、表面しか理解していなかったことが分かりました。Knuthは単に「これがどう動くか」を示すだけでなく、「なぜこの方法なのか、どんな代替案があるか、それぞれの決定にどんなコストがあるか」を示してくれます。
これらの巻を読むためには、同じKnuthがGrahamとPatashnikと共著した「Concrete Mathematics」が必要になるでしょう。これは単なる補足ではなく、アルゴリズム解析を理解するための数学辞書なのです。
TAOCPがあまりにも学術的に見える場合(それは普通のことです)、Cormen、Leiserson、Rivest、Steinによる「Introduction to Algorithms」から始めてください。この本は著者の姓の頭文字をとってCLRSと呼ばれることが多いです。これが大学の事実上の標準になったのには理由があります。著者たちはアルゴリズムがどう動くかを示すだけでなく、その正確性を証明し、パフォーマンスの境界を分析します。B木、ハッシュ化、ストリーミングアルゴリズムの章に特に注目してください。これらはサーバー開発で直面することになる内容そのものです。
コンピュータが実際にどう動作するか
プロセッサのキャッシュがどう動作するかを理解することが、パフォーマンスにどれほど大きな影響を与えるかに驚いたことを覚えています。アルゴリズム的に最適なコードを書くことはできますが、メモリ内でデータがどう配置されるかを考慮しなければ、パフォーマンスは何倍も失われます。
BryantとO’Hallaronの「Computer Systems: A Programmer’s Perspective」は、全体の連鎖を示す本です。プロセッサが命令をどう実行するかから、仮想メモリとリンクがどう動作するかまで。入出力の遅延がなぜ発生するかを理解すると、システムの設計方法がまったく変わってきます。
もう一つの宝石は、Arpaci-Dusseauの「Operating Systems: Three Easy Pieces」です。この本で何が私を引きつけたか分かりますか。著者たちが常に「なぜ?」と問いかけることです。単に「スケジューラはこう動く」ではなく、「なぜこのように設計されているのか、どんな代替案があったのか、開発者はどんなトレードオフを行ったのか」です。そして、この本は無料でオンラインで入手できます。このレベルの資料としては珍しいことです。
さらに深く掘り下げたいなら、McKusickの「The Design and Implementation of the FreeBSD Operating System」を見てください。これは完全にハードコアです。実際のオペレーティングシステムを内部から分析します。例はC言語ですが、概念は普遍的でどこでも適用できます。
分散システム:魔法が始まる場所
アプリケーションが一つのサーバーで動作している間は、すべてが比較的シンプルです。でも、複数のマシンに分散させた瞬間、興味深い質問が始まります。状態をどう同期するか。ネットワークが一時的に切断されたらどうするか。データの一貫性をどう保証するか。
Martin Kleppmannの「Designing Data-Intensive Applications」は私にとって啓示でした。Kleppmannは単に技術について語るのではなく、トレードオフを示してくれます。強い一貫性が欲しいですか。可用性を犠牲にする覚悟が必要です。高い可用性が必要ですか。結果整合性を受け入れなければなりません。この本は「正しい」解決策を探すのではなく、あなたの具体的なタスクに適したものを選ぶことを教えてくれます。
TanenbaumとVan Steenの「Distributed Systems: Principles and Paradigms」は、より形式的なアプローチです。数学モデル、論理クロック、因果関係。CAP定理とFLP不可能性の厳密な説明。この本は「完璧な分散システムを構築することは可能か」という質問に答えます(ネタバレ:不可能です。でも、なぜかを理解できます)。
そして重要なのは、オリジナルの論文を読むことです。Lamportの論文「Time, Clocks, and the Ordering of Events in a Distributed System」は、すべての教科書を合わせたよりも論理時間の概念をよく説明しています。同じLamportの「Paxos Made Simple」は、分散システムでコンセンサスを達成する方法を示しています(タイトルは欺瞞的ですが、そこでの「simple」は相対的です)。BrewerとFoxの「Harvest, Yield, and Scalable Tolerant Systems」は、CAP定理への別の視点を提供します。これらの論文はそれぞれ10ページから20ページですが、後に何百もの記事が語り直す本質が含まれています。
ネットワークとパフォーマンス
サーバーコードを書いていて、W. Richard Stevensの「UNIX Network Programming」を読んでいないなら、それを直す必要があります。第1巻はネットワーキングAPIについて、第2巻はプロセス間通信についてです。はい、例はC言語です。はい、場所によってはコードが古臭く見えます。でも原則は永遠です。ソケットがどう動作するか、epollとkqueueとは何か、プロセス間の効率的な相互作用をどう組織するか。すべてがStevensの本にあります。
Brendan Greggの「Systems Performance: Enterprise and the Cloud」は、システムが遅くなり始めて理由が分からないときの私の卓上リファレンスです。Greggは大規模データセンターで働いており、実際の条件下でパフォーマンスを分析する方法を知っています。レイテンシ対スループット、フレームグラフ、深いプロファイリングのためのeBPFの使用。「Observability Tools」の章は、適当に探るのではなく、正しいツールでシステムを見る方法を教えてくれます。
データと信頼性
Jim GrayとReuterの「Transaction Processing: Concepts and Techniques」は、1992年の古典ですが、今でも関連性があります。トランザクションが実際にどう動作するか、ACIDとは何を意味するか、システムが障害後にどう回復するかを理解したいなら、ここに来てください。NoSQL革命のずっと前に書かれましたが、原則はLevelDBやRocksDBのような現代のストレージシステムにも適用されます。
Alex Petrovの「Database Internals」は、データベース管理システムの内部で何が起こっているかを示します。LSM木、インデックス、分散クエリがどう実行されるか。Petrovはトレードオフを見事に説明します。LSM木がなぜ書き込みに優れているのに読み取りでその代償を払うのか、書き込み増幅にどんな代価を払うのか。
Michael Nygardの「Release It!」は、システムが本番環境でどう失敗するか、そしてそれをどう防ぐかについての物語集です。サーキットブレーカー、バルクヘッド、カオスエンジニアリング。Nygardは実際のインシデントを説明し、適切なアーキテクチャがそれらをどう防げたか、または少なくとも影響を軽減できたかを示します。
さて、Rustについて
Rustを最後に残したのは意図的です。言語に依存しない基礎について最初に話したかったからです。でも、バックエンド開発にRustを選んだなら(そしてそれは素晴らしい選択です)、最大限に活用するための本があります。
Jon Gjengsetの「Rust for Rustaceans」は初心者向けではありません。Rustを始めたばかりなら、まず公式の「The Rust Programming Language」を通してください。でも基本的な構文がもう疑問を引き起こさなくなったら、Gjengsetが深さを示してくれます。ボローチェッカーが実際にどう動作するか、データ競合なしで並行性がどう組織されるか、Cに近いレベルでコードをどう最適化するか。これはシステムコードを書き、フードの下で何が起こっているかを理解したい人のための本です。
Luca Palmieriの「Zero to Production in Rust」は純粋な実用主義です。ActixやAxumのようなウェブフレームワーク、SQLxを通じたデータベースとの作業、マイクロサービスアーキテクチャ、オブザーバビリティ。Palmieriは実際のプロジェクトで使える本番コードの例を示します。これは学術的な作品ではなく、行動へのガイドです。
公式のRustドキュメンテーション、特にunsafeコードとFFIについてのNomicon(The Rustonomicon)を忘れないでください。また、言語の変更が議論されるRFC(Request for Comments)を読むことをお勧めします。そこでは、言語開発者がトレードオフについてどう考えているか、どんな決定を下し、なぜそうするのかが見えます。
ここにないもの(そしてその理由)
「Clean Code」や「Grokking Algorithms」のような本をリストから意図的に除外しました。それらが悪いからではなく、異なる問題を解決するからです。これらは速習のため、基本的なスキルを形成するための本です。でも何十年も動くシステムを構築したいなら、別の深さが必要です。
ここには特定のフレームワークに関する本はありません。フレームワークは変わるからです。DockerやKubernetesのチュートリアルもありません。これらはツールであり、基礎知識ではないからです。5年後には新しいツールが現れるかもしれませんが、分散システムやトランザクションの原則は同じままです。
これらすべてをどう読むか
長年で理解した主なことは、これらの本は週末にコーヒーを片手に読むものではないということです。鉛筆、ノート、時には例を確認するためのコンパイラが必要になります。いくつかの章は何度も読み直す必要があります。そしてそれは普通のことです。
すべてを一度に読もうとしないでください。現在のタスクを解決するか、知識のギャップを埋める1冊の本を選んでください。読んで、実験して、実践で適用してください。それから次に進んでください。
もう一つのアドバイス:ソースコードを読んでください。SQLiteは約10万行の非常に高品質なCコードで、データベースエンジンコアアーキテクチャの参考です。CassandraやetcdのバグについてのJepsenレポートを分析してください。そこには、分散システムが本番環境でどう壊れるかの実例があります。
結論
このリストは「1ヶ月でバックエンドを速習したい」人のためのものではありません。これは20年以上動作するシステムを構築しようとしているエンジニアのためのものです。「これをどうやるか」だけでなく「なぜこのように動作するのか」に興味がある人のためのものです。
Knuth、Lamport、Gray、Stevens。これらは何十年も標準を設定してきた著者たちです。彼らの作品は努力を必要としますが、その努力は、複雑なシステムの問題に直面し、それをどう解決するかを理解するたびに報われます。
今あなたが興味を持っていることから始めてください。より深く掘り下げてください。そして覚えておいてください。優れたシステムは、流行のフレームワークの知識ではなく、基本原則の理解の上に構築されるのです。