Don't Repeat Yourself

Don't Repeat Yourself (DRY) is a principle of software development aimed at reducing repetition of all kinds. -- wikipedia

2024年読んで印象に残った本(技術書編)

2024年に読んで印象に残った本の技術書編です。去年はそんなに多くの冊数は読めていません。というか、技術書を執筆して出版したので、技術書そのものにお腹いっぱいだったのは大きいと思います。

本を書いたという話は下記です。

blog-dry.com

非技術書編を先に書いているので、よかったらこちらもどうぞ。

blog-dry.com

免責事項ですが、記憶を元に書いている箇所が含まれることがあります。また、書籍のリンクにはアフィリエイトコードが付与されているので、苦手な方はURLから外してご購入ください。

目次

ルールズ・オブ・プログラミング

Ghost of Tsushimaを作った会社の人が、こういう会社で扱われる大きめの規模のプログラムをいろいろ書いてきた経験を通じて、大事だったと思われる話を紹介してくれる一冊です。

今読み返しても「抽象化ないしは一般化は事例が最低でも3つ見つかるまではやるな」というのがまず目に入ってきます。先日Rustのような抽象力の高いプログラミング言語であったとしても、Goを書くかのように愚直にコードを書くべきという話で盛り上がっていたのをTLで見ました。私は常に愚直に書くべきとは思っていなくて、抽象化できる部分はもちろん抽象化してもいいのだけど、大半のケースで「結局これに対応してないじゃん」が発生するんですよね。事例が3つくらい見つかると、そろそろいい共通項が見つかり出すように思っていて、そういうタイミングが来るまでは愚直に書いておいて、来たら抽象化したらいいと思います。見つかる前からDRYを意識しすぎて抽象化しまくるのは大体いい結果に終わらないので、たしかにやめておいた方がいいなという経験則があります。

あとは、「ジュニアとジュニアのコードレビューは本当に意味ないからやめよう」でしょうか。コードレビューの話は私のいる大規模めのプロダクトでも、品質担保の一環としてよく議論に上がるんですが、まず最初にこれをチェックするようにしています。ジュニアというのは、要するに業界に入りたて〜人によっては3年目くらいまでのソフトウェアエンジニアのことを指しています。あるいは、プロジェクト入りたての人同士でもと言い換えてもいいかもしれません。要するに超若手同士/オンボーディング中の人同士でコードレビューをしても、たとえば業界経験が浅すぎるが故に深いフィードバックを得られず、結果彼らにとっても成長につながらないといったところでしょうか。そうならないように、必ず経験の長い人が入るようにした方がよいと思います。

感想は以前こちらに記しています。

blog-dry.com

Tidy First?

そういえば翻訳が出たようですね。めでたい!原著で読みましたが、いい本でした。翻訳版は持ってないので、「tidying」がどう訳されているかはちょっと知らないのでその点にご注意ください。

Tidyingは、要するにリファクタリングには至らない規模の、ちょっとしたコードの整理のことを指しています。リファクタリングの部分集合のようなものでしょうか。たとえば、関数の順序を読みやすく入れ替えたり、概念的に違う箇所にあるものを適切な位置に戻したりするなどがこれに該当します。

リファクタリングはどちらかというと大規模になりがちで、機能開発を止めがちです。なので、リファクタリングそれ自体コストのかかる活動だと認識されがちかもしれません。これ自体コストのかかる活動だということになると、ついつい後回しにしてしまいがちでしょう。ただ、リファクタリングが本来になっていたようなコード整理の活動をおろそかにすると、将来どこかでその借金を返済しなければならないときがきます。

著者はそこに問題意識を感じており、Tidyingという小さめの改善活動を日常の開発業務の中にとりいれていく必要性を強調します。本書の2章ではどのようにそうした活動を運営していけばよいかについて触れられており、参考になります。たとえば通常の機能開発のPRとTidyingのPRを混ぜないなどです。

最後の章の経済分析は、NPVなどを用いて「今それをやる理由」を説明しています。経済分析の中身自体は金融工学の初歩的な知識を多少要求するようには思いますが、要するにこうしたリファクタリングというかTidyingの活動には経済性はついて回るもので、経済性も説明できるのだ、だからやらない理由はないはずだという基礎づけをしているのかなと思っています。

感想は以前こちらに記しています。

blog-dry.com

Domain Modeling Made Functional

やっと読めました。通読したので、ぼちぼちRustやKotlinのような言語でどう実践できるかを考えています。こちらも翻訳が出たようですね!そして、やはり翻訳版を持っていないので、どう訳されているかはちょっと知らない点にご注意ください。

本書の主題は、関数型プログラミングの手法をDDDのような設計手法に持ち込んでいくとどういうデザインになるかを探求していると理解しています。逆にいうと、F#のようなゴリゴリの関数型プログラミング言語でDDDを実践するとどうなるかを考えているともいうでしょうか。

