2013年、私はBluLogixでフルスタックJavaを書いており、Google Web Toolkitを使ってJavaScriptにコンパイルし、Spring SecurityをAuthのために配線し、テレコムオペレーター向けのクラウド課金プラットフォームを出荷していた。TypeScriptはまだ1.0になっていなかった。Reactは Facebook内部のものだった。Node.jsはブログ記事を書く対象であり、課金システムを出荷するプラットフォームではなかった。

知らないまま、デフォルトになる十年前に型安全なフルスタック開発をやっていた。

GWTが実際に何だったか

Google Web Toolkit(GWT)は大胆なアイデアだった:フロントエンドをJavaで書き、GWTコンパイラを走らせ、最適化されたJavaScriptを得る。薄いラッパーではない。JSXの類似物でもない。Java — クラス、ジェネリクス、インターフェース、完全な型システム — がブラウザで動くJavaScriptにクロスコンパイルされる。

これはGoogleがそれを必要としていたから機能した。GmailはGWTで作られた。Google DocsはGWTで作られた。Googleはコンパイラに本格的なエンジニアリングを注ぎ込んだ — デッドコード除去、コード分割、ブラウザターゲット全体にわたるパーミュテーションベースの最適化 — そして驚くほど効率的な出力を生み出した。出力JSはブラウザごとにminifyされてパーミュートされたので、IEは一つのアーティファクト、Firefoxは別、Chromeはまた別になった。それについては気にしなくて良かった。コンパイラが処理した。

私のようなチームへの価値提案はすぐに明確だった:バックエンドを守っているのと同じ型システムがフロントエンドを守っていた。 APIがBillingCycleオブジェクトを返せば、UIコードはすべてのフィールドが型付けされたBillingCycleオブジェクトを受け取り、コンパイラはビルド時にすべての不一致をキャッチした。JSONの形のミスマッチはない。「そのフィールドはStringだと思っていた」はない。誰かがバックエンドDTOのプロパティ名を変えてフロントエンドのfetch呼び出しを更新し忘れたことによるランタイムの驚きはない。

2013年、これは本当に珍しかった。他の全員はjQueryコールバックを書いて祈っていた。

静的型付けのために払った代価

GWTは無料ではなかった。コンパイラは遅かった。「数秒余分に」という遅さではない — 中規模のGWTアプリのコンパイルサイクルは2分から5分かかった。インクリメンタルなdevモード(ホストされたブラウザでアプリを実行してJavaバイトコードをホットスワップする)は助けになったが、脆かった:devモードと本番コンパイルが微妙に乖離することがあり、devブラウザが決して試みなかったパーミュテーションで壊れるものを出荷してしまった。

ウィジェットモデルはJavaスタイルのオブジェクト階層だった:抽象基底クラスを拡張するGwtWidgets、イベントハンドラーインターフェース、JavaクラスにマッピングするUiBinderXMLテンプレート。これは2013年のJavaエンタープライズカルチャをUIに適用したものだ。SwingやJSFから来た人には自然に感じられた。それ以外から来た人には異質に感じられた。

CSSは本当の闘いだった。GWTのCssResourceシステムは型安全なCSSクラス名を提供した — Javaコードは生の文字列の代わりにmyStyle.myClassName()を参照することができ、CSSクラス名の変更はサイレントな壊れではなくコンパイルエラーを生み出した。これは理論的には本当に素晴らしい。実践では、ツーリングがそれを取り囲むほど粗くて、なぜスタイルが適用されないかをデバッグするのに有意義な時間を費やし、間違ったCssResource型を参照していたとわかったことがあった。

Spring Bootが現れてギフトのように感じられた

2012年頃からSpring Frameworkを使い始めた — RESTエンドポイント用のSpring MVC、Auth用のSpring Security、SOAPサービス用のSpring WS(そう、SOAP、これはテレコム向けのエンタープライズJavaだった)。これはXML設定Springの時代だった:500行のBean定義、名前空間宣言、プロパティプレースホルダーを持つapplicationContext.xmlファイル。アプリケーションコンテキストと深い関係があった。すべてのBeanを名前で知っていた。

Spring Boot 1.0は2014年4月に出荷された。その頃私はAFAQにいて、早期に採用した — すべての設定問題にStack Overflowの答えが400もまだなかった頃だ。

Bootが行った変化は機能を追加することではなかった。セレモニーを排除した。自動設定はフレームワークがクラスパスから合理的なデフォルトを推測して実際に必要なものを配線することを意味した。@SpringBootApplicationはXMLの迷路を置き換えた。組み込みTomcatはコンテナデプロイを管理する代わりにjava -jarで実行することを意味した。application.propertiesはXMLの三分の一を置き換えた。

Spring Bootアプリをゼロから実行して、ドキュメントを読む時間を除いて10分以内に動くRESTエンドポイントを得た最初の時 — 何かが変わったと理解した。技術的に革命的ではない。哲学的に異なる。

GWT + Spring BootでのAFAQ EHRの構築

AFAQ(2014〜2017年)では、EHR/EMRスイートを構築していた — ウェブベースで、ERPモジュールと完全に統合され、VA VistAのコンポーネントの上にデプロイされた。技術スタック:フロントエンドはGWT、バックエンドはSpring Boot + Java EE、後ろにあるVistA MUMPSコンポーネントはサービスレイヤーの後ろ(その側については別の投稿がある)。

GWTとSpring Bootの特定の組み合わせはヘルスケアに対して実際にかなり良かった。理由はここだ:ヘルスケアUIは複雑で、ステートフルで、ハイステークスだ。 患者チャートビューにはネストされたタブ付きパネル、リアルタイムの検査結果フィード、セッション中にアップデートされる投薬リスト、リッチテキストの診察メモ、何かが変わったときに発火しなければならないアラートバッジがある。GWTのJava UIモデルはjQueryスパゲッティよりこれをうまく処理した。データが任意のJSONではなくAllergyRecordMedicationOrderオブジェクトのとき、型安全性は重要だった。

Spring Bootの積極的なデフォルトもAFAQで助けになった。チームは大きくなく、速く動く必要があったからだ。規約より設定はBeanのライフサイクルを議論する代わりにビジネスロジックを書くことを可能にした。

ペインポイントはビルドだった。フロントエンドでの完全なGWTコンパイル、バックエンドでSpring BootのMavenビルド、2014年当時のハードウェアで、クリーンチェックアウトからデプロイ可能なアーティファクトまで15分のプロセスだった。「何かが壊れるものをマージした」から「それが壊れていることを知る」までのフィードバックループが最低でも四半時間だったので、ビルドを壊さないことを規律立てて行う必要があった。

GWTが消えた理由とそれを置き換えたもの

GWTは2012〜2013年頃にピークに達し、その後JavaScriptが急速に良くなった。TypeScriptが登場し、GWTが常に売り込んでいた静的型付けをJavaScript世界に提供した。Reactがコンポーネントモデルを提供した。Webpackがコード分割を提供した。ビルドツーリングは劇的に改善した。そして決定的に:すべてのウェブエンジニアはすでにJavaScriptを知っていた。GWT JavaフロントエンドコードをかけるJavaエンジニアの プールは「Javaエンジニア」と「フロントエンドを書くことをいとわない人々」の交差 — 悪名高く小さいベン図だった。

GoogleはGWTへの投資を徐々に減らした。コミュニティが引き継いだ。GWTでの新規開発は今ではニッチの中のニッチだ:まだそれを動かしている医療請求システム、移行しなかったエンタープライズJavaショップ、そしてそれを使う一握りのオープンソースプロジェクト。

Spring Bootは対照的に反対方向に進んだ。Javaバックエンドの世界を飲み込んだ。2024年に新しいJavaサービスを書いているなら、ほぼ確実にSpring Bootを使っている。数少ないフレームワークがなるほどの方法でデフォルトになった。

皮肉なのは、あまり新しくなかったスタックの部分(Javaバックエンドは1997年から存在している)が耐久性があったということだ。本当に時代の先を行っていた部分 — 型安全なコンパイルされたフロントエンドJava — そのエコシステムが成熟するにつれて競争していたエコシステムに負けた。

GWTノスタルジアの壁に当たっている人に言いたいこと

GWTで働いていて郷愁を感じるなら:実際に懐かしんでいるのはスタック全体にわたる一貫した型システムの感覚だ。その感覚は今やTypeScript + tRPCで、または生成されたTypeScriptクライアントを持つ完全なJavaバックエンドで、または勇気があればKotlin + Compose Multiplatformで利用可能だ。ツーリングは劇的に良くなっている。

しかしGWTが本物の問題を最初に解決したことは間違っていない。多くのJavaと非常に遅いコンパイラとSwingのように見えるウィジェットモデルで解決した。2013年にそれは正しいトレードだった。2024年にはより良い選択肢がある — そしてそれらのより良い選択肢のほとんどはGWTが最初に存在し、価値を実証し、他の全員がよりクリーンなものを作れるように実験的なコストを払ったからこそ存在する。

GWTのUIBinderXMLテンプレートについては今でも時々考える。懐かしくはない。しかし、本当に難しくて本番に出荷した何かに対して取っておく特定の尊重の念とともに。

Spring Bootは毎日考える。今の私のスタックに入っている。