FastComments.com Blog

Fri Jan 31 2025
...

FastComments TypeScript Migration Completed

! この記事には技術用語が含まれています

新しい内容

FastCommentsでは、静的型付け言語を重視しています。具体的には、迅速なコンパイラを持つ優れた型システムが好きです。FastCommentsは後者、もしくはコンパイラなしでスタートしました。その最初の年に、モダンなJavaで書かれた2つのサービスがあったものの、主なバックエンドとフロントエンドのライブラリはNode上で動作するCJS JSで書かれていました。

次の10年間の開発に備えて、FastCommentsの最大のコンポーネントをTypeScriptに移行しました。

これには、1441ファイルにわたる130,000行以上のコードを移行し(そのうち100,000はバックエンド)、8000を超えるコンパイルエラーを修正することが含まれました。

woooooo
GitHub Screenshot

この作業は2週間で行われました。

コードフリーズ - ありがとうございました

バグ修正や機能リリースの遅延に対処してくださったお客様に感謝いたします。これを完了するために2週間のコードフリーズを実施しました。ありがとうございました!

修正されたバグ

ご想像の通り、いくつかのバグを修正しました。これらは主にスパム検出とキャッシュに関するものでした。

破壊的変更

  • すべてのAPIエンドポイントは、状態値として「failed」と「failure」の混合の代わりに、status: 'failed'を返すようになりました。「success」は変更されません。
  • 一致するものがない場合、最初のウィジェット設定をデフォルトとして使用することはなくなり、代わりにデフォルトシステム設定を返します。

どのような体験だったか?

例によって、NPMエコシステムの多くのツールはこの作業の助けにはなりませんでした。そこで、LLMを使用して大部分の作業を行うスクリプトを生成しました。例えば、JSDocを多用していたため、JSDocを取り込み、それをTypeScriptインターフェースや型定義に変換し、関数の引数や戻り値の型を正しく注釈付けするスクリプトを書くことができました。これらのスクリプトを使用して、CJSからESMへの移行も行い、インポート、エクスポートの書き換えや、__dirnameのような共通のランタイムの問題の検出を行いました。

ランタイムの問題について言及しましたか?

2025年のTypeScriptはどうか?

TypeScriptはビジネスロジックを書くための良い言語です。しかし、Javaはまだ優れた開発体験を提供しています。Java、Go、またはRustがコンパイルされる場合、ほぼ間違いなく動作します。TypeScriptでは、次のようなことができます:

console.log(__dirname);

...そしてこれはコンパイルされます。

しかし、現代のESモジュールでは実行されません。あなたのIDEは喜んで__dirnameをオートコンプリートしてくれるでしょうが、実行時にエラーが発生します。Spring DIのような感触ですが、さらに悪化しています。

また、次のようなこともできます:

context.someImportantMethodToCall;

これは「ステートメント」です。これは有効な「ステートメント」です。一見すると、私たちがsomeImportantMethodToCallを呼び出していると思うかもしれませんが、実際には呼び出していません!少なくとも私のIDEはこれについて警告を出さず、コンパイラも同様です。コードは何もしないだけです(someImportantMethodToCallがクラスのgetterである場合、それは暗黙的に呼び出されますが…)。

修正は次のようになります:

context.someImportantMethodToCall();

おそらく、eslintのようなものでこれを検出することができますし、「副作用のない」ルールのようなものも使えますが、そうすると別の大規模なライブラリセットを更新する必要が生じ、eslintは全てのビルドでコード全体を解析する必要があるため、ツールは遅くなりますし、ありがとうございました。eslintのような遅いツールを扱うことによる生産性への影響は、過去の仕事において、私がeslintが修正/防止する些細な問題から得た生産性「向上」よりもはるかに重要でした。今ではより高速な代替手段が出てきており、素晴らしいです。

TypeScriptは、Pick<User, 'username', 'email'>のような言語機能のおかげで本当に素晴らしいです。これと型推論を組み合わせることで、各シェイプのためにクラスを定義することなく、大きなオブジェクトのサブセットから型安全なクエリ結果を得る方法を提供します。PickはScalaにはないことに驚いています。型ユニオンも本当に良いです。

増分ビルドもかなりうまく機能しており、CIでのビルド時間は共有ライブラリ、フロントエンド、バックエンドを構築する際に平均して約5~10秒しか増えていません。

開発のタイムライン

興味のある方のために、我々の進捗は次のようになっています:

  • 初日:362ファイルで5564エラーを検出。
  • 2日目:239ファイルで4034エラーを検出。
  • 3日目:191ファイルで3784エラーを検出。
  • 4日目:169ファイルで2974エラーを検出。
  • 5日目:171ファイルで3000エラーを検出。
  • 6日目:165ファイルで2916エラーを検出。
  • 7日目:157ファイルで2618エラーを検出。
  • 8日目:109ファイルで2253エラーを検出。
  • 9日目:69ファイルで1605エラーを検出。
  • 10日目:53ファイルで686エラーを検出。
  • 11日目:バックエンドのユニットテスト通過。
  • 12日目:フロントエンドに移行開始、3118エラー。
  • 13日目:2172エラーを検出。
  • 14日目:1224エラーを検出。
  • 15日目:498エラーを検出。
  • 16日目:すべてのコンパイルエラーを修正。
  • 17日目:リリース。E2Eテスト通過。予期しないランタイムの問題による30分のダウンタイム。 :)

今後について

これを行ったのは、次の10年間の開発を支援するためです。システムは十分に大きくなったため、型システムを使用して開発する方が、使用しないよりも速くなっています。

また、私たちのTypeScriptライブラリがNPMで改善されることを期待しています。すでに改善が始まっています。なぜなら、私たちは今、そのライブラリをサーバーとクライアントのコードで使用しているからです。

サーバーコードから直接生成されたクライアントSDKを間もなくリリースする予定でもあり、これはこの取り組みの主要な動機の一つでした。

結論

すべての主要なリリースと同様に、最適化、テスト、そしてこれらの変更を適切にリリースするための時間を取ることができたことに感謝しています。問題を発見した場合は、下記でお知らせください。

Cheers!