とりあえずよかったポイントとしては、型付けをしっかりやりながらコードを書くという議論がなされている点でした。古めのJavaのような言語を使っていると型付けがどうしても緩いというか、オブジェクトの中身の状態を変化させながらコードを書く関係で、そのオブジェクトの状態が今何なのかは、コードを実際に動かしてデバッグしないとわからないとなりがちだと思います。こうした問題は、そもそも状態に型付けをすれば回避できることが多いです。この議論は多くの現場で実践しやすいように思っていて、ぜひ私の所属するプロダクト(Kotlin製)でもとりいれていきたいかなと思います。というか、すでにとりいれています。

次に、Railway-Oriented Programmingという手法についてです。RustやScalaを使っているとこの話は当たり前のように感じてしまうのですが、他の多くのプログラミング言語では、そもそも例外が使われていて、例外を送出するスタイルをとっていることが多いです。Kotlinもご多分にもれずです。例外創出は単純に型付けとして表現されないので、その分自分たちで組んだ型の体系に抜け穴ができることになります。型つけや論理を重視する関数型プログラミングスタイルではこれは避けたいところでしょうか。というか単純に純粋性がなくなるのでダメですね。

ところで、このRailway-Oriented Programmingは注目を集めているようです。さまざまな言語で実践してみている例を目にします。が、本当に導入すべきかは検討の余地ありだと思っています。私の個人的な意見としては、Railway-Oriented Programmingは最終的にはflatMapを多用しなければならなくなるわけですが、このflatMapに対する特別な言語処理系側からの支援機構がない限りはただただコードを読みにくくするか、型パズルを辛くするだけではと思っています。Rustなら?Scalaならfor-yieldが支援機構に該当します。これがないプログラミング言語では、むしろおとなしく例外を使った方がいいのでは…と思わなくもないです。

関数型プログラミング言語をそれなりに使ったことがある方であれば、本書の内容それ自体はあまり大きな驚きはない印象です。すでに実践しているよと思う話が大半でした。

私はどちらかというと、Scalaで書かれたこちらの方がためになったかなと思いました。いろんなモナドを駆使してDDDを実践する一冊です。たしか中身はScalazだったと思うんですが、Catsにも同等の機能はたくさんあるので、Catsで再実装してみるとおもしろいです。この本のおかげで、モナド慣れ(?)できました。

naoyaさんのこのスライドも参考になりました。

TypeScript 関数型スタイルでバックエンド開発のリアル - Speaker Deck

私自身も、Scalaで書き直してみています。TypeScriptの例ばかり見て、さすがにそこはScalaだろうと思ったのでScalaで書いてみています。Scalaならめちゃくちゃ綺麗に書けますね!Haskellの練習にも良さそうなので、いつかやってみたいです。

github.com

大規模データセットのためのアルゴリズムとデータ構造

広告配信にいたころは日夜超大規模なデータとの戦いをしていたので、その頃に欲しかった一冊だったなと思います。もうちょっと早く知っていれば…と思わなくもないですが、よい読書体験でした。ただこの分野はまだ勉強中で、上の数冊のように考えたことをつらつら書けるほど理解もしていないので簡潔に済ませておきたいと思います。

古典的なアルゴリズムやデータ構造はそれなりに理解しているし使いこなして日常業務にあたっているけれど、日々の開発で「実はここはもっと効率のいい方法がとれるんじゃないか」と思うことがあると思います。広告配信の場合、キャッシュを多用してなんとかレスポンス時間を高速に保つという泥臭い努力が行われるわけですが、メモリにすべての広告情報が乗り切ることはまずありません(乗り切ってしまうようなサービスは案件が少なすぎるので早晩潰れます)。そういうとき、たとえば本書でも紹介のあるブルームフィルターを知っていたりすると、別の効率良い手段をとれるといった具合です。

私も完全に初学者なので勘所は詳しくはわかりませんが、本書は「実はここはもっと効率のいい方法がとれるんじゃないか」を紹介してくれている一冊だと思っています。なかでの議論も数学的にきちんと説明されていて、入門書として適切らしいのはもちろんのこと、一介のソフトウェアエンジニアにとっては、採用できる手段の引き出しを増やす意味で読んでおくといいんじゃないかと思いました。私も純粋な興味が半分と、そういう動機が半分くらいで読みました。

コード×AIーソフトウェア開発者のための生成AI実践入門

生成AI関連の今年読んだ本の中では最もよかった一冊でした。私自身はそもそも巷を騒がせているような「何かを作れているAI」に対する関心はそこまでないです。というのも、自分で手を動かせば作れてしまうからです。ただ一方で、「自分で手を動かして作るスピードを高める方のAIの使い方」には興味があります。要するに、コードを書いている最中のAI活用の文脈です。本書はその部分で活用できるのではないかと思って手に取りました。

