前期では、本プロジェクトのゴールである Chrome でのデバッグ機能を実現する CDP サーバーと、CDPサーバー と DAPサーバー(VS Code でのデバッグ機能を実現するサーバー) のテストフレームワークの開発を中心に取り組んだ。
CDP サーバーの開発については本プロジェクト開始前にプロトタイプとして導入されていたものを改善する形で主にバグ修正や Chrome DevTools 上の UI として提供されている機能をサポートしていった。 バグ修正については手元の環境で Chrome を用いてデバッグ機能を行いそれを元に見つかったバグを中心に修正を行っていった。提供されている機能のサポートについては、例外で止まる機能やブレークポイントなしでスクリプト実行を強制する機能などを実装した。他にもデバッガー起動時に Chrome を自動で開いて Chrome DevTools とデバッガーの接続を自動で行う機能や Chrome のコンソールで式評価をした際に標準出力に出力されるものをターミナルではなくコンソール上に出力されるものを開発した。
テストフレームワーク開発についてはプロトタイプとしていくつかのものを Pull Request として作りながらメンテナンス性や可読性の高いものを考えていった。現在 DAP サーバーのテストフレームワークがプロトタイプとしてマージされている。
その他の取り組みとして、デバッガーの統合テストをするテストフレームワークやテストケースジェネレーターの改善・バグ修正などを行った。具体的にはデバッギーに出力 されるものが多いとタイムアウトになってしまうテストフレームワークのバグの修正や、テストケースジェネレーターではデバッグをしたソースコードが出力先のファイルに含まれていないかチェックしてなければ出力できるようになった。
- Fix #329 by getting frame's path correctly
- Continue the debuggee after detaching to Chrome
- 繋いでいる状態で Chrome DevTools ページを閉じると、エラーが出て終了するバグ修正の Pull Request 。閉じた時に Chrome は Opcode に8(8は接続を閉じるという意味)を入れて送ってくるが、それに対応できていないのが原因だった。
- この時、対応方法は以下の3通りだった。
- デバッギーを
exit
で終了する。 - デバッギーに
continue
コマンドを実行させる。 - rdbg REPL に戻る。
- デバッギーを
- gdb や リモートデバッグに合わせるのが良いと考え、デバッギーに
continue
コマンドを実行させる方法を採用した。
- Fix bug that error occurs after detaching to Chrome
- デタッチ後にエラーが出て終了するバグ修正の Pull Request 。スレッド終了後に
readline
メソッドが呼ばれてエラーが出てしまうということが原因だった。
- デタッチ後にエラーが出て終了するバグ修正の Pull Request 。スレッド終了後に
- Ensure that the correct line number of the breakpoint is returned
- Chrome がブレークポイントをセットするよう要求した行番号が正しいかどうか確認するようにした Pull Request。
ブレークポイントをセット後、それらを全て削除したがまだブレークポイントが残っているバグ修正に関する Pull Request 群
- Make sure to get break numbers correctly in CDP server
- Fix bug that breakpoints still left even though they are removed in Chrome
- Fix bug that line numbers can not be retrieved from Chrome's requests
- Fix bug that number of lines in a file are not counted correctly
- Add missing methods in Chrome DevTools Protocol
マウスオーバーをした時に表示するオブジェクトに関するPull Request 群。当時はマウスオーバーされたオブジェクトを eval
して返ってきた値を返すようにしていたが、グローバル変数など値が変わってしまうという問題があった。
- Do not evaluate the method when "objectGroup" is "popover"
- メソッドの時以外
eval
するようにした。マージされなかった。
- メソッドの時以外
- Update several parts in CDP to support for the current change
- DAP サーバーの処理では
eval
を使わないで評価していたので DAP サーバーの方に合わせるようにしたもの。上記の Do not evaluate the method when "objectGroup" is "popover" と比較して読みやすさやオブジェクトの表示範囲が広かったのでこちらを採用することにした。 - バックトレースの部分も DAP の方に合わせてそれぞれの変数の継承元のオブジェクトなどを表示できるようにした。
- DAP サーバーの処理では
コンスタント変数にマウスオーバーをした時にデバッガーが落ちるバグを修正する為のPull Request 群。
- Make sure to match all constant variables in Chrome
- ピリオド以降の文字(
ABC.new
のうち.new
の部分)にマッチしないようにした。 CDP サーバーに関する変更。
- ピリオド以降の文字(
- Do not match any characters after the dot in an expression
- ピリオド以降の文字(
ABC.new
のうち.new
の部分)にマッチしないようにした。DAP サーバーに関する変更。
- ピリオド以降の文字(
- Match not only top level namespaces but also inside of them
A::B::C
と言ったコードがあった場合B
やC
にマウスオーバーをしてもそれらのオブジェクトが表示されないというバグがあったのでその修正をしたもの。
Chromeが自動で起動した後、 Chrome DevTools ページに飛ばないというバグを修正する為のPull Request 群。1.4.0リリース直前にこのバグを発見した。
- Fix bug that debugger sometimes doesn't open Chrome automatically
- ワークアラウンドとして出したPull Request。Chrome からのレスポンスの取得回数を増やした結果、筆者の環境でバグが修正されたように見えたことを根拠とした。
- Correct changes in #445
- ワークアラウンドのPull Requestの変更を書き直したもの。Page Domain を有効にする"Page.enable"メソッドを送信することで指定したURLへと移動する"Page.navigate"メソッドを確実に実行できるようにした。
- Send current page's frame id when debugger sends 'Page.navigate' method
- "Page.navigate"メソッドの中にFrame Id をパラメーターとして送ることにしたもの。
- 感覚ではあるが、上記の Correct changes in #445 でバグはだいぶ改善された。しかし、デバッガーを使い始める1回目にバグがまだ観測された(一度終了して再起動するとこのバグはほとんど観測されない)。ドキュメントを見たところ、"Page.navigate"メソッドを送る際に Frame Id のフィールドをパラメーターとして送らない場合トップフレームを Frame Id として取得するという内容があったの遷移するフレームがトップフレームではなかった場合失敗するのではないかという推測を立て Fame Id をパラメーターとして送るようにした。その結果、現在に至るまでバグは筆者の環境で観測されていないので、バグを修正することができたと判断している。
- Show objects when a hovered expression is a specific class in Chrome
- Fix bug that several types doesn't show their classes
- Fix bug that debugger doesn't stop at the final line in Chrome
- ファイルの最終行に止まらないバグを修正するPull Request。デバッグコマンドを入力する順番が間違っていたことが原因だった。
- Skip cleanup code for CDP
- Chrome を自動で開くために作ったテンポラリーディレクトリを削除する処理に止まってしまうというバグを修正する Pull Request 。
- Call "cleanup_reader" method in "UI_ServerBase" class when CDP exits
- 継承元のメソッドを呼び出す Pull Request 。 Chrome のプロセスを終了しない方針になっていてこのメソッドは削除予定なのでクローズした。
- Give correct arguments to "respond_fail" method
- メソッド呼び出しの際にハッシュを展開して引数として渡す。
- Use "DEBUGGER__.safe_inspect" when objects are inspected
- Object#inspect の代わりに DEBUGGER__#safe_inspect を使う。
- Fix bug that debugger raise an error when breakpoints are set in script snippets
- Snippets ペインにブレークポイントをセットしている状態でデバッガーを起動しようとすると落ちてしまうバグの修正 Pull Request 。
- Refactor processing of WebSocket in
cdp_server.rb
- WebSocket の処理を WebSocket クラスとして切り出したもの。
- Fix processing not related to WebSocket
- WebSocket の処理に関係ないものを WebSocket クラスから切り離した。
-
- 当初、以下の機能が実装されていたが断念した。
- ポートなどの情報をファイルとして持たせる
- なんらかの方法でそのファイルを書き換えることができた場合意図しない接続先にデバッガーが接続しようとしてしまうというセキュリティリスクがあり断念。
- DevToolsActivePort ファイルからポートなどの情報を読み取る
- 実験してみたところ、ポート番号が変わっても DevToolsActivePort ファイルが更新されなかったり、 DevToolsActivePort ファイルを用いたいくつかのプロジェクトでうまく動かないといった Issue が観測されたので断念。
- ポートなどの情報をファイルとして持たせる
- 当初、以下の機能が実装されていたが断念した。
-
Do not open Chrome automatically if "CONFIG[:chrome_path]" is an empty string
- Chrome を自動で開きたくないケースがあると考え、環境変数で設定できるようにした。
- Output stdout to Console instead of the terminal
- Make sure that $stdout returns to its original value after evaluation in CDP
- Support "Pause on exceptions" feature in CDP
- 捕捉された例外でも止まるのか、捕捉されなかった場合のみとまるのか2つのオプションがあったため、以下のようにした。
- 捕捉された例外でも止まる ->
catch Exception
- 捕捉されなかった場合のみ止まる -> postmoterm モードで実行
- 捕捉された例外でも止まる ->
- 捕捉された例外でも止まるのか、捕捉されなかった場合のみとまるのか2つのオプションがあったため、以下のようにした。
- Show exception messages in Chrome when debugger paused on an exception
- 例外で止まった時、メッセージを表示するようにした。
- Show variables in the target frame in Chrome
- funcitonLocation パラメーターを"Debugger .paused"メソッドの中に追加することで実現。 functionLocation フィールドの中の lineNumber フィールドにはワークアラウンドとして0を固定値で入れていたが、筆者の試した範囲では正常に表示することを確認できたのでこの変更で良いと判断した。
- Set lineNumber of functionLocation correctly
- lineNumber フィールドに正しい行数を入れるようにしたもの。意図しない場所に変数が表示されるというバグが見つかったためワークアラウンドの部分を修正することにした。
- Make multidimensional hashes and arrays easier to read in Chrome
- 配列やハッシュの中身を以下のようにクリックして見れるようにしたもの。
-
Support several features in Chrome DevTools
- 以下の機能をサポートした。
- ブレークポイントをアクティベートする機能
- スクリプトをブレークポイントなしで強制実行
- 以下の機能をサポートした。
-
Improve error messages when it evaluates expressions in Console
- エラーメッセージの改善。
- Add explanations on how to maximize Chrome DevTools
- Chrome DevTools ページを最大化する為の方法をドキュメントに記載。
- Fix typo
- タイポ
-
- 実験で作ったフレームワーク。イメージができたのでクローズした。
-
[WIP] 1. Add the test framework for CDP
-
テストフレームワークの1パターン目。以下のように
server_cdp.rb
と同じように書くような形にした。 -
def test_sample run_cdp_scenario PROGRAM do res1 = cdp_request 'Debugger.setBreakpointByUrl', condition: '', lineNumber: 7, url: "http://debuggee#{temp_file_path}" res2 = cdp_request 'Debugger.setBreakpointByUrl', condition: '', lineNumber: 5, url: "http://debuggee#{temp_file_path}" res3 = cdp_request 'Debugger.setBreakpointByUrl', condition: '', lineNumber: 3, url: "http://debuggee#{temp_file_path}" ...
-
メリット
- 最も柔軟に書くことができる。
- 行数が少なくて済む
-
デメリット
- 可読性が低く CDP をよく知っている人にしか分からないものになっている。
-
-
[WIP] 2. Add the test framework for CDP
-
テストフレームワークの2パターン目。以下のようにJSON 形式でリクエスト・レスポンスを書くような形にした。テストジェネレーターも併せて作った。
-
def test_sample run_cdp_scenario RROGRAM do cdp_req({ "id": 1, "method": "Page.getResourceTree", "params": { } }) ...
-
メリット
- パターン1と比べ可読性が高い。
-
デメリット
- 毎回メソッドを通して呼んでいるので余計なカッコがついたりして可読性が下がる。
- 行数が長くなる。
-
まだ実装はしていないが、3パターン目として以下のようなものを考えている。
def test_sample
run_cdp_scenario PROGRAM do
{
"id": 1,
"type": "request"
"method": "Page.getResourceTree",
"params": {
}
...
- メリット
- DAP と同じ形式なので読みやすい。
- デメリット
- 返り値を使ってリクエストを送ることができないなど柔軟性が低い。
- 行数が長くなる。
- Add the test framework for DAP
- DAP をテストする為のフレームワーク。
- Skip tests for DAP if the environmental variable is not set
- Call "recv_request" method with correct number of arguments
- DAP のテストを実行する際に時々落ちるバグを修正。メソッドを呼び出す際に正しい引数を与えていなかったことが原因だった。
- Add a new workflow to test for DAP
- DAP テスト用の新しいワークフローを追加
- ランダムなタイミングでテストが失敗するという問題を抱えていて
rake test
では実行されないようになっている。
- Fix tests
- CI が落ちていたのでその修正。継承元オブジェクトの表示される順番が筆者の環境と CI 環境で違ったことが原因だった。
Debuggeeの出力が多いときテストフレームワークが動かないというバグを修正する為のPull Request 群
- Read data from the I/O stream of the remote debuggee every commands are typed
- Read data from the I/O stream of the remote debuggee when Timeout Error occurs
- Timeout Errorが起こったタイミングでリトライするようにしたもの。バグが治ったことは筆者の環境で確認できたが、この変更によってどうしてこのバグが直ったのか原因がわからず、たまたまの可能性が高くマージされなかった。
- Fix bug that test framework gets stuck when debuggee outputs many lines
- デバッギー側の出力を常に読み取る新しくスレッドを作るようにした。マージされた。
- Fix test
- CIが落ちていたのでその修正。
assert_finish
メソッドをAPIから削除後、まだ消し忘れが残っていたことが原因だった。
- CIが落ちていたのでその修正。
- Remove the useless method call
- 必要のないメソッドが呼ばれていたのでそのメソッドの削除。
- Remove some unused code
- 使われてないコードの削除
- Fix unused block arguments
- Fix small parts in lib/debug/thread_client.rb
- Remove redundant "begin" block
- Use snake case instead of camel case
- キャメルケースで変数が定義されていたのでスネークケースに変数を書き直したもの。VS Code のフィールド名であることを強調する為意図的にキャメルケースで書かれていたものだった為、マージされなかった。
- Refactor the logic by removing an intermediate variable
- 中間変数を削除するもの。テストが通らずクローズした。
- Verify that the debugger and debuggee program have exited
assert_finish
メソッドをAPIから削除しテストフレームワークの内部でデバッガー・デバッギープログラムが終了しているかどうか確認するようにした。
- Add the
program
method if the source of the script file doesn't match the source of allprogram
methods in the file- テストケースジェネレーターの改善。デバッグ対象のソースコードがテストケース製成先のファイルに含まれていなければシナリオメソッドと一緒にソースコードを追加するようにした。
- Update the guide for the test generator
- テストケースジェネレーターの使い方を記載。
- Add descriptions about assert methods to CONTRIBUTING.md
- テストの API の使い方を記載。
- Fix typo
- タイポ
本プロジェクト開始時のゴールに対する進捗は以下のようになっている。全体的には順調にプロジェクトを進めることができていると考えている。Chrome に関してはプロジェクト開始時のゴールを達成できた。テストフレームワークについても先述したようにいくつかのプロトタイプができているので問題はない。
- Chrome でのデバッグ機能を実現する CDP サーバーの開発
- vscode-rdbg と遜色ない機能を持ったデバッグができる。
- Chrome DevTools 上の UI として提供されている機能のサポートをする。
- CDPサーバー と DAPサーバー のテストフレームワークの開発
- CDP サーバー
- テストフレームワークがマージされる。
- テストフレームワークが安定して動く。
- DAP サーバー
- テストフレームワークがマージされる。
- テストフレームワークが安定して動く。
- CDP サーバー
現時点で “debug.gem” の利用体験を向上することができたと考えている。VS Code を用いたデバッグと同様の機能を Chrome でも実現することができ、 Chrome を用いた JavaScript のデバッグに慣れ親しんでいるユーザーが “debug.gem” を使いやすくなったということができる。さらにこれらの Chrome DevTools を用いたノウハウを活かしてデバッグ体験にとどまらず、 irb を Chrome のコンソールで実行することでより良い体験を実現かもしれないという新たな可能性が出てきた。開発者支援ツールはターミナルをメインの UI として用いられることが多いものもあるが、よりリッチな体験を実現できる Chrome を一つの選択肢として考える機会を作ったという意味で有用な成果を得ることができた。
前半ではデバッグを問題なくできることに多くの時間を費やしたので後半では Chrome の強みを活かしたリッチな開発体験向上に取り組んでいく。また、テストフレームワークの開発では DAP のテストフレームワークを安定させ CDP のテストフレームワークもマージしていきたい。
- Chrome を用いた機能開発
- プログラム中で出力される
p
メソッドなど標準出力に出力するものをターミナルではなく Chrome のコンソール上で表示できるようにする。 - Ruby の補完機能を利用できるようにする。
pp
メソッドを拡張して Chrome のコンソールを使って表示できるようにする。- irb のような使い方を Chrome のコンソールでできるようにする。
- ブラウザの強みを活かしたターミナル上では実現できないリッチな出力をできるようにする。
- プログラム中で出力される
- テストフレームワーク開発
- DAP サーバーのテストフレームワークを安定させるようにする。
- CDP サーバーのテストフレームワークを開発する。
本プロジェクトを進めるに当たって笹田耕一さんには Pull Request のレビューを始め沢山の助言をいただきました。Ruby に関する知識はもちろんのこと、一流のプログラマとしての姿勢や視点からは沢山のことを学ばせていただきました。本当にありがとうございました。これからもどうぞ宜しくお願い致します。
また、このような素晴らしい機会を与えてくださった Ruby アソシエーション関係者の皆様に感謝します。