退屈な技術(Boring Technology)
次々と新しい技術が生み出されるソフトウェア開発の時代において、名作記事であるChoose Boring Technology(退屈な技術を選べ)を一緒に振り返ってみたいと思う。
開発において、僕たちは言語の選定が時代遅れだと不平を漏らしがちだ。「PHPのクソコードは全部RustやGolang、あるいは思いつく限りのモダンな言語でリライトすべきだ」「データベースにPostgresやMySQLを使うなんて時代遅れだ。大規模トラフィックをさばくにはMongoやDynamoDB、Cassandra、Neo4jを使わなきゃダメだ」といったように。
「新しい技術を導入すれば」既存の問題を解決できるという考えは、大抵の場合、開発者がまだ十分に考え抜けていないことを意味しているに過ぎない。しかし、このことに気づくには通常、時間の蓄積が必要だ。新技術に触れて目を輝かせていた少年から、油ぎった顔の中年のおじさんになるまでの時間が。
理解できない開発者にこの話をしても、新しいことを学びたくない老害の戯言だとしか思われないだろう。だが、数々の浮き沈みを経験し、「山は山、水は水」という第3の境地に達したからこそ、退屈な技術こそが往々にして最高の技術であると分かるのだ。
僕たちは本能的に退屈を嫌う。退屈は停滞や新鮮味の欠如を意味するからだ。しかしソフトウェアの世界において、「退屈」とは安定、成熟、そして実戦で検証済みであることを意味する。技術がもたらすスリルや刺激は、運用コストという代償を払って手に入れていることが多い。
Vercelの積極的なプロモーションもあり、多くのSaaSがフルスタック開発にNext.jsを採用している。LLMやVercel独自のプラットフォームの強みと組み合わせることで、プロダクトを迅速にローンチし、ストレスなくデプロイできるのは確かだが、同時にそれがもたらす複雑さにも気づかされた。
例えば、Reactコンポーネントを書く際にフロントエンドとバックエンドの違いを理解しなければならない複雑さや、Server Actions / Server Component / Client Component の使い分けなどだ。これらはすべて、彼らが主張する「より良いUX」を実現するためのトレードオフである。
Vercelが悪いと言っているわけではない。Next.jsとの統合は非常によくできており、SSG/SSRをサポートし、純粋な静的生成にも対応している。SSR版では、サーバーが必要なNext.jsの関数を自動的にEdge Functionsに変換し、自動デプロイ、ロールバック、実用に足るログやアラートシステムを提供してくれる。これらは非常に役立つ機能だ。
しかし欠点が全くないわけではない。要件が徐々に複雑になるにつれ、ライブラリの選定だけでも相当頭を悩ませることになる:
- 権限管理
- フォームバリデーション
- JWTなどの認証認可の実装
- データベースのマイグレーション管理
- WebSocketやSSE
- Background Job / Scheduled Job / Cron Job などの非同期処理機構
あるいは、Edge Functionsとローカル開発環境との差異を認識させられ、一部のコードの挙動がまったく異なってしまうこともある。
自由な選択肢があるとも捉えられるが、立ち上げたばかりの企業や開発者にとって、こういった部分でハマって時間を浪費することは、確かに面白い体験ではあるものの、プロダクトを世に出す必要がある企業にとっては決してコスパの良い選択ではない。多くのフレームワークは、かなり早い段階からこれらの問題を解決済みだ。前述したような仕組みは、Django、Laravel、Ruby on Railsならすべて標準で備わっている。
僕の現在の仕事内容を例に挙げると、画像処理を多く含むためCPUバウンドな処理の最適化が必要で、最終的にはAWS SQSを使って解決したが、それ以外の部分はすべてDjangoの組み込み機能で実装している。Djangoの非同期サポートはそこまで強力ではないものの、確実に多くの時間を節約してくれた。また、デプロイも非常に注意を払うべきポイントだ。放っておくと簡単に複雑化してしまうからだ。
では、もし僕が選ぶとしたらどう選ぶかについて話そう。僕が考える「退屈なフレームワーク」が備えるべき要件は以下の通りだ:
- ビルトインで完全なDatabase Adapterとマイグレーション機構を備えていること:見落とされがちだが、マイグレーション機能の存在は極めて重要だ
- これは時に諸刃の剣でもある。例えば一部のDBでUUIDの実装がない場合、アプリケーション層でUUIDを生成してDBに書き込む必要が出てきたりする
- 上記に関連して、便利で柔軟なORM:DjangoやRuby on Railsのモデルは非常に快適に書ける。同時に、必要な時にはRaw SQLクエリを発行できる能力も備えている必要がある。ORMによる抽象化や柔軟性の欠如を嫌う開発者が多いのは知っているが、それがもたらす利便性とメンテナンス性をむげに無視するのは現実的ではない。
- ログインおよび権限管理機構:少なくともAPIレベルで権限管理ができること。例えば(Djangoを例に挙げると):
# 在 request 過來時會根據設定的 permission 控管
class MyProfileAPIView(APIView):
permission_classes = [IsAuthenticated, xxxGroupPermission]
- バックグラウンドジョブの統合機構があること:Djangoでよく使われるCeleryや、Ruby on RailsのActiveJobのようなもの
- キャッシュをサポートしているか:アダプターがあり、インメモリやRedisを自由に切り替えられるのが理想だ
- WebSocketの抽象化をサポートしているか:例えばDjangoのChannelsや、Ruby on RailsのAction Cable
- WebSocketの要件というのは、時として突然湧いて出てくるものだ
- ローカル環境で簡単に動かせるか
- 組み込みの管理画面生成機能があること:ModelとUIオプションを定義するだけで管理画面が生成される
class File(MyModel):
device_id = models.CharField(
max_length=255,
verbose_name="設備ID",
null=True,
blank=True
)
admin.site.register(File, FileAdmin)
こう書くだけで、Djangoは自動的に対応する管理ページを生成し、データベース内の値を編集できるようにしてくれるし、簡単なカスタマイズも可能だ。正直に言って、この機能は後になって極めて重要だと気づいたものだ。
開発者にゼロから管理画面を作らせたら、技術選定だけでもしばらく時間がかかる。さらにフロントとバックエンドを分離しようものなら、UI、API、データベースの繋ぎ込みにまた時間を取られることになる。それに比べてDjangoは、画面こそ素朴ではあるものの、Modelを宣言するだけで作業の90%を削減でき、しかも完全に正しく動作することが保証されているため、極めて便利な機能だ。
どんなフレームワークにも多かれ少なかれ限界や欠点はあるが、僕が考える「優れた退屈なフレームワーク」は以下の7つの特徴を備えているべきだ:
- ✅ 非同期または軽量並行処理(グリーンスレッド / コルーチン)をネイティブサポート
- 🧱 安定したデータベース統合とマイグレーション機構**
- 🧩 使いやすく、かつ強制されないORM(Raw SQLを自由に使用可能)
- 🔐 組み込みのログインおよび権限管理機構
- ⚙️ バックグラウンドジョブやスケジューリング機構の統合(Celery / ActiveJobなど)
- 🪄 管理画面UIの自動生成(Django Adminなど)
- 💾 充実したキャッシュとWebSocketサポート
華やかな技術は人目を引くが、荒波を乗り越えて生き残り続けるのは、いつだって退屈で信頼できる選択肢だ。
後記
DHHはRails WorldのKeynoteで、現在のWeb開発の状況はあまりにも複雑すぎると言及していた。以前ならSFTPでドラッグ&ドロップするだけで即座にリリースできたのに、今ではCI/CDを回すだけで15分もかかる。DHHの意見に完全に同意するわけではないが、Web開発者なら誰しも一度は「複雑すぎるのではないか」という思いを抱いたことがあるはずだ。
関連記事
- エンジニアの面接にどう備えるか テック業界の面接対策はいつだって骨の折れるものだ。面接で最も人を落胆させるのは、権力関係が極めて一方通行になりがちな点にある。応募者の立場では相手の本当の基準を読み取るのは難しく、面接が終わった後は自分を疑ってしまいがちだ。今回はそのあたりについて話してみよう。
- 人生観を変えた言葉 ファインマン、チャップリン、そして映画『ひゃくえむ。』。劣等感を抱えていた少年から誰かを助けられるようになるまで、僕に最も深い影響を与えた思考と生き方についての共有。
- 独立したウェブサイトを持つN個のメリット ショート動画やSNSが全盛のこの時代に、なぜわざわざ時間をかけて自分のブログを運営するのか?約10年間ブログを書き続けてきた僕の考えを共有する。
- 筋トレ(ウエイトトレーニング)の記録と感想 ここ最近の筋トレの振り返りと感想をシェアする。