注意:本稿にはあまり一般的ではない(かもしれない)筆者の独自思想がふんだんに盛り込まれています。これを受けてどう考え、行動するのかは自己責任でよろしくおねがいします。
ソフトウェア開発に銀の弾丸なし、という言葉は広く市民権を得ています。多少なりとも開発の経験がある方ならばこれに異を唱える人はいないでしょう。
しかしそんな我々もアーキテクチャ(多くの現場でこれはフレームワークの選定と同義語である)の話になると無意識のうちに「最強の何か」を想定して思考してしまいがちです。そうだよね?
なので未来の自分へのメッセージもかねて、いまここではっきりと宣言しましょう。 この世界に最強のアーキテクチャは存在しません。各プロダクトに合わせた最適が存在するだけです。
にんにくの存在
とはいえ先の僕の宣言を完全に鵜呑みにして、要件に合わせてプロダクトに必要なものを一から自作していくのがベスト!という結論に飛び付くのは安易です。
作ろうとしているものがありがちな仕組みに乗っかれるのであれば既製品を流用しましょう。
例えば動画のエンコードだとか……絞られた目的、機能であれば良い選択肢が無数にあります。
他にもWebサイトを作成、という曖昧模糊とした要件であってもWordPress、Ruby on Rails、NextJS……この辺の大衆的フレームワークにはありがちな課題を解決するための道具がたくさんついています。
この手のDSLはVictorinoxの万能ナイフと同じで、ハマる用途に限定して使う分にはとても便利です。
つまり対象とその対処が明確なのであれば、にんにくや十字架を駆使して退治できますよ、という話です。
もっとぶっちゃけて言えば、こいつらはリッチになったノーコードツールです。
上手に使えば高い効力を発揮しますが、複雑なことをしているとどこかで限界がきて中のコードを読んだりパッチを書いたりしないといけなくなります。
DIY
しかしありあわせのおまじないが通用しない怪物も存在します。
僕はフロントエンドをメインで担当していますが、よくあるWebアプリのフォームよりもBIツールや管理画面の類を担当することのほうが多かったです。
この手のツールは扱うデータの量や複雑性が大きくなりがちなので、よくある要件を定型文で書けるようにしているリッチDSLのようなフレームワークは力不足で、あっという間に抽象化の漏れが生じます*1。
僕はよくRedux(や、そのフォロワーライブラリ)のことを「メタフレームワーク」と呼んでいます。
Redux系のライブラリは特定の書き方を強制することがありません。というより、ここを未だに誤解している人が多いですが、本来のReduxはほぼなんの機能も提供していません。
ただ思想のみが存在しており、それをどう実現するかは各プログラマーの手腕に委ねられます(最近は各種toolが充実してきましたが)。
僕がフロントエンドでReactおよびRedux系統を好むのは、プロダクトの要求する複雑度に応じて都度最適なフレームワークを自分で構築する余地があるからです。
課題の複雑さ、あるいは特殊性がある閾値を超えたら要件に応じたアーキテクチャを組むべきだというのが僕の考えです。
少なくともなんでもかんでも素朴なMVXやDDDの表面だけをさらったアーキテクチャというなのディレクトリ構成で解決しようとするのはやめましょう
これには異論反論のある方がほとんどでしょう。
Reduxが理解されずにmobx(は早々に消えましたが)やVueのようなライブラリが好まれることからも明らかです。
しかし既存のソリューションの、そのまたコード片をつぎはぎでどうにかなる範囲というのは一般に考えられているよりは限定的です。
フレームワークの自作のすすめ
ここまでで
流行りのフレームワークは「あるあるパターンをまとめたDSLの集合体」に過ぎないことが多い
複雑なプロダクト開発において、そういった既製のフレームワークはそれほど役に立たない
モノリシック一辺倒の反省から産まれたグルー系フレームワーク、そしてその次のメタフレームワークとでも言うべき潮流が存在する
ということがわかりました。 そこから導き出される結論は必要なアーキテクチャの考察、そしてフレームワークの自作です。
「自家製フレームワーク」
このワードを耳にした瞬間、鼓動は跳ね上がり手の震えが止まらなくなるプログラマーは多いはずです。かくいう僕もその一人です。
しかし一方で、プロダクトの複雑度が一定の範囲を超えた瞬間に、既製品のフレームワークはその輝きを失います。当初は空を飛ぶとりもかくやとおもわれた生産性は地を這うようになり、過去の全てが負債として立ち上がってきます。
ここを軽視される方は多いですが、全てのプロダクト開発はユニークなのです。
ベンチャー企業であればプロダクトそのものがユニークです。内容としては枯れた受託であっても、それを実装するときに主流な技術は違います。メンバーの得意な技術スタックやチームの開発スタイルも異なります。
既製品がこれらの条件全てを満たすことは残念ながら不可能です。
ゆえにフレームワークとは自作されるものなのです(自作すれば条件を満たせるかどうか、それはまた別のお話)。
RailsやDjangoなどかつて流行ったさまざまなフレームワーク達も、始まりはどこかの企業の自家製フレームワークでした。
一般的なアプリケーション構築のアーキテクチャパターンは出し尽くしかけているといってよいでしょう。
ゆえにちゃんとした実力のあるプログラマーが担当するのであれば、自作されたフレームワークがプロジェクト進行のボトルネックとなることはありません。
むしろプロジェクト規模に必要な機能のみを持たせているため贅肉が少なく、理解しやすいAPIとなっているはずです。
一から全部書かなくてもいい
とはいえ1から全てを書く必要はないです。
例えばNodeJSでいうと、NestJS(は余計な贅肉が多すぎますが)やnexusは既存のライブラリをうまく組み合わせてフレームワークとしています。
リクエストのルーティングやシリアライズのようなアーキテクチャを組む上であまり本質的ではない機能、あるいはORマッパーやクエリビルダなど作るのが大変なもの(data-loaderサポートとか型安全性を考えると以前より難易度は上がっている)はありものを使ってもいいでしょう。
もちろん書きたければHTTPサーバーやクエリビルダーを自分で書いてもいいですが……
自作のデメリット
いいことづくめのようにみえる自作フレームワークですが、無視できない欠点があります。
万が一、クソを作ってしまったときに被害が甚大になる可能性が高い、ということです。
Ruby on Railsのような超有名ライブラリであればダメな部分があったとしてもそれが広く共有されているため、回避する方法もググればわかることがおおい*2です。もしかしたらどこかの誰かがパッチを送って直してくれるかもしれません。
自作フレームワークだと、利用者は世界でお前のチームだけ。という感じになるのでまかり間違ってとんでもないコードを書いてしまうとドッカンバッカン大騒ぎでプロダクトがポシャる可能性だってなくもないです。
例えば有名どころなRailsはかなり思想が強いので、デフォでこの挙動するのやばくね?ってなることがあったりしますが、そのヤバ挙動の裏には数々の地雷を避けてユーザーをマイルドなクソへと軟着陸させてくれる優しさが隠されていたりする(らしい)です。
ところが全てを自由に書ける自作では全てを自分で制御できる反面、とんでもない地雷を踏む可能性があります。
また、オーダーメイドすることに意味があるので、フレームワークを設計する人間は業務の要件をしっかり理解してドメイン設計に落とし込まなければいけません。
それっぽくまとまっていても、やっていることが劣化Railsではプログラマーの自己満だと言われても仕方がありません。
自由を行使するには力が必要で、そこには責任が伴うという話ですね。
まぁ何度も言うように既存のフレームワークでどうにかなる範囲なんてタカが知れているので、大抵のプロダクトは数年運営しただけで半分自作のキメラになってしまいがちですが。
まとめ
万能なアーキテクチャパターンがどこかにあるという素朴な信仰を持っている人が多い
「gemやnpmのようなパッケージやプラグインを組み合わせてものを作る」というノーコード的な考え方が通用する規模はおもったよりも小さい
- どんなに良くできたフレームワークを使おうが、早晩リポジトリのissueをチェックしたり中のコードを読める程度の能力が必要になる。そして裁きの日は近い
自作フレームワークは自分達が必要な機能しか搭載しないので"理論上は"メンテもアップデートも比較的に簡単
- 自作自体はそれほど難しくはない
大いなる力には大いなる責任が伴う
「Webフレームワーク」といえば印象に残っている出来事があります。
Goがでてしばらく、色んな人がいろんなフレームワークを作ったり、試したり比較したりしていました。
でもGopherの多くは「いや、標準のhttpで機能は十分なんだから普通にコード書けば良くない?」と言い続けていたんですよね。
この「普通にコード書けば良くない?」っていう考え方は多くの示唆を含んでいるんじゃないでしょうか(深読みかもしれないですけどね)。
DDDが既存のフレームワークに依存するな、と言っているのもそうでしょう。
ありものは広く使われるためにどうしても余計な機能がついてしまいます。機能は最小限に、必要なものだけ、普通にコード書けば良くない?エヴァンス先生もきっとそう言いたかったんだとおもいます。たぶん。
それが難しいんだけどな!!!!
以上です。