右上↗

プログラミングに関するメモをのこしていきます

フレームワークを作れる人に憧れながら、ユーティリティを作る

エンジニアとして働くにあたって、無意識に気をつけていたことを自覚するたびに、言語化しておきたいなと思うようになりました。 今日はフレームワークを作らないようにしている話を書いてみます。 (個人ブログを育てていたのですが、なんとなくはてなブログに復帰することを検討しているので、こっちに書いてみる)

なぜフレームワークを作らないのか

フレームワークの定義は正直いまだに厳密にはよくわかっていませんが、ここでは「その仕組みの上に乗っかってプロダクトコードが書かれるような基盤となる仕組み」全般をフレームワークと呼びます。(Reactは自称libraryですが、このブログではあれはフレームワーク扱いしたい、くらいのふわっとした独自定義でいきます。そもそもグラデーションなので、あまり厳密なものでもありません。)

なぜ僕がフレームワークを作らないようにしているかというと、すごく単純な話で、自分でフレームワークを作るには能力が足りていないと思っているからです。フレームワークを作るのは、非常に難易度が高いのです。もう少し正確に言うと、「フレームワークを作って、それを継続的にチームで運用し続けること」の難易度が非常に高いと思っています。

「運用」という言葉もニュアンスが広いのですが、ここでの「運用」には、そのフレームワークが(当初の思想を理解したうえで)正しい方向に進化していくための改善活動も含んでいます。

オレオレフレームワークに苦しめられる、みたいなのはあるある話だと思います。自分自身はそこまでひどく苦しんだ経験はありませんが、類似のケースには何度か触れてきました。

フレームワークには思想が必要

フレームワークには思想が必要です。思想なきフレームワークは、すぐに崩壊するものです。

フレームワークと呼べるくらい “仕組み” になっているものは、フレームワークの内部で解決される、暗黙(ユーザーから見て)の挙動をそれなりに含んでいます。

思想の伝わらないフレームワークは、ユーザーから見ると、ブラックボックスの中で何が起きているか・何をやってくれているのかを想像することが難しくなります。

本当にブラックボックスとして扱って構わない場合は、ブラックボックスの中で何が起きているかをユーザーが知る必要はないのですが、思想が伝わらないフレームワークだと、ユーザーは「フレームワークに何を任せたらいいか」の判断が適切にできなくなります。

結果として、本来フレームワークを拡張することで解決すべき問題をユーザーランドで無理矢理に解決してしまったり、逆にユーザーランドで解決すべき問題をフレームワークの中に持ち込んでしまったりします。前者はフレームワークの恩恵がどんどん薄れていくことを意味するし、後者はフレームワークの複雑さを招き、この問題をより加速させる結果に繋がります。

自作フレームワークを正しく運用するために必要なもの

フレームワークが正しく運用されるには、以下のどちらか(あるいは両方)が必要です。

  1. フレームワークの思想と正しい運用方法を普及する活動にコストを割く
  2. 運用が自走するくらい直感的に動く & 思想が簡単に浸透するフレームワークを作る

1. フレームワークの思想と正しい運用方法を普及する活動にコストを割く

「1. フレームワークの思想と正しい運用方法を普及する活動にコストを割く」は、その重要性は言わずもがなです。

ドキュメンテーションやオフィスアワーの開催など、いろいろな打ち手が考えられます。

ここで重要なのは、自作フレームワークを作った場合、これをやるのは作者しかいないということです。

世間一般で使われているフレームワークであれば、公式のドキュメントを頼ることもできますし、世間にあふれるユーザーの声を頼ることもできます。

社内に閉じた自作フレームワークの場合は、これができません。

作者自身がまず利用者になるだけでなく、伝道師になる必要があるのです。

詰まったときにググっても何も出てこない自前フレームワーク v.s. ググればいくらでも事例が出てくるOSS、というイメージです。(実際にはそこまで自明な状況で自作フレームワークを作ることは現実ではあまりないと思いますが)

また、先に述べたように、フレームワークには思想が必要です。チームでメンテナンスする対象としてのフレームワークという文脈においては、さらにその思想をちゃんとチーム内に伝導することが非常に大切です。どのような思想に基づいて足場が設計されているのか、を知らない(または勘違いした)状態で、足場の”改善”をしようとすれば、より脆い足場が作られることになります。

思想の伝導には、単に使い方レベルの説明をするだけでは足りません。ADRのように、アーキテクチャ上の意思決定の履歴を残す取り組みが普及してきていますが、フレームワークについても同様に「どういう状況下で、どういう課題を、どう解こうとしたからこういうフレームワークになったのだ」ということが伝わるようにしなければなりません。

誰もついてこれない思想なら、その思想はそのチームにはフィットしていないし、そのフレームワークはチームにとってプラスではありません。ついてこられるように伝導するコストを払いましょう。

