Logpointsと自動アタッチの紹介
2018年7月12日 ケネス・アウチェンバーグ、@auchenberg
過去数ヶ月間、私たちはVisual Studio Codeのデバッグ体験の改善に力を注いできました。この記事では、私たちがデバッグについてどのように考えているか、ユーザーから寄せられたフィードバックを紹介し、VS Codeでのデバッグをより簡単でシンプルにするために講じているステップについて説明します。
VS Codeの開始以来、私たちは統合されたデバッグ体験を提供してきました。なぜなら、デバッグはソースコードを記述・編集する場所、すなわちエディターの不可欠な一部であるべきだと考えているからです。
VS Codeのデバッグ体験は、Debug Adapter Protocol (DAP) を介して、私たちがDebug Adapter (DA) と呼ぶ特定の種類のVS Code拡張機能と通信する汎用デバッガーUIによって提供されています。DAは実際のデバッガーと通信し、DAPとランタイム固有のデバッグプロトコルまたはデバッガーのAPI間で変換を行います。
これは、VS Codeのコアが特定のデバッガーから完全に分離されていることを意味し、このアーキテクチャにより、ここに示されているように、Debug Adapterが利用可能であればVS Codeはあらゆるものをデバッグできます。
観察と課題
今日、VS Codeで定期的にデバッグを行っている満足している開発者は多数いますが、私たちのミッションの一環として、より多くの開発者にとってデバッグをより簡単に、利用できるようにしたいと考えています。
この目的のため、私たちはVS Codeにおけるデバッグの課題をよりよく理解し、なぜ一部の開発者が私たちのデバッガーを全く使用していないのかを知るために、議論を開始しました。
以下が私たちの観察結果です
デバッグ構成を正しく設定するのは難しい
VS Codeは汎用デバッガーを備えた一般的なエディターであり、特定のスタックやランタイムに特化していません。このため、すべての人に機能するような、ある程度意見を押し付けたデフォルトのデバッグ構成を提供することはできません。
これは、VS Codeでは、デバッガーの設定だけでなく、適切なパラメータなどを使用してランタイムをどのように起動したいかを指定する必要があることを意味します。
これを正しく設定するのが難しいことは認識していますが、すべての人にとってデバッグ構成を完全に排除する方法は見当たりません。しかし、デバッグ構成は簡素化でき、コンテキストによっては最小限に抑えることができると信じています。
これについては後ほど説明します。
起動構成とアタッチ構成の混同
VS Codeにはデバッグのための2つの主要な概念があります: 起動 (Launch) と アタッチ (Attach) であり、これらは2つの異なるワークフローと開発者のセグメントを扱います。ご自身のワークフローによっては、どの種類の構成がプロジェクトに適しているかを判断するのが混乱する場合があります。
ブラウザのDevToolsに慣れている方であれば、ブラウザインスタンスは既に開いているため、「ツールから起動する」という概念には慣れていないでしょう。DevToolsを開くとき、開いているブラウザタブにDevToolsを単にアタッチしているだけです。一方、Javaの経験がある方であれば、エディターがJavaプロセスを起動し、エディターが新しく起動したプロセスにデバッガーを自動的にアタッチするのはごく普通のことです。
起動 (launch) と アタッチ (attach) の違いを説明する最良の方法は、起動構成をVS Codeがアタッチする前にデバッグモードでアプリを起動する方法のレシピと考える一方で、アタッチ構成はVS Codeのデバッガーを既に実行中のアプリまたはプロセスに接続する方法のレシピと考えることです。
起動構成の価値は、適切なデバッグパラメータでアプリケーションを起動する際の認知的負担の一部を軽減する方法を提供することです。これは、プロジェクトやチームと繰り返し利用・共有できる構成を作成することで実現されます。
しかし、開発者がどのようにアプリケーションを起動しているかについて話を聞いたところ、あるパターンが見られ、重要な観察結果が1つ得られました
観察結果: VS Codeを使用している多くの開発者は、統合ターミナルを非常に気に入り、アプリケーションの起動にコマンドラインツールを頼りにしています。多くの人にとって、ターミナルでコマンドを実行し、その後エディターからデバッガーをアタッチする方がより自然なワークフローです。これは、ブラウザが起動した後にDevToolsを開くのと似ています。
この観察は重要であり、多くのユーザーがエディターで完全な「魔法のような」起動体験を求めていないことに気づきました。彼らはエディターをソースコードの編集とデバッグの場所として保持し、ターミナルを使用してアプリの起動、ビルドスクリプトの実行などを行いたいと考えています。これが、VS Code内に統合ターミナル体験がある理由の1つです。私たちは、優れた機能的なUIがターミナルと共存し、うまく統合されるべきだと信じています。
多くの開発者は、状態の変化を調査しているためブレークポイントを使用しません
開発者がアプリケーションをデバッグする方法を見てみると、もう1つの興味深いパターンが見られました。それは、ブレークポイントの代わりにログを使用することです。
デバッグのためのロギングは新しい概念ではありませんが、この観察は重要でした
観察結果: 従来のデバッグワークフローは、プログラムロジックを検査するために実行を遅らせることに最も焦点が当てられていますが、ロギングワークフローは通常、プログラムの状態と、アプリケーションの通常の実行中にそれがどのように変化するかを検査することを含みます。ここでの根本的な観察は、この2つの手法が異なるデバッグ目的に使用されるということです。
この観察は、状態管理の複雑さに主に対処するJavaScript開発者にとって特に重要であり、ほとんどのJavaScript開発者がスクリプトデバッガーを使用する代わりにconsole.logを追加することを依然として好む理由を説明できるかもしれません。
Nodeプロセスへの自動アタッチ
一部の開発者が統合ターミナルを使用してデバッグセッションを起動している方法を検討した際、ユニークな機会が浮上しました。エディターと統合ターミナルからVS Code内に持っているコンテキスト情報を活用することで、開発者のコンテキストとデバッグの意図を検出し、Node.js開発者にとってよりシンプルなデバッグ体験を提供できると考えました。
そのため、VS Codeの3月のイテレーションで、Nodeの自動アタッチ (Auto Attach for Node) と呼ばれる新機能をリリースしました。これにより、NodeデバッガーはVS Codeの統合ターミナルからデバッグモードで起動されたNode.jsプロセスに自動的にアタッチできるようになります。
自動アタッチを有効にするには、コマンドパレットからデバッグ: 自動アタッチの切り替え (Debug: Toggle Auto Attach) コマンドを実行します。一度有効にすると、ステータスバーからも自動アタッチを切り替えることができます。
この機能は、node --inspect
で起動されたすべてのNode.jsプロセスをデバッグの意図があると解釈するため、デバッグ構成を完全に不要にします。統合ターミナルと組み合わせることで、開発者が独自のやり方でアプリを起動しつつ、同時にデバッグ構成を排除できる、はるかにシンプルなデバッグ体験となります! 🎉
NPMスクリプトとデバッグ
多くのNode.js開発者は、アプリケーションの起動やデバッグセッションの開始にnpmスクリプトに依存していますが、この点でも素晴らしいニュースがあります。自動アタッチはnpmスクリプトでも機能します。npm run debug
を実行し、"debug"
スクリプトが"node --inspect"
または--inspect
を含むその他のコマンドである場合、自動アタッチはそれを検出し、デバッガーをアタッチします 🎉
また、一部の開発者がnpmスクリプトを見つけて実行するためのより視覚的な方法を求めていることを認識し、2018年4月のイテレーションで、UIから直接npmスクリプトを参照・実行できる新しいNPMスクリプトエクスプローラーを追加しました。デバッグ構成の簡素化に向けた作業の一環として、デバッグ構成を作成することなく、エクスプローラーから直接Node.jsのデバッグを開始できるようにもしました。
ここに示されているように、--inspect
のようなデバッグ引数を含むnpmスクリプトがある場合、それを自動的に検出し、デバッガーを起動するデバッグアクションを提供します。
Logpointsの紹介
ロギングが重要なデバッグ手法であるという学びに基づき、既存のデバッグ体験に状態検査を追加する機会を見出しました。VS Codeの3月のイテレーションで、Logpointsと呼ぶデバッグ機能の最初の実装をリリースしました。
Logpointは、デバッガーに「中断」するのではなく、コンソールにメッセージをログとして出力するブレークポイントのバリアントです。
Logpointsの概念は新しいものではなく、ここ数年間、Visual Studio、Edge DevTools、GDBなどのツールで、TracepointsやLogpointsなど複数の名称でこの概念の異なるバリアントを目にしてきました。
Logpointsを使用する理由とタイミング
Logpointsは、多くの場合、アプリケーションの特定の部分で実行を停止するのではなく、アプリケーションのライフサイクル全体で状態がどのように変化するかを検査したいという観察に基づいています。
Logpointsを使用すると、アプリケーションの起動前にロギングステートメントを追加したかのように、オンデマンドでロギングステートメントをアプリケーションロジックに「注入」できます。Logpointsは実行時に注入され、ソースコードには永続化されないため、事前に計画する必要がなく、必要なときにLogpointsを注入できます。もう1つの利点は、デバッグが終了した後にソースコードをクリーンアップすることを心配する必要がないことです。
JavaScript開発者にとって、これはもはやconsole.log
を残すことを心配する必要がないことを意味します — Logpointsを使用するだけです!さらに良いことに、console.log
とLogpointsを組み合わせることもできます。既にconsole.log
があるソースコードのブロックにLogpointを挿入すると、両方の種類のロギングステートメントがデバッグコンソール内に表示されます。
クラウド環境におけるLogpoints
Logpointsは、アプリケーションを再デプロイすることなくリモート環境にロギングを注入できるため、クラウド環境(または実際にはあらゆるリモート環境)で特に役立ちます。同様に重要なのは、Logpointsではスクリプトの実行を停止しないため、通常のブレークポイントで実行中のアプリケーションを停止する場合とは異なり、ユーザーに影響を与えないことです。
Azure上のNode.jsでLogpointsを使用する方法については、こちらをご覧ください。
サポートされる言語
VS CodeでLogpointsが最初にリリースされて以来、VS Code Debug Adaptersによる採用が拡大しており、現在、以下の言語でLogpointがサポートされています
- Node.jsデバッガー
- Chromeデバッガー
- Firefoxデバッガー
- Microsoft Edgeデバッガー
- React Nativeデバッガー
- Pythonデバッガー
- Dartデバッガー
- Luaデバッガー
- Javaデバッガー
- メインフレーム用デバッガー
VS CodeにおけるLogpoints
VS CodeのDebug AdapterにLogpointサポートを追加することに興味がある場合は、プロトコルにおけるこれらの変更点をご覧ください。上記のデバッグアダプターを参考に、各ランタイムがLogpointsをどのように実装しているかを確認することもできます。
次のステップ
今回はここまでですが、まだ終わりではありません。ユーザーからのフィードバックに基づき、7月のイテレーションでは、自動アタッチの発見しやすさ向上(#53640)のために改善を行っています。
自動アタッチ、NPMスクリプトエクスプローラー、Logpointsの導入により、VS Codeでのデバッグがより簡単になることを願っています。これまでと同様、皆様からのフィードバックをお待ちしておりますので、GitHubまたはTwitterの@codeまでご連絡ください。
VS Codeチームを代表して: ハッピーコーディング!
/ケネス・アウチェンバーグ — Twitterの@auchenberg