はじめに
こんにちは!ソーシャル経済メディア「NewsPicks」新卒2年目のエンジニアのカトマサです。
この記事はNewsPicks Advent Calendar 2025 の14日目の記事です。
私はPlatform Engineeringチームに所属していて、ニュースの編成業務から、課金、動画配信業務まで幅広い業務を行うチームに所属しています。
経緯
「カトマサさん、このままNPの環境にいても、コードを書けるようにはならないよ」
上長であるプリンシパルエンジニアのむとうさんから言われたこの言葉に、私はハッとしました。
NewsPicksに入りたての頃、私はなんとなく動くコードを書いて開発を進めていました。ちょうどChatGPTやClaudeが普及し始めた時期で、AIが生成したコードも「良さそう」と思えば採用する。でも、PRレビューで「このコードを書いた意図は?」と聞かれると、うまく答えられない。そんな「雰囲気」でプログラミングをしていました。
むとうさんは続けてこう言っていました。
「エンジニアには英語学習と同じで、ネイティブしかいない環境に行くと自然に喋れるようになるタイプもいる。でも、文法や単語をゼロから積み上げていかないといけない人間もいる」
これを聞いて、私は深く納得しました。私はまさしく英語を学習する際に、SV, SVO,SVOCから丁寧に文法を積み上げてきた人間です。体で覚えるには、体系立てた基礎的な土台がないと応用できないタイプなのです。(ちなみに、英語は愚直に頑張って、TOEIC 900点の実力まで成長しました。)
この記事では、私がチームで行っている「プログラミングの基礎」勉強会を通じて学んだことを共有します。AIに頼り、雰囲気でコードを書いてしまっている初心者エンジニアの方々の参考になれば幸いです。
教材
私たちが題材にしているのは、浅井健一さんの著書『プログラミングの基礎』です。OCamlという関数型言語を使い、メトロネットワーク最短路問題をダイクストラ法で実装していく内容になっています。
この本は「プロになるJava」の著者である、きしだなおきさんも紹介しており、プログラミングの本質を学ぶのに適した一冊です。
デザインレシピという考え方
この本の特徴は「デザインレシピ」に基づいてプログラムを組み立てていく点です。関数を作成する際のデザインレシピを一部抜粋すると、以下のようになります。
- 目的 — 関数が何をするものかを考える。何を受け取り、何を返すのかを明確にし、関数の型を決定する
- 例 — 関数に望まれる入力と出力の例を作成し、実行可能なテストプログラムにする
- 本体 — 関数の本体を作成する。目的では「何を」するかを考えたが、ここでは「どうやって」実現するかを考える
- テスト — 作成したテストプログラムで動作を確認し、問題があればデザインレシピに沿って原因を特定する
例えば、鶴亀算はデザインレシピに従うと、以下のような形で書けます。
(* 目的:鶴と亀の数xと足の総数yに応じて、鶴の数を計算 *)
(* tsurukame : int -> int -> int *)
(* 鶴の数をa, 亀の数をbとした連立方程式を解くと、a=(4x - y)/2となる *)
let tsurukame x y = ((4 * x) - y) / 2
(* テスト *)
(* 例1:鶴と亀の数:2匹, 足の数:6ならば、鶴の数:1匹 *)
let test1 = tsurukame 2 6 = 1
(* 例2:鶴と亀の数:2匹, 足の数:4ならば、鶴の数:2匹 *)
let test2 = tsurukame 2 4 = 2
(* 例3:鶴と亀の数:3匹, 足の数:10ならば、鶴の数:1匹 *)
let test3 = tsurukame 3 10 = 1
書籍ではもっと複雑なアルゴリズムも同様にデザインレシピに従って書いていく練習を行います。
一見すると面倒に感じるかもしれませんが、このプロセスを愚直に繰り返すことで、複雑な処理も迷わず実装できるコードを書く上での「型」が身についていきます。
プリンシパルエンジニアから得た学び
書籍の内容はもちろん素晴らしいのですが、読めばわかります。ここでは、勉強会を通じてむとうさんから教わったマインドを紹介したいと思います。
プログラミングで覚えることは意外と少ない
私が所属しているPlatform Engineeringチームでは、幅広いシステムを管理しているので、多様な技術スタックを扱っています。
| 領域 | 言語・フレームワーク |
|---|---|
| サーバーサイド | Java, Kotlin |
| クライアントサイド | React |
| レガシー画面 | CoffeeScript |
| AWS Lambda | Python |
| 社内システム | AngularJS |
これだけ見ると覚えることが膨大に思えます。しかし、勉強会を通して、どのプログラミング言語も本質的には同じことをしているということを学びました。むとうさんによると、一つの言語を深く理解していれば、他の言語にも簡単に読み書きができるようになるとのことでした。
勉強会を通していろいろな基礎的なことを学びましたが、例えば、filterやmapを基礎を勉強会を通して学ぶことができました。書籍の中ではリストの基礎的なところから出発し、再帰関数で書いていた処理がfilterやmapなどの高階関数を使うことでスッキリ書けるようになっていきます。
この修行をしたことで、どのプログラミング言語を読み書きしていても、「Ocamlでやったところだ!」となり、物怖じせずに自信を持って、コードを読んだり書いたりできるようになりました。
(余談ですが、第14章の「高階関数を使ったリスト処理」の完全数を求める例題では、for文を使わずにfilterなどだけで、たった3行で完全数が求められるのはとても感動しました。)
気をつけていること
写経と練習問題を怠らない
とにかく教科書に書かれているコードを丁寧に写経すること。練習問題も自分で考えて手を動かすこと。これを徹底しています。
一時期、Copilotを使ってコード補完させたことがありましたが、正直まったく勉強になりませんでした。デザインレシピに従って、型の定義から始めてテストを書いて……という面倒なプロセスを自分でやることで、初めて「型」が身につくのだと実感しています。
業務コードと学びをリンクさせる
教科書で学んだ概念を、業務のコードと結びつけることも意識しています。
たとえば、書籍で学んだ「高階関数」の概念は、業務で使っているKotlinのコードにも現れます。
以前、ロック処理を行う際は以下のようにtry-finallyで囲む必要がありました。
fun update(request: UpdateRequest) {
val lockState = lockManager.lock("ResourceLock:${request.id}", Duration.ofSeconds(3))
try {
// ロック中の処理
val entity = repository.findById(request.id)
// ... 省略 ...
} finally {
lockState.unlock()
}
}
このパターンはコードベースの至るところで使い回されていました。毎回try-finallyを書くのは冗長ですし、unlock()の呼び忘れというリスクもあります。
そこで、関数を引数に取るwithLockを導入しました。
inline fun <T> LockManager.withLock(lockName: String, duration: Duration, block: () -> T): T {
val lock = this.lock(lockName, duration.toJavaDuration())
try {
return block()
} finally {
lock.unlock()
}
}
これを使うと、先ほどのコードは以下のようにスッキリ書けます。
fun update(request: UpdateRequest) {
lockManager.withLock("ResourceLock:${request.id}", Duration.ofSeconds(3)) {
val entity = repository.findById(request.id)
// ... 省略 ...
}
}
勉強会を行う前まではKotlinの本で読んだことがあって、上のようなパターンで書けることを知っていたものの、Kotlinはそんなに詳しくないし、間違ったらどうしようかと思って、わざわざリファクタリングしようとしていませんでした。
しかし、勉強会でOcalmを使って高階関数を必死に手を動かして書いたので、たとえ、言語がKotlinでも「Ocamlでやったところだ!」となり、自信を持ってリファクタリングできるようになりました。
勉強会で学び直して気づいたこと
この勉強会を通じて、私が一番学んだのは 「型」さえ身につければ、どんな言語でも、どんな問題でも恐れずに立ち向かえる ということです。
英語学習で文法を積み上げたように、プログラミングでも基礎やデザインレシピという「型」を愚直に繰り返すことで、応用力を身につけたいです。
AIが当たり前になった今だからこそ、「なぜそう書くのか」を自分の言葉で説明できる基礎力が、エンジニアとしての自信と成長を支えてくれると思っています。
おわりに
雰囲気でコードを書いていた頃の自分に
焦らなくていい。でも、基礎はちゃんとやろう。
と言ってあげたいです。
業務時間外に行っている勉強会の準備は決して楽ではありません。しかし、プリンシパルエンジニアから直接学べる貴重な機会に感謝しながら、一歩ずつ積み上げています。
今後は「計算機プログラムの構造と解釈」(通称SICP)にも挑戦したいと考えています。チームのエンジニアがすでに読み進めていて、むとうさんのおすすめでもあるこの本で、さらに深いプログラミングへの理解を目指します。
この記事が、かつての私のように雰囲気でコードを書いてしまっていて、成長できていないと悩んでいる初心者エンジニアの参考になれば嬉しいです。
プリンシパルエンジニアのむとうさんが気になった方は、是非、弊社のテックブログを読んでみてください。