ソフトウェア工学をコンピュータサイエンスとよぶのはおかしい

職業エンジニアを始めてから,ソフトウェア設計論についての議論が多く目につくようになりました.それらは,よいシステムを作るうえで有用である一方で,周りのエンジニアの向き合い方に違和感を覚えることも多いです.

たとえば SOLID 原則や DRY / YAGNI や OOP / FP や TDD / DDD といったソフトウェア開発における作法や経験則が,あたかも絶対的な真理であるかのように語られ,コンピュータサイエンス的に正しい,アルゴリズムとしてこうあるべきだ,原則に従っていないので誤りだ,といった強い言葉で,システムやコードの良し悪しが断罪されるような光景です.

私はその違和感を,そのまま言葉にして投稿しました.

こんなことも書きました.

これらの投稿には,思いのほか多くの反響がありましたが,同時に「CS 学部のカリキュラムに含まれているのだから CS だ」や「実用的な工学もサイエンスの一部だ」といった反論も寄せられました.

しかしながら,私がここで指摘したかったのは,単なる言葉の定義遊びではありません.従うべき「事実」と調整すべき「規範」という,性質の全く異なる知識に,同じ「科学」というラベルを貼りつけてしまうことに対する,エンジニアとしての危機感です.

両者を混同することは,現場から考えることを奪います.本来,文脈に応じて取捨選択すべき設計論が「科学的に正しい」という権威の衣を借ることで,批判を許さない信仰へと変質してしまいます.

私は (修士までとはいえ) 工学を修めたエンジニアの一人として,この境界を明確にし,我々がどのように知識と向き合うべきかを整理してみたいと思います.

停止性問題の決定不能性とリーダブルコードを同列に語るべきではない

コンピュータと向き合い方について解像度を上げるために,一歩引いて全体を俯瞰してみましょう.そこには,明確に性質の異なる二つの領域が混在しているはずです.

一つは,従うしかない事実の領域です.たとえば,計算理論における「停止性問題の決定不能性」を見てみましょう.これは,どのようなアルゴリズムを用いても,与えられた任意のプログラムが停止するかどうかは判定できないという,厳密に証明された紛れもない事実です.あるいは,分散システムにおける「CAP 定理」や「FLP 不可能性」もそうだし,クイックソートの平均計算量が O(nlogn)O(n \log n) で最悪計算量が O(n2)O(n^2) といった,ソートアルゴリズムの計算量オーダーの話もここに分類されるはずです.

物理層に近い制約もそうです.光速を超えて情報を伝達できないことや,ネットワーク帯域の物理的な上限といったハードウェアの限界も,我々が受け入れざるを得ない事実でしょう.

これらは,我々エンジニアがどれほど努力しても,どれほど整理された美しいコードを書いたとしても,決して覆すことのできない制約です.物理学において重力や光速に逆らえないのと同様に,これらは「サイエンス」として我々の前に立ちはだかります.

もう一つは,取捨選択して調整すべき規範の領域です.冒頭で挙げた SOLID 原則や,デザインパターン,あるいは RESTful といった設計思想がこれに当たります.これらは,自然界の法則でも数学的な定理でもなければ,観測された事実ですらありません.先人たちが,人間にとって扱いやすいシステムを作るために,あるいは認知負荷を下げるために編み出した知恵やベストプラクティスです.誤解を恐れずに言えば,これらはあくまでも「人間側の都合」に過ぎません.

したがって,これらを採用すべきか,どう扱うべきかは,チームのスキルセットやシステムの寿命を始めとした目的や文脈によって,常に正解が揺れ動きます.これらを「科学」とか「サイエンス」とかよぶことは,そのグラデーションを隠蔽して「CS の権威が発言したのだから正しい」と疑いの目を持たずに思考停止してしまうリスクを孕んでいます.

カリキュラムにあるから科学というわけではない

これに対する反論として「大学の CS 学部のカリキュラムに入っているのだから分野として CS に包含して差し支えないはずだ」というものがありました.あるいは「(チューリングマシンに限らない) OS やネットワークといった実用的な分野も科学として扱われている」という指摘です.しかしながら,私が明確にすべきだと主張しているのは「事実」か「規範」かという分類であって,決して「基礎」か「実用」かというものではありません.実用的な分野の中にもこのレイヤーは存在します.