書籍の中には、たとえばプロンプトをどう書いたら効率がよいかや、アカデミックな場所で議論されているプロンプトの技法などが紹介されていて、生成AI素人の私も大変ためになりました。普段はGitHub Copilotをそれなりに使って実装を行っているわけですが、そうした人であってもたとえばコードのピン留めなど役にたつテクニックが記載されています。また、生成AIにもいくつか種別があって、目的や用途ごとにツールを使い分けると良いという話は大変ためになりました。GitHub Copilotと、GitHub Copilot Chatをこれにより使い分ける日々が始まりました。

それよりさらに興味深く思ったのが、AIが意図を把握してくれやすいコードの書き方の部分でした。何か特別なことがあるのかと思いながら読み始めたのですが、結局紹介されている技法はすなわち人間にとっても読みやすいコードを書くためによく使われるテクニックでした。一見するとこのことは何もおもしろみがないように感じられてしまうかもしれません。しかし見方を変えれば、結局AIが意図を把握しやすいコードというのはそもそも人間が意図を把握しやすいコードなのだ、ということです。つまり普段の開発から、チームメイトや未来の自分に意図の伝わるようなコードを書いたり、コメントを残したり、ドキュメンテーションを行ったりすることが、そのまま生成AIを上手に使うことにつながるのだと気づきました。

ソフトウェアエンジニアの仕事がAIによってなくなるかというと、現時点のレベルのAIだったらなくならないと思っていますね。現時点の中途半端なAIであれば、2024年読んで印象に残った本(非技術書編) - Don't Repeat Yourselfでも取り上げた『技術革新と不平等の1000年史』にも書かれていた通りで、劇的には世の中や社会を変えてはいかないと思っています。

なぜかというと、そもそも出力が正しくないケースがまま多いからです。少し賢くなったコード補完程度の役割であれば十分こなせると言えばこなせますし、またAIでゼロから100まで全部作り上げたとしたらおそらくまあまあ動くものを作れそうな気はしています。しかし、ソフトウェアエンジニアリングというのはすでにあるソフトウェアの保守運用や改良改修がメインの作業のはずです。このソフトウェア産業を成立させるためには既存ソフトウェアに対する高品質な改修は欠かせないわけですが、AIにはそれは今のところは無理でしょう。

たとえば自身の文脈の外にある事象が多分に含まれるようなコードベースに関する、既存の機能の改修に類するような問いかけをすると、ソースないしは知識不足からなのか割と出鱈目な答えが返ってきます。[*1]既存の文脈の把握は人間の場合だと現場の人に聞くという作業が経由されるわけですが、AIについていえば今のところプロンプトの入力者の知識を越え出ることはありません。これは割と現場作業では致命的で、要するに作業者の作業がスケールし得ない(入力者の主観を越えなそうな)ことを意味すると思います。加えてこうした誤認の度合いは、対象の傾向にももちろんよるものの、おそらくですが同程度の知識を得た人間よりもまだよくない感じがします。このギャップが埋まらないとソフトウェアエンジニアの代替はまだちょっと厳しいですね。AIエージェントというものがこれからこうした問題を解消してくれそうですか?であれば、失職するかもしれません。

しかし一方で、生成AIの活用は社会インフラに近い存在になってしまったのもあり、いつまでも小馬鹿にして距離を保ち続けるのも違うとは思っています。インフラとなった以上はそこに乗っかって新しい機会や生産性向上を享受する必要があります。なので、来年以降もいいツールが出れば使い続けたいとは思っています。仕事で何か施策を行いたいとなったときにも、AIを活用して自動化できないかは常々考え続けたいものです。

モデル検査器をつくる〜Goで実装して学ぶ形式手法〜

techbookfest.org

最後はこれです。技術書典でお見かけしたので、興味を持って買ってコードを写経しました。形式手法については業務でいかしてみたいと常々思っていて、いかすためにはまずそもそも何ができるかを知っていかないとと思っています。

内容の紹介は著者の方のブログへのリンクを貼っておきます。

ccvanishing.hateblo.jp

余談ですが、巻末に次の学習のための参考文献がいくつか示されているとさらに嬉しかったです。独学しようにも、書籍のガイドがいかんせん少ない分野な気がしているためです。

まとめ

とりあえず年末年始読み切ろうと思っている本は下記です。最近はアーキテクトという仕事に半分くらい足を突っ込んでいるのですが、意思決定をする場面が非常に多いです。トレードオフなどを検討しながらいろんな人の意見をまとめる必要があるわけですが、結局何を大事にしたらいいんだっけ?をよく忘れてしまいます。局所最適解を導かないようにしていきたいものです。

*1:もちろんプロンプトエンジニアリングをはじめとする訊き方の工夫や学習させるデータの質を改善するなどすれば、相当数改善するかもしれません。しかしその手間にかかるコストが、人に聞いて解決する場合と比べて割に合わないように思います。割に合わなさもまた、AIの課題点だとは思います。