0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

null の原因が分からない人へ

0
Posted at

はじめに

・さっきまで値が入っていた
・途中で突然 null になる
・どこで消えたのか分からない

👉 こんな経験ありませんか?

例えば、

var user = GetUser();

var name = user.Name;

実行すると、

NullReferenceException

になる。

でも、

👉 「user はさっき見た時、値入ってたよね?」

となる。

実務では、

👉 「どこで null になったのか分からない」

で止まることがかなり多いです。

この記事の位置づけ(シリーズ)

これまでのシリーズでは、

・処理が追えない
・意味が分からない
・どこに書けばいいか分からない

など、

👉 「コード理解」

について整理してきました。

今回はその中でも、

👉 「値の追い方」

にフォーカスします。


なぜ null が追えなくなるのか

理由はシンプルです。

👉 “値が変わるポイント”を見れていないから

多くの人は、

👉 「今の値」

だけを見ています。

でも重要なのは、

👉 「どこで変わったか」

です。

よくある勘違い

nullになると、

👉 「この行がおかしい?」

と思いやすい。

例えば、

var name = user.Name;

ここで例外が出ると、

👉 「Name取得がおかしい?」

と思う。

でも実際には、

👉 user が null

なだけ。

本当に見るべき場所

重要なのは、

👉 「最後に正常だった場所」

です。

つまり、

「どこで壊れた?」

ではなく、

「最後に正常だったのはどこ?」

を追う。

null調査で重要な考え方

null調査は、

👉 「逆向き」に追います

例えば、

var user = repository.Get(id);

var name = user.Name;

ここで null なら、

まず確認するのは👇

repository.Get(id)

の戻り値。

さらに遡る

もし、

return cache.Get(id);

なら、

👉 cache の中を見る。


つまり、

結果
↑
戻り値
↑
取得元
↑
入力値

と、

👉 逆向きに辿る

よくある null 発生パターン

パターン① 初期化漏れ

かなり多いです。

User user;

だけで、

👉 new していない

症状

user.Name

で落ちる。


パターン② 条件分岐で代入されていない

User user = null;

if (isLogin)
{
    user = GetUser();
}

isLogin == false

だと、

👉 user は null のまま


パターン③ 非同期で値が変わる

これ実務でかなり多い。

await LoadAsync();

user.Name

一見問題なさそう。

でも実際には、

👉 await 中に状態が変わる

ことがある。


パターン④ 別処理で上書きされる

例えば、

currentUser = null;

が別イベントで動いている。


すると、

👉 「さっきまで値あったのに」

になる。

null調査でありがちなミス

❌ 例外行だけ見る

かなり多い。


例えば、

user.Name

で落ちても、

👉 本当の原因はもっと前


❌ 今の値だけ見る

これも多い。


重要なのは、

👉 「どう変化したか」

です。


❌ 全部追おうとする

これも迷子になる。


正解は、

👉 「最後に正常だった場所」

から追うこと。

実際の調査イメージ

例えば、

① null が発生
↓
② 直前の値確認
↓
③ どこから来たか確認
↓
④ その戻り値確認
↓
⑤ さらに遡る

👉 これを繰り返す

ブレークポイントで見る場所

重要なのはこれです。


✔ 代入直後

user = GetUser();

👉 ここで値を見る


✔ 戻り値直前

return user;

👉 ここで null になってないか確認

✔ 条件分岐

if (user != null)

👉 分岐条件を見る


「nullになった場所」と「原因の場所」は違う

ここかなり重要。

例えば、

user.Name

で落ちても、

原因は👇

・初期化漏れ
・条件分岐
・非同期
・別イベント

かもしれない。


つまり、

👉 「落ちた場所」

ではなく、

👉 「値が変わった場所」

を見る必要があります。

まとめ

null が追えなくなる原因の多くは、

👉 “値の変化”を追えていないこと

です。

重要なのは、

・今の値
ではなく、

👉 「どこで変わったか」

を見ること。

そして、

👉 「最後に正常だった場所」

から逆向きに追うことです。

✔ 1つだけ意識するなら

👉 「最後に値が正常だった場所はどこ?」

これを意識するだけで、

👉 null調査はかなりやりやすくなります

実務では、

👉 「nullになった」

より、

👉 「なぜ null になった?」

を調査することの方が重要です。

最初は難しく感じますが、

👉 値の流れを逆向きに追う

ことを意識すると、
少しずつ原因が見えるようになります。

もし、

「この null の追い方で困った」
「このケースでハマった」

などあれば、ぜひ教えてください。

今後の記事で取り上げていきます。

0
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?