たとえば,OS の話題について考えてみましょう.スケジューリングアルゴリズムの数理や待ち行列の理論はサイエンスの側面が強いですが,UNIX のファイルシステム設計思想 (すべてはファイルであるとか) や,モノシリックカーネルかマイクロカーネルかの議論は,トレードオフの中で現状の最適解を探るべきエンジニアリングです.

もっと分かりやすい例を挙げましょう.一般的に,理学や工学のカリキュラムには「科学技術者の倫理」が必修として含まれるかと思います.では,これがカリキュラムに含まれているからといって,我々は「倫理」を「科学」とよぶでしょうか? 倫理は従うべき規範であって,決して観測された法則ではありませんよね.

私が主張したいのは,これと同じことです.コンピュータサイエンスの教科書にあるからという理由で,全く性質の異なるものを十把一絡げに「サイエンス」とよぶのは,あまりに乱暴な話です.それは工学という営みの本質である「制約の中で如何に設計を操るか」というダイナミズムを見失わせることになります.

ソフトウェア工学という分野そのものを否定するつもりは全くありません.実際の開発プロセスからデータを収集して,統計的に有意な傾向を見出すような実証的アプローチは科学的と言えるでしょう.しかしながら,現場で語られる SOLID などの原則は,そうした統計的な事実ですらなく,経験則に基づいた規範に過ぎません.

物理法則と設計戦略を混同してはならない

前述したようなレイヤーの混同が極まると,時として耳を疑うような議論が生まれます.私の発言に対して今回寄せられた意見の中に,その典型例がありました.

命令をメモリに格納すること、階層的に命名管理することは、ソフトウェア開発では必須作業です。 DRYやSOLIDはそのメモリ領域の管理を破綻させないための工学原則であり「お作法」ではありません。 電子回路を破壊しないための絶縁原則を「自然科学でないから単なる慣習」とは言わないのと同じです。

この主張には明確な誤りが含まれます.物理的な破壊と論理的な複雑さの混同です.

電子回路における絶縁破壊は,観測された物理法則であり事実です.電圧が閾値を超えれば回路は不可逆的に焼き切れますが,これは人間の意図や都合とは無関係に発生する自然現象です.

一方で,ソフトウェアにおいて DRY 原則の違反は常にメモリ領域の管理を破綻させるでしょうか? これは明確に「いいえ」です.事実として,近代的なコンパイラは,インライン展開による最適化を頻繁に行い,関数呼び出しのオーバーヘッドを減らすために,あえてコードを複製 (i.e. DRY の逆) しています.もし DRY の違反がメモリの破壊をもたらすとすれば,コンパイラが最適化を行った瞬間に,生成されたバイナリはクラッシュしてメモリ空間は崩壊するはずです.

しかしながら,現実にはそんなことは起きません.なぜなら DRY や SOLID は,あくまでもコードの管理や構造の理解を容易にするための,人間のための規範だからです.コンパイラや CPU にとっては,スパゲッティコードであるとか,綺麗にモジュール化されているかはどうでも良いことです.メモリ安全性を担保するのは GC や Rust の借用チェッカーといった言語処理系の仕組みであり,決してソースコード設計の美しさではありません.

私は設計原則を軽視しているわけではありません.むしろ逆です.絶縁破壊のような物理現象と DRY 違反のような認知負荷の問題を混同することこそ,工学的視点での低い解像度の表れです.前者は壊れるか否かの二元論ですが,後者は自分たちにとって保守しやすいか否かというグラデーションの議論だからです.

人が動かないからと権威付けするのは怠慢

もう一つ気になった反応があります.厳密には科学でないとしても,初心者に正しい作法を守らせるためには,強い言葉や科学的権威で指導する必要があるという,一種の教育的配慮を擁護する意見です.

私はこの考え方に強く反対します.なぜなら,それは指導する側の「説明の怠慢」に他ならないからです.

どうしてその設計が必要なのか,それを適用しないとどんな実害 (保守コストの増大や認知負荷の上昇など) があるのか,本来なら説明すべき目的とトレードオフを省いて,CS の理論だから黙って従いなさいと権威を借りて押し付けたとします.その結果として,いったい何が起きるでしょうか?

そうです.目的が蔑ろにされて「従うこと自体」が目的化します.たとえ文脈が変わっても,思考停止して万能薬のようにルールの遵守を強制させ続ける,カーゴカルトが生まれます.初学者が「守破離」の「守」として,まずは型を身につけること自体は否定しません.しかしながら,指導者がその理由を説明せず「科学的に正しいから」と虚偽の権威でマウントを取ることは,決して教育ではなくただの怠慢に過ぎません.

そんな極端な界隈があるのか? 藁人形論法ではないか? と疑う方もいたようですが,現に私の投稿には「DRY の違反は物理的な破壊と等しい」と本気で信じ込んでいるリプライが付きました.教育的方便のつもりだった偽りの権威付けが,いつしか現場で絶対的な信仰として定着し,エンジニアからエンジニアリングの能力を奪っている実例が,まさにそこにあったわけです.

工学の本質は「よい抽象化」の模索だという話

それでは,科学的な事実ではないにも関わらず,どうして我々はこれほどまでに設計原則や規範を重視するのでしょうか.どうして SOLID 原則やデザインパターンが必要なのでしょうか.それは,エンジニアリングの本質が「よい抽象化を模索する」ことにあるからだと私は考えています.

あくまでも「抽象化」であって,単なる「共通化」や「一般化」や「圧縮」ではないところが重要です.多くの現場では,ここも混同されがちですが,コードを共通化することと抽象化することは似て非なるものです.

共通化というものは「A と B は似ているからまとめちゃおう」というボトムアップな整理整頓に過ぎません.文脈が異なるものを無理やり共通化すれば,片方の仕様変更にもう片方が引きずられる密結合なシステムが生まれてしまいます.

一方で,エンジニアリングにおける抽象化は,トップダウンな境界線の設計です.複雑な事実の上に,人間が扱いやすい「都合のよいモデル」の層を作ることだと言い換えられるかなと思います.

たとえば,パケット通信を考えてみましょう.一般的な事実として,ネットワーク上のパケットは消失するし,順序も入れ替わってしまいます.これは逆らいようのない制約です.しかしながら,我々は TCP というプロトコルを被せることで,データが信頼性をもって順序通りに届くという,抽象化されたモデルをアプリケーション層に提供しています.パケットロスという事実の上に,ストリームという扱いやすいモデルを提供しているわけです.これこそがエンジニアリングに他なりません.

SOLID 原則や DRY は,このような抽象化を成立させるための発見的な道具であって,観測された事実そのものではありません.だからこそ,どの詳細を隠蔽して,どの自由度を残すかという境界線の引き方は,科学的な裏付けだけではなく,エンジニアの意思決定やトレードオフに委ねられます.

そこに絶対的な唯一の正解はなく,我々人間の美意識やチームの文化に依存するアートやデザインに近い側面が残ります.だからこそ,これを自然科学などと同列に扱うことには無理があるわけです.

まとめ

コンピュータサイエンスという言葉は魅力的です.自分の主張に「サイエンス」のラベルを貼れば,それは「客観的な事実」という皮を被って,他者からの反論を封じ込める強力な武器となるように思えるかもしれません.

しかしながら,エンジニアは科学者である以前に「エンジニア」であるはずです.科学者の仕事が「変えられない事実」を解き明かすことだとするなら,エンジニアの仕事は「変えられる設計」を調整して現実の問題を解決することです.

規範や原則を科学と偽ることは,このようなエンジニアリングの本分を放棄することに他なりません.CS の原則として正しいからと思考停止するのではなく,サイエンスという制約条件のもとで設計原則の物差しをどう使いこなすか,その文脈とトレードオフを語ることこそが,プロフェッショナルとしての工学的な態度ではないでしょうか.