「フレームワークを使うな」の真意
今回のテーマは、kuniwakがどこかで語っていたという「フレームワークを使うな」という過激な主張です。hentekoはその過激さを面白がりつつ、なぜそんな思想に至ったのかを問いかけました。
kuniwakの主張はシンプルです。フレームワークを使うということは、ビジネスの成功という観点で「八十点以上を目指さない」という決断だ、というのです。つまり百点を目指すなら使わない方がいい、という趣旨でした。
フレームワークを使う時って、ビジネスの成功という観点で八十点以上を目指さないっていう決断であると私は思っているんですね。
この思想の背景には、実体験があります。バニラ(言語標準)ならちょっとした工夫でできることが、フレームワークに載せようとした途端に難しくなる。ある機能を実現したいのに、フレームワークの部品を経由すると壮大なコードが必要になってしまう。本質的ではない苦労を強いられる経験を、kuniwakは数多くしてきたと言います。
もう一撃を加えたのが、フレームワークのアップデートです。RailsRuby言語で書かれた代表的なウェブアプリケーションフレームワーク。「設定より規約」を掲げ、決められた作法に沿えば高速に開発できる。のようなフレームワークは定期的にアップデートが来て、部品の規格が少しずつ変わります。その追従作業が本当に自分の恩恵になっているならまだしも、多くは他の利用者の要望が取り込まれた結果で、自分にとっては必要ない変更が圧倒的に多かった、と振り返ります。
アップデートが来る
関数のシグネチャが変わる/意味が変わる
対応を迫られる
本質的でない修正作業が発生
誰のための時間?
「フレームワークを使うと決めた人のため」に払っている感覚
ただしこれは「直ちに使うな」という意味ではありません。フレームワークの良いところは、良くも悪くも六十点から八十点の間に収まりやすいこと。フレームワークなしで一から作ると、経験のない人なら三十点や四点になることもある。底上げはしてくれるが、百点までは届きにくい──これが「百点を取りたい時には使わない方がいい」という言葉の真意です。
フレームワークとライブラリの違いとは
議論の前提として、kuniwakはまず「フレームワークとは何か」を定義します。ここで言うフレームワークとは、部品を足す規格を決める側のこと。Railsならコントローラーやモデルの規格を決めており、ミドルウェアを足すときもRailsが決めた規格に合ったものを探してきてはめ込む、という関係です。
一方で、ライブラリは部品側にあたります。つまりフレームワークにとって、我々はライブラリを作る側になるわけです。
規格を決める側。部品をはめる場所が決まっている。カセットをはめる位置が固定されている。
規格を決められる側=部品。理想は「関数を呼ぶだけでいい」もの。好きなように組み立てられる。
ここで押さえておきたいのが、見る角度によって性格が変わるものがある点です。kuniwakはReactMeta(旧Facebook)が開発したUI構築用のJavaScriptライブラリ。コンポーネント単位で画面を組み立てる。を例に挙げます。アプリケーション全体から見れば、Reactを使わずにDOMを直接書くこともできるので、Reactはライブラリ的に見えます。しかしいったんUIの内部に入ると、JSXやuseState・useEffectなどはすべてReactの規格で決まっているため、ビュー層からはフレームワークとして立ち現れる、というわけです。
つまりフレームワークとは、規格をどれだけ強く決めてくるか=強制してくるかの度合いで「強さ」が決まります。そして強ければ強いほど、ビジネスの成功という観点では成功を目指しにくくなる、というのがkuniwakの見立てです。
脱フレームワークが難しい理由
現実の多くの現場では、ReactもRailsも何らかのフレームワークを使っています。そのツケ(技術的負債)を後から解消するのは、ゼロから一を作った人ではなく、後に入ってきたメンバーだったりします。ではどうやって剥がしていくのか──hentekoはここが難しいと指摘します。
kuniwakは、AIの登場で書き換えコストが劇的に下がったため、以前よりはやりやすくなったと言います。かつては「できない」という決断がほとんどでした。そのため、最初にフレームワークを選びやすい時代にもなった、とも。
脱フレームワークが難しい本質的な理由は、規格に合わせて部品を作ってしまったからです。その規格に沿った部品が自分たちだけの財産になっており、それを活用しようとすると「結局その規格を使った方が早い」となり、フレームワークから離れられなくなる、という構造です。
レゴブロックの規格に沿った形でレゴを作ってきているから、レゴ以外くっつけられないよね、という感じですね。
移行可能なように作っておけばよかった、というhentekoの喩えに、kuniwakも同意します。ただしフレームワークを使う以上、その部品の中で生きるしかなく、部品にはまるサブセットしか作れません。使う・使わないを選ぶことはできても、それは「相当厳しいゲーム」だと語ります。kuniwak自身の理想は、ライブラリをうまく使い、自分たちが規格を決めるという主導権を握ることにあります。
AI時代にフレームワークは必要か
hentekoは、AI登場以前のフレームワークの利点を振り返ります。少ないコードを書けば、いい感じのAPIが生えて動く──それが利点でした。しかし現代のAIでは、数行書いて動かすようなことはフレームワークなしでもAIに頼めばできる、と気づいたと言います。であれば、できる限りバニラで、ライブラリを選定した上で「どう構築するか」に人間が重きを置いた方が良さそうだ、と共感を示しました。
kuniwakはここで良い面も悪い面も整理します。バニラ寄りの選択が取れるのは、部品の分け方や選定眼が鍛えられた人。そういう人が百点を目指すならフレームワークを使わない決断がいい。しかし、ジュニアを率いて広げていくケースでは、依然としてフレームワークを使う方がいい場面が残っています。
| 状況 | おすすめ | 理由 |
|---|---|---|
| ジュニア中心のチーム | フレームワーク | クラスの分割などを強制してくれ、開発速度を上げる |
| シニアが集まる/百点狙い | バニラ+ライブラリ | 尖った要求を実現でき、インターフェースを自分で握れる |
| ゼロ→一で高速に作って捨てる | 組み合わせで簡単なら使う | ただし簡単に作れるアイデアは他社もやっている点に注意 |
フレームワークが取り込む要望は「みんなにとって平均的にいい」ものです。民主的に決まるため、尖った要求は入りづらい。ところがビジネスで他社を出し抜きたいときは、その尖ったことをやらねばならない場面が多く、そこでフレームワークが足かせになってきた──kuniwakはそう語ります。だからこそフレームワークのアダプター職人をやめ、ライブラリを直接使う人になった。コツをつかむと、平均的なユースケースではなく「自分だけのユースケース」を満たせばよくなり、インターフェースを雑にできる。これが開発速度を上げ、百点に近づく部分だといいます。
AIの現状についても言及があります。kuniwakの観測では、現在の生成AIはまだ設計が下手で、部品の分け方が拙い。工夫なしに「よろしく作って」と頼むとその傾向が出ます。だからこそ、生成されたコードの設計がひどいと見抜けるスキルは依然として重要で、すべてを丸投げできるフェーズではない、というのが結論です。
依存の話も重要な論点でした。依存が増えるほどアップデートは頻繁になり、脆弱性も入り込み、サプライチェーンアタックソフトウェアが依存する外部ライブラリなどに悪意あるコードを仕込み、それを利用する多数のプロジェクトを間接的に攻撃する手法。のリスクも高まります。今は「依存が多いほど不利な時代」になってきている。AIがテストまで書いてくれるなら、ライブラリを使わずハードコードした方が得な場面もある、とkuniwakは述べます。ちなみにAIは何も指示しないとCobraGo言語でCLIツールを作るための定番フレームワーク。多くのOSSで採用されている。のようなCLIフレームワークを真っ先に落としてくるため、あえて「こちらの方が成功できる」という一貫した思想を注入してやる必要がある、とも語りました。
TypeScriptだけが別格な理由
ここでhentekoが投げかけたのが「JavaScriptでいうTypeScriptはどうなのか」という問いです。kuniwakは、自分がnpmJavaScript/Node.jsのパッケージ管理ツール。ライブラリの追加・管理を行う。で真っ先にインストールするのはTypeScriptと型定義ライブラリくらいで、あとはほとんど入れない、と答えます。TypeScriptは「ちょっと別格」な存在なのです。
なぜ別格なのか。TypeScriptにはフレームワークの悪いところ=制限が出ていないからです。TypeScriptは「型検査が通れば動く」という健全性よりも、「動くものは型検査が通る」という完全性を重視した言語だとkuniwakは説明します。だから大抵の動くコードはTypeScriptで書けるし、なんならanyで逃げることもできる。JavaScriptの関数呼び出しもライブラリもそのまま使えるため、言語の自由度が損なわれていません。
型検査が通るものは動くことを保証。厳格だが自由度が下がりがち。
動くものは型検査が通る。自由度が保たれ、素のJavaScriptの力を制限しない。
対比として挙がったのがCoffeeScriptかつて流行した、JavaScriptに変換(トランスパイル)される言語。簡潔な記法が特徴だったが、TypeScript普及後は下火に。です。JavaScriptでできることは大体できるものの、素直にJavaScriptのコードを読めなかったりと、どこかで言語の力を制限していた。その制限がない方が好ましい、というのがkuniwakの立場です。ただしTypeScriptについても、enumやネームスペースのような「余計な機能」はいらないと感じており、消せばいいのにと思いながら使ってきた、とも語りました。
C・Rust・Goの立ち位置
話は言語論へと脱線していきます。kuniwakは、フレームワークの強さと似た尺度が言語にもあると言います。それは他の言語で書かれた関数をどれだけちゃんと呼べるか。この意味で最強なのがC言語1970年代に誕生した低水準言語。OSや多くの言語処理系の基盤で、他言語からの呼び出し規約の事実上の標準になっている。で、どの言語からも大体呼べるように作られています。正確には、各言語が「C言語は呼べるようにしておこう」と足並みを揃えた結果です。
ただし「全部C言語で書こう」という話にはなりません。kuniwakは「自分の足を撃ち抜く未来しか見えない」と即答します。自由に書ける中でも「やっちゃやばい領域」があり、それをどれだけ守ってくれるかが大事。明らかにエラーを吐くコードは許してほしくない──これがJavaScriptではなくTypeScriptを使う理由と同じ発想です。Cは「速さを要求したなら危険も引き受ける」言語なので、性能が本当に必要なときにこそ使う、という整理でした。
| 言語 | 狙う領域 | 性格 |
|---|---|---|
| C / C++ | カリカリの性能 | 速い代わりに、自分の足を撃ち抜かない責任は自分持ち |
| Rust | 安全+高性能 | C/C++より安全。メモリ解放タイミングを型で制御 |
| Go | 素朴に動く(C的領域) | 制約を気にせずストレートに書けて動く |
kuniwakが普段RustMozillaが開発した高性能かつ安全性を重視するシステムプログラミング言語。所有権やトレイトの仕組みでメモリ安全を保証する。をあまり使わずGoGoogleが開発したシンプルさを重視する言語。ガベージコレクションを備え、素朴に書いて動かすことに向く。を使う理由もここにあります。Rustはカリカリに速く書け、C/C++より安全ですが、そこまでの安全性が必要ない場面が多い。インクリメンタルGCがあれば、少しCPUを食っても止まらずメモリリークもしない。それで十分だ、というわけです。
RustのトレイトRustにおける型の振る舞いを定義する仕組み。メモリの解放タイミングや、ヒープ/スタックの配置などを制御する際に関わってくる。も、ヒープに置くかスタックに置くかといった決定を常に迫ってきますが、その決定が自分のアプリケーションでは重要でないことも多い。それならストレートにやりたいことを書いて動く方がいい、とkuniwakは述べます。RustはもともとFirefoxのためにCから置き換える文脈で生まれた言語であり、メモリ制約が強い場面や速さが本当に大事な場面でこそ生きる──やるプロダクトによって選定すべき、という結論に落ち着きました。
アーキテクトに残る「意思決定」という仕事
一連の議論を貫く筋は、「自分のプロジェクトは自分で意思決定し、技術選定を抜かりなく行う」という点にあります。言ってしまえば当たり前ですが、安易にフレームワークを選ぶな、というのが強い思想として立ち上がります。
AIと付き合う中でkuniwakが大事だと感じているのが「実現しすぎない」ことです。AIは「これもできますよ、やりましょうか?」とすぐ提案してくるが、その提案は大体余計。欲しい機能が百あるとして、八割で止めておくとちょうどいい保守性になり、実現すべきことは実現されている。この八割をどう見極めるかが重要だといいます。パフォーマンスチューニングを頼むと「ここもやりましょうか?」と言ってくるが、そこをチューニングすると変更容易性やテスト容易性が下がる──そういうときは「やめろ」と止めに入る勘所が必要です。
こうした勘所が成立するのは、人間が痛い目を見てきたからです。AIはまだそのコンテキストを自覚していません。ここでkuniwakが会社で紹介されたという「プレモーテム」という概念が登場します。
「この設計にしようと思うが、これで何が起こる?」とAIに事前に問うと、「このままいくとこう破滅する」という予測がコンテキストに乗り、比較的いい選択肢が出やすくなります。hentekoは、これは技術選定時に複数案を比較検討するADRArchitecture Decision Record(アーキテクチャ決定記録)。どの設計案を、なぜ採用・却下したのかを文書として残す手法。に近いと指摘し、kuniwakも同意。アーキテクトは未来を見ながら意思決定しており、今のところAIは近視眼的でコンテキストが小さいため、そこがまだ人間に残された仕事だ、と語ります。
もっとも、AIのコンテキストが人間並みに広がれば話は別です。kuniwakは自身の三十八年分の記憶が意思決定に活きていると述べ、それをAIが保持できるようになった瞬間には「あなたの方が正解だ」となる、と冗談交じりに認めます。ただし、それには人間の脳並みの圧縮率とエネルギー効率が必要で、まだ難しい、という見立てでした。
まとめ
最後にkuniwakが挙げた「一番過激な言い回し」が、この回のタイトルにもなっています。フレームワークは補助輪だ、という表現です。
あくまでこれは補助輪であって、加速装置ではないんだぞ、というところですね。エンジンはお前自身なんだから頑張れ、みたいな。
henteko自身、当初は「フレームワークを使うな」という過激派の主張として受け止めていましたが、話を聞くうちに、依存関係を減らす、プロジェクトの意思決定を自分で握る、アーキテクトとして未来を見て判断する──その根っこにある思想には強く共感できたと振り返ります。過激というより、むしろ堅実な技術論だった、というのがこの回の着地点でした。
- フレームワーク=規格を決める側、ライブラリ=決められる部品側。規格の強制が強いほどビジネスで百点を目指しにくくなる。
- フレームワークは六十〜八十点への底上げはするが、アップデート追従や依存増加が本質的でないコストを生む。
- ジュニア中心のチームには有効だが、選定眼のあるシニアが百点を狙うならバニラ+ライブラリで主導権を握るのが速い。
- TypeScriptは「動くものは型が通る」完全性を重視し、言語の自由度を制限しないため別格に扱える。
- C・Rust・Goは狙う領域が異なり、性能や安全性の必要度に応じて選定すべき。全部Cで書くのは危険。
- 依存が多いほど脆弱性・サプライチェーン攻撃・追従コストで不利な時代。AI時代はハードコードが得な場面もある。
- 「実現しすぎない」「プレモーテムで未来を予測する」など、未来を見た意思決定が人間=アーキテクトに残された仕事。
- フレームワークは補助輪であって加速装置ではない。エンジンはエンジニア自身。
