Kengo's blog

Technical articles about original projects, JVM, Static Analysis and TypeScript.

オブジェクト指向か関数型か、という話題に私達はどう接するべきか

私がコードを書くときには「オブジェクト指向でいくか、それとも関数型か?」みたいなことはほとんど気にしていません。特にオブジェクト指向については人によって定義から違うこともままあるため、この手の議論がとても遠回りになることも多いと感じます。

ただきしださんのLT資料を拝見して、もしかしたらまだ需要があるのかなということで、この話題にどう接するべきか考えていることを書いてみます。

どう書くべきかはコンテキスト次第

結論から書くと、どのようにコードを書くべきかはチームや解決したい課題、利用言語や既存資産などのコンテキストによって変わります。 ので「何がオワコンでこれからは何が来る」みたいな議論は、チーム内という限られたスコープでのみ有効なはずです。 チームよりも広い場で議論する場合は、「どういったコンテキストにおいてどのような書き方をするか」のように若干抽象的なテーマが適切でしょう。

言い換えると、コードの書き方において絶対善や絶対悪は存在しないはずと考えています。例えばバッチ処理ないしウェブアプリケーションでは、複数スレッドから同一データを共有することで性能を高めるため、メソッドの戻り値をキャッシュしたりメモ化を施したりするかもしれません。このためにはデータが不変であると便利でしょう。 しかしこうした実装に登場するデータすべてが不変であるべきかというとそうではなく、むしろ可変データによって性能や可読性が向上することだってあるはずです。

私の経験した範囲でいうと、Repository内部で扱うデータを完全に不変にした結果コピーコンストラクタやシリアライズ・デシリアライズが頻出する読みにくいコードになったことがあります。 今ならライブラリの力を借りてビルダーを実装するなどもっとうまくできる気もしますが、単体テストによる品質担保を厚めにしつつ可変データを導入する手もあったはずでした。

トレンドの書き方が良いソフトウェアを届けるのに必須ということはない

OSSから例を出すと、OpenJDKやKotlin, Gradleといった著名なプロジェクトで使われているObjectWeb ASMはオブジェクト指向で書かれており、継承や配列といった今ならまず採用を避けるであろう書き方も頻出しています。また異なる意味を持つ intString も多く登場し、「この文字列はクラス名だっけティスクリプタだっけ?」といった注意を払いながらコードを読む必要があります。一部ではTypeTypePathみたいな型が用意されていて取り回すこともできますが、そのAPIはカプセル化やTellDontAskといった近年プログラマが慣れ親しんだものとは程遠いものです。

この面ではObjectWeb ASMは「プログラマの認知負荷を下げる」トレンドからは大きく離れていると言えます。

ですが、ObjectWeb ASMは事実上オワコンでなく、JVMエキスパートからの支持を集めて止まないわけです。 加速したJavaのバージョンアップにも速やかに追随し、コミュニティからの貢献を受け付けて修正をデリバリするとともに、リファクタリングや性能改善も行っています。今日SonarQubeを見たところではカバレッジ96.6%でした。まさに「質とスピード」を地で行くプロジェクトです。 *1

この面ではObjectWeb ASMは「ユーザに高い品質とかけがえのない価値を継続的に提供する」ソフトウェアの理想像に限りなく近いと言えます。 だいぶ極端な例ではありますが、トレンドの書き方が良いソフトウェアを届けるのに必須ということはないことを説明する良い事例だと思います。

曖昧な定義や由来を明らかにすることが重要

何がいいかはコンテキストによるのでコンテキストを明らかにしないまま議論をするのはやめましょう、というのが私の主張ではありますが、コンテキストを限定せずとも行うべき重要な議論・問題提起はあります。不明瞭な定義や由来に補足をしてただすものがそうです。言葉が曖昧だと議論が噛み合わず、建設的な議論になりません。例えばまさに今日読んだ Value Objectについて整理しよう - Software Transactional Memo はまさにこの貢献をするもので、とても勉強になりました。

定義や由来を明確にすることは、コンテキストが明らかなチームにおいても重要です。 例えばオブジェクト指向だと 2021年の「オブジェクト指向」を考える で指摘されるように、様々な定義が想起されます。 今話しているオブジェクト指向が何を意味しているのか、議論に参加する各々がきちんとすり合わせる必要があります。

まとめ

コードの書き方は結局、チームが望む働きを実現する道具のひとつです。チームの中で合意が取れているか、コードの理解と変更が容易か、APIや性能が利用者にも受け入れられているか……そういった要件に目を向けるべきです。オブジェクト指向や関数型も私達の道具箱に入っている道具のひとつとして、それぞれ尊重して理解につとめていきたいです。

*1:またAPIの認知負荷が高いのも、言い換えれば他のことに特化していると言えます。これは想像ですが、クラスファイルとプリミティブとの架け橋に徹し高い性能を実現することが設計の主目的かなと感じます。認知負荷については、各利用者が自分のコンテキストに最適化されたAPIを設計しそれでObjectWeb ASMを包むことで解決できます。ObjectWeb ASMはその用途が幅広いため、いたずらに抽象化してしまうと特定ユーザにとって使いにくいものになるでしょう。今のVisitorベースとTreeベースのAPIを提供するくらいがちょうどいいという判断かもしれません。