(ここでは、フレームワーク自体の「実装が難しくて」作者にしかメンテナンスできない、という問題は無視しています。それは単にチームの技術力不足であり、ここで取り上げたい問題とは別のものです。往々にして、メンテナンスできなくなる要因は、実装が高度なことではありません。)

当然のことながら、これらのコストを払う価値があると判断している場合は、話は別です。

例えば、一般的な解法ではプロダクトの提供したいレベルのUXがどうしても実現できず、そのUXを提供することこそがプロダクトの競争優位になる、と判断している場合などです。

その場合は、ドキュメンテーションやそのメンテナンスコストを支払うことを前提に、フレームワークを作りにいくべきです。

(一方で、そんなケースは非常に稀だろうとも思っています。)

2. 運用が自走するくらい直感的に動く & 思想が簡単に浸透するフレームワークを作る

「2. 運用が自走するくらい直感的に動く & 思想が簡単に浸透するフレームワークを作る」も非常に重要で、「フレームワークを作れるに人に憧れながら」と題してこのブログを書いているのは、確かにこれができる人というのは存在するし、目の当たりにしてきたからでもあります。

絶妙な薄さ、絶妙な API、絶妙な柔軟性と規約のバランスなどが噛み合っているときしか達成し得ないことです。

Example を見ただけて直感的にどういうことをしてくれるフレームワークか伝わる、やりたいことのほとんどがフレームワークによって考慮済みである、といった条件が整えば、そのフレームワークはどんどん使われていくことになるだろうし、フレームワーク自体にガタが来ることも少ない(大量の変化を必要としない、健全に進化する)はずです。

ただし、これは明らかに難易度が高いです。スキル・経験・センスすべてがものをいう世界だと思います。

後ろ向きな発言ですが、僕はまだこれに自信と責任を持つことはできません。

これらの2つの理由から、フレームワークを作ることは避けるようにしよう、というのが僕のエンジニアとして心がけていることの一つです。

では効率化を試みることは悪なのか

当然ながらそんなことはありません。僕は以下の二点を心に留めるようにしています。

フレームワークなんて作らなくても効率化はできる

フレームワークと呼べない程度の、小さな Utility / Helper の集合を作ることは、どう転んでも害になりにくいものです。

勘所が悪いと、想像より益をうまない Utility を作ってしまうかもしれませんが、そういうものがあったとしても、多くの場合は、少しコードサイズが膨らむだけですみます。

Utility 程度であれば、ドキュメンテーションもそこまで頑張る必要はありません。普通に KDoc なり TSDoc なりを書いておけば十分です。

Example も、自動テストとして残しておけばよいので、コストは掛かりません。

小さいに Utility そのものに思想はそこまで現れません。(これは少し嘘かもしれません。強い思想がにじみ出る Utility というものは存在しますね。 Kotlin の let  なんかは個人的には思想が現れている Utility の一例に感じます。)

さらにいえば、小さな Utility を合成して積み重ねていくことによって、実質的にフレームワークと呼べるような機構に育つこともあるかもしれません。

このケースは、ある意味では危険信号(局所最適に陥っている可能性)かもしれませんが、理解しやすいブロックの合成で構築されたフレームワークは、それ自体が理解しやすいものになりやすいはずです。少なくとも中をブラックボックスとして扱わなくていい程度には。

挑戦をしないとフレームワークが作れるようにはならない

さっきはフレームワークを作らないようにしていると書きましたが、僕も一ソフトウェアエンジニアとして、スーパー使いやすくて生産性の高い “フレームワーク” と呼ぶにふさわしい仕組みを作ってみたいと常々思っています。

最初からきゅぴーんと閃いてフレームワークを作れる人もいるのかもしれませんが、小さい成功体験を積み上げてパターンの引き出しを増やすことで、少しずつフレームワークを作れるエンジニアになっていくというパスが自分には向いているのかなと思っています。

自分が過去に見てきた “仕組みを作れる人” たちも、最初から完璧なものを作っていたわけではなさそうでした。小さく作ってFeedbackを受けながら育てていたり、一気に作って個人で利用する中で反芻して改善したものをリリースしていたり(当たり前ですが)

何にせよ、そういう経験を踏まなければパターンの引き出しが増えず、仕組み化できるものを仕組み化するスキルがないままになってしまいます。自分の許容ラインを少し超えるくらいのアグレッシブな仕組み化に挑戦し続けていきたいなと思います。

まとめ

大仰な仕組みを作っても、チームがついてこられないと不幸を呼ぶので、

  • チームがついてこられるように布教活動をきちんとやる
  • チームがついてきやすいよう、思想や実装がわかりやすい筋のいい仕組みを作る

の二点に気をつけましょう。

そしてそれらをきちんとやるのは非常に難しいことを理解し、大仰な仕組みを作らなくて済む解決方法(Utilityを提供する程度に留めるなど)も検討しましょう。

ただし、巨大だけど筋のいい仕組みを作れるソフトウェアエンジニアになるためには、その領域に挑戦することが必要なので、バランスを見つつ挑戦していきましょう。