🐛

Intellijを使用して上手に問題に対処する方法

2024/09/30に公開

はじめに

このページは、
普段バックエンドのコードを書いてる私が何か問題が発生したときにJetbrainsのIDEを使用して速やかに発生元を突き止め、対処する方法を書いたものです。
言い換えると、問題が起きたときにコードを眺める際の私のルーチンワークを紹介します。

Java、Kotlin、PHPしか仕事では使わないので他は不明ですが、多分一緒です。
これを書いてる端末がmacなのでキーはmacです。

graphql-kotlinのコードを使いながら書いていこうと思います。

なぜ書くのか

問題が発生したときに、その機能の入口からコードに潜る人を観測したため。
入口から特定しに行くなとは言わないですが、サブタイピングをゴリゴリ使っていると入口から特定しにいこうとするのはしんどいです。
なので、発生源のあたりを付けてボトムアップで何が行われているのかを確認する方法について書きたくなりました。
また、IDEの使い方に個人差があるので、紹介したくなりました。

問題の特定をどうやってるか

テキストから問題となっていそうな箇所を調べる

ログでもレスポンスのエラーでも何でも良いのですが、テキストで何か残っていると思います。
まずはそれを調べます。

Cmd + Shift + F

これはよく使用すると思います。
検索ワードを突っ込んで検索します。
適当な例外のエラーメッセージ(specifies malformed field set)を入れてます。
デフォルトでプロジェクトの全ファイルが対象なので、テストコードなどを除きたい場合は、「Project Production Files」を選択しておくと良いです。

呼び出し階層を表示して階層を遡る

上記の検索結果からここに飛んでいるはずなので、このvalidateFieldSetメソッドから遡っていきます。

private fun validateFieldSet(directiveInfo: DirectiveInfo, fieldSet: List<String>) {
    var isOpen = 0
    for (field in fieldSet) {
        when (field) {
            "{" -> isOpen++
            "}" -> isOpen--
        }

        if (isOpen < 0) {
            break
        }
    }

    if (isOpen != 0) {
        throw InvalidFederatedSchema(listOf("$directiveInfo specifies malformed field set: ${directiveInfo.fieldSet}"))
    }
}

Option + Control + Hをメソッド名にカーソルを当てて押します。
(メソッド内でも問題ないですが、listOfなどにカーソルが当たっていると、listOfの使用箇所を全部探しにいったりしてしまうので、あまりお勧めしないです)
そうすると、Hierarchyのタブに階層が出てきます。(キャプチャの右側)

テストコードが多くて邪魔な場合は、AllをProductionに変更するとテストコードを除けますが、テストコードに問題となるパターンを追加するときに、対象クラスへ楽にアクセスできるので私はそのままにしておいてます。
ただこのページでは説明のために、Productionに変更します。
階層を遡ると以下みたいになります。

これから入口になる処理を辿り、問題となったときにどんな処理が行われていたかをログなどと照らして確認することになります。
問題になった処理に関しては、以下を集められれば大体原因が特定できるのかなと思います。

  • 入力値
  • DBに持っている各種パラメータ(表現が曖昧になってしまう)

これらから仮説を立てて実行し、実際に問題を起こせればほぼゴールです。

問題をどうやって直しているか

簡単な問題ならシュッと直して、テストコードへ反映して確認しますが、ここでは割と何やってるかわからない場合の対処方法について書いときます。

とりあえずブレークポイントを打つ

と思うんですけど、このときに原因がわかっているなら以下のようなことが可能です。

ブレークポイントに対して右クリックを押すとブレークポイント自体へ追加設定が可能です。
Conditionに式を設定でき、これがtrueのときにのみブレークポイントで実行を止めることが可能です。
繰り返し文の中で特定の要素の時に止められればいいときなどにF9連打しなくて済みます。
ちなみにブレークポイントを外して再設定した場合、設定は消えてます。

ブレークポイントから実行を進めたくないけど、その中身を実行したい

ログを出すようにして参照したり、ブレークポイントを進めてその結果を参照するでも良いのですが、
私の場合は特に例外が起きるときにこれをよく使用します。
一次情報の例外を確実に知りたい、というのが動機です。
とりあえず右クリックしてEvaluate Expression...を押します。

そうすると、こんなのが出てくるので実行したいコードを書いてEvaluateを押します。

戻り値がなくて例外も起きないと、「だから何?」って感じなので1行上のコードでじっこうしてみました。

結果が取れてブレークポイントも進まないです、素晴らしい機能。

特定のシチュエーションで起きることを特定できたので、サクっと確認したい

  • ある関数の戻り値がHOGEのときだけ
  • 特定の例外が投げられたとき
    意図しない動きになる。
    ただデータ作るのはめんどいからサクっと確認したい、という場合には以下の方法でよく確認しています。

ブレークポイント自体への設定の中には、特定のコードを実行するという設定があります。
Moreを押すと以下のダイアログが表示されます。

真ん中くらいの Evaluate and logというのがそれです。
ここで実行するコードを書いてデバッグ実行するだけです。
ここではこんな感じにしときました。
ちなみにreturnは使えないので結果を変えたい場合は、その変数をこのように書き換える必要があります。
valでも書き換えれて便利

これをデバッグ実行するとちゃんとテストが落ちます。

ちなみに通常実行すればテストは全部成功します。

こんな感じでIntelliJを駆使してます。

おわりに

私がどうやってIntelliJを駆使してデバッグしているか、とりあえずパッと思いつく範囲でお届けしました。

Money Forward Developers

Discussion