SEROKU の開発を例に、弊社で使っているリモートデバッグとロガーの Tips をご紹介します。
当記事は 2018 年、と過去の記事ですが、現在でも応用可能な Tips になっています。
案件としても OSS 成果物としても、JavaScript を利用するシチュエーションは増え続けています。まだまだ枯れた言語とは言い難い状況で、使われるバージョンも ES5 から ES7 まで進化を続け、新しい文字列リテラルや async/awaitのような「イマドキの JavaScript の書き方」を紹介する記事は多い中、デバッグはこうあるべきという情報は比較的少ないように思います。
本記事では JavaScript による開発、特に node.js を使ったサーバーサイド開発環境および babel を使ったクライアントサイド開発環境で便利なロガーの Tips、そして Microsoft 提供の Visual Studio Code とのリモートデバッグの Tips を紹介します。
動機
デバッガ、ロガーの存在意義とは
開発を行う上で、print デバッグを卒業してデバッガを利用し、ブレークポイントを仕掛けてなにがどうなっているのかを見るのが脱初心者の証。どうしてうまく動かないのか、流れるコードを途中で止めて状況を把握するのは、生産性向上に直結します。
他方でロガーは、開発時・運用時両方で重要な要素です。正常時・異常時両方を把握するのに便利な一方で、いざ本番環境で理解不能な状況に陥った場合に一時的にログレベルを上げることで問題解決に必要な情報を手に入れることができます。
Java の世界を見てみよう
筆者は Java 歴が長いのですが、あちらのエコシステムではその両方をすぐ使える状況になっています。
デバッガに関して言えば、Java 開発の文化では Eclipse や IntelliJ のような重量級 IDE を利用するのが一般的です。それらにはボタン1つクリックするだけでデバッガが立ち上がるようになっているため、Java 開発者は初心者のうちからデバッガの利用を教えられ、活用していくことが多いと思います。
ロガーに関しては、Java ではインターフェース・実装共に選択肢が非常に多いのが特徴的です。Commons Logging の登場を皮切りに多種多様なロギングライブラリが登場し、何を採用したらいいのかわからない暗黒時代を経て、現状は SLF4j というインターフェースを中心に、プロダクト開発者やフレームワーク開発者が自由にライブラリを組み合わせて、好みのロギング方法、ログ出力方法を選べるようになっています。
参考: Javaのロギングライブラリの歴史と現状をふんわり把握する(初学者向け)
言語仕様が枯れていること、そもそも静的型付けの言語であること、歴史が長いことも、Java コミュニティがこれらの資産を産み出すことができた一因と言えるでしょう。
翻って JavaScript 開発
JavaScript 界隈の変化のスピードは Java の比ではありません。そのため、アーキテクチャとして何を組み合わせるのか、ビルド環境をどうするのかなど、様々な要素で「これがデファクト」というものが事実上存在していない状況です。
デバッガ
IDE を利用するチームは少数派で、多くはコーディングはエディタで行い、開発環境でのビルド・実行は直接ターミナルから npm を叩く構成が主流です。そのため、デバッガの整備には一工夫必要で、エディタと連携してリモートデバッグ可能な環境で開発を行っている開発者は少ないのではないでしょうか(もっとも、ライトウェイト言語による開発全般でその傾向はあると思われます)。
ロガー
先にフレームワークの話から入りますが、「デファクトのフレームワークが標準搭載しているロガーが便利」な状況があるからこそ、Java や Ruby でそのあたりをがんばらなくていい、というのはあります。Spring Boot と log4j, logback の関係であり、Ruby on Rails と Rails.logger の関係です。
Express は Spring Boot や Rails と比べて守備範囲が狭く、オールインワンで使えるロガーを準備してくれているわけではありません。クライアントサイドに於いても webpack/babel は地位を固めましたが、これらはビルドツールであり、React もまたそのあたりは守備範囲外です。
また、多くの開発者に使われている debug というライブラリは明らかに機能不足です。ログレベルがないのが致命的で、できることと言えばログが属するネームスペースごとに出すか出さないかを決められるだけ、そしてその設定方法も環境変数 DEBUG にネームスペースを羅列するだけと、非常にシンプルなだけに手が届かないところは多いと言えます。
理想の世界
では、今の世界がどうなると JavaScript 開発者の生産性が上がるでしょうか。理想を挙げておきましょう。
対象システム
以下の3つのシナリオをカバーすることにします。
-
シナリオA
- node.js (Express)
-
シナリオB
- node.js (Express) + webpack/babel によるクライアントビルド
-
シナリオC
- next.js on Express
シナリオCなどは大変「イマドキ」ですね
デバッガ
-
SourceMap の利用
- ブラウザの開発者ツールでエラーを追う場合、トランスパイル前のソースの行数が分かる
-
リモートデバッグ
- Microsoft Visual Studio Code で編集中のソースに対してブレークポイントを仕掛けて止めることができる
- node.js 用コードでも、クライアント用コードでも同様に VSCode 上でデバッグ可能
ロガー
-
記述側
- サーバーサイド、クライアントサイド両方で同じログモジュールを利用できる
- ログレベルを指定したログ出力行の記述ができる
-
出力側
-
サーバーサイド、クライアントサイド両方で同じログモジュールを利用できる
-
development, production 等の環境用の設定ファイルでデフォルトの挙動を設定できる
- 環境変数設定により、上記を一時的に変更できる
-
プロダクト全体でのデフォルトログ出力レベルを設定できる
-
ログのネームスペースごとにログ出力レベルを設定できる
-
development, production 等の環境に応じて出力フォーマットを変更できる
- development 環境ではフォーマットされたログ出力
- production 環境下では JSON フォーマット出力による高速なログ出力
-
-
過去の資産の有効利用
- 今まで記述された debug ライブラリによる記述を変更することなく、新しいロギングライブラリによる出力を可能にする
今回見送ること
ロガーに関しては、他言語のフレームワークでできているようなファイルへのログ出力 および ログローテートを可能にしたい、という需要もあるかもしれません。今回利用するロギングライブラリでも設定によってはそれも可能なのですが、コンテナディプロイ全盛の「イマドキ」では優先度は低いと考え、見送ることにします。
まとめ
前編ではデバッガ、ロガーの大切さと、他の言語・フレームワークと比べた際の JavaScript 開発環境に於けるビハインドについてまとめました。次回、中編・後編で「理想の世界」を実現する具体的なコードを紹介していきます。