Webエンジニア向けプログラミング解説動画をYouTubeで配信中!
▶ チャンネル登録はこちら

【ITニュース解説】The Silent Alert Bug: When Your Instant Push Exists but Never Fires

2026年10月12日に「Dev.to」が公開したITニュース「The Silent Alert Bug: When Your Instant Push Exists but Never Fires」について初心者にもわかりやすく解説しています。

作成日: 更新日:

ITニュース概要

プッシュ通知が届かない原因は、通知作成関数が定義されているがどこからも呼び出されていないデッドコードだった。誤ったコメントが原因で誰も呼び出しを追加せず、問題が放置された。コードは定義より呼び出し箇所を監査し、実行パスを検証することが重要である。

ITニュース解説

「ユーザーからプッシュ通知が届かない」という報告は、ITシステム開発においてよくあるトラブルの一つだが、その背後には見過ごされがちな、システムエンジニアの誰もが注意すべき重要な問題が潜んでいることがある。

今回の事例は、まさにその典型だ。あるシステムで、新規注文やイベントが発生した際に即座にユーザーのスマートフォンに届くはずの「インスタントプッシュ通知」が、突然機能しなくなった。不思議なことに、毎日定期的に送られる「デイリーレポート」は正常に届き、そのフォーマットも問題ない。プッシュ通知サービス自体も正常に稼働しており、手動でテストプッシュを送るとちゃんとユーザーの元に届く。つまり、プッシュ通知を運ぶ「パイプライン」は生きている。このことから、問題は通知を実際に「発動させる」プログラムのコード内部にあると推測される。

開発者は、プッシュ通知のメッセージを作成する関数を探した。見つかったのはformat_instant_alertという関数だ。この関数は、注文の詳細情報を受け取り、ユーザーにわかりやすい一行のプッシュメッセージを生成する。コードは非常にシンプルで、これまで何ヶ月も問題なく動作していた。見た目には全く問題がなく、「クリーンで、テスト済みで、正しい」状態だ。

しかし、このformat_instant_alert関数がプログラムのどこで使われているかを調べると、驚くべき事実が判明した。この関数が呼び出されている場所は、その「定義」が書かれている場所だけだったのだ。つまり、システム内の他のどのコードからも、この関数は一切呼び出されていなかった。定義された関数が、実はシステムのどの部分からも一度も使われない状態。これが「デッドコード」と呼ばれるものだ。デッドコードは、無駄なリソースを消費するだけでなく、プログラムの理解を妨げ、今回のように重要な機能が動作しない原因となることもある。ユーザーの「プッシュが壊れている」という感覚は誤りで、実際には「プッシュがそもそもシステムに組み込まれていなかった」のだ。まるで、美しい姿をしていても、魂の宿らない「作りかけの体」のように、この関数は存在していても決して機能することはなかった。

さらに調査を進めると、事態はもっと深刻であることが分かった。このシステムには、注文を処理する四つの異なる方法(コマンドラインからの手動入力、スケジュールされた戦略の実行、ウェブフックからの信号、システム再起動後の復旧処理)が存在していた。これら四つの処理パスは、それぞれが注文処理ロジックのブロックを持っていたが、それらは初期段階でコピー&ペーストされ、その後個別に変更が加えられていた。そして、それぞれのブロックには、次のようなコメントが添えられていた。「# open the position, update state, push is integrated into the daily report」(ポジションを開き、状態を更新する。プッシュはデイリーレポートに統合されている)。

この同じコメントが四つの場所に存在し、四つの場所すべてで誤った仮定を伝えていた。元のコードを書いた開発者は、プッシュ通知がデイリーレポートの生成時に処理されると信じていたため、インスタントプッシュメッセージを生成する関数を呼び出すコードを追加しなかった。その後、このコードがコピー&ペーストされるたびに、このコメントと、通知の呼び出しの「抜け落ち」も一緒に引き継がれてしまったのだ。

このような「どこかで処理される」というコメントは、非常に危険だ。コメントは単なる記述であり、実際のコードの動作を強制する仕組みはない。もし「どこか」のコードが変更されたり、あるいは最初からそのケースを処理していなかったりしても、コメントだけはそのまま残り、自信満々に嘘をつき続ける。そして、それがコピー&ペーストされると、この嘘がシステム全体に広まってしまうのだ。今回のケースでは、デイリーレポートにはインスタントアラートは含まれていなかったし、これまで一度も含まれたことはなかった。このコメントは単なる願望か、あるいはすでに廃止された設計を指していたのだろう。しかし、誰もその真偽を再確認することはなかった。なぜなら、コメントは書くのが簡単で、読むと理解したような気分になるからだ。

この問題に対処するための基本的な原則は、「デッドコード」を見つけるには、関数が「どこで定義されているか」ではなく、「どのように使われているか」を調べることだ。定義を探すことは、その関数が存在することだけを教えてくれる。しかし、その関数が「本当にシステムにとって意味があるのか」、つまり実際に実行される可能性があるのかを教えてくれるのは、その関数が「呼び出されている箇所」(コールサイト)を探すことだ。これら二つの質問を混同してしまうことが、デッドコードが監査をすり抜け、システムに残り続けてしまう主な理由となる。システムエンジニアを目指す上で、コードの「使われ方」を常に意識することは非常に重要だ。

具体的な手順としては、まず「本来動作するはずなのに動作していない」と疑われる関数をリストアップする。今回のケースでは、format_instant_alertのようなメッセージフォーマット関数や、send_pushのような通知送信関数が該当する。次に、これらの各関数がシステム内でどれだけ呼び出されているかを数える。手作業で一つずつ調べることもできるが、多数の関数がある場合はスクリプトを使って自動化するのが効率的だ。例えば、Pythonのコードであれば、プログラムコードを解析して関数の定義を抽出し、その関数名が他のファイルでどれだけ言及されているかを検索するスクリプトを作成できる。

このスクリプトを実行すると、各関数の呼び出し回数が表示される。例えば、「format_instant_alert calls=0」のように表示されれば、それは間違いなくデッドコードであるという確実な証拠だ。定義はされていても、誰にも使われていない「煙の上がらない銃」のような状態だ。もし呼び出し回数がゼロでなければ、それは「疑わしいリード」ではあるが、結論ではない。なぜなら、関数が「呼び出されている」と表示されても、その呼び出しが特定の条件分岐の中にあり、実運用では決してその条件が満たされない可能性があるからだ。

例えば、「手動入力の場合のみプッシュ通知を送信する」という条件分岐があったとする。この場合、format_instant_alertは呼び出し箇所を持つためスクリプトでは「ok」と判断される。しかし、ほとんどの注文がスケジュールやウェブフック経由で自動的に処理される場合、この条件分岐はほとんど実行されず、結果としてインスタントプッシュ通知は機能しないことになる。これを検出するためには、各注文処理パスを追跡し、プッシュ通知の呼び出しが、実際に実行されるコードブロックの中に含まれているかを確認する必要がある。もし呼び出しが、実運用で満たされない条件によって守られているのであれば、それは事実上デッドコードとして扱うべきだ。

このような問題を見つけた際の修正方法にも注意が必要だ。安易に「ユーザーが不満を言っているパスだけを修正する」という対応は避けよう。それでは残りの三つのパスはサイレントなままで、数週間後には別のユーザーから同じ不具合の報告が来るかもしれない。正しい修正方法は、同じロジックを持つすべての箇所を一度に修正することだ。今回の事例では、誤ったコメントが書かれた四つの注文処理ブロックすべてに、インスタントプッシュの呼び出しを追加することになる。修正時には、その場にある古くて誤ったコメントも忘れずに削除しよう。「他の場所で処理される」というコメントは、コメントがないよりも悪い結果を招くことがある。それは、次にコードを読む人の疑念を積極的に抑え込んでしまうからだ。

さらに、もし可能であれば、重複した注文処理ロジックを一つの共通関数にリファクタリング(整理し直すこと)することも強く推奨される。四つの異なるパスで同じようなロジックがコピー&ペーストされていること自体が根本的な原因であり、コメントの腐敗はその症状に過ぎない。全てのパスが共通のopen_position関数を呼び出すようにすれば、プッシュ通知が発火する場所は一つになり、その後の監査もはるかに簡単になる。そして、将来的に五つ目の注文エントリーパスが追加されたとしても、この共通関数を呼び出すだけでアラート機能が自動的に提供されるようになる。

修正後も、監査スクリプトを再実行して、format_instant_alertが期待通りに呼び出されているかを確認する。そして、さらに一歩進んで、実際に各パスが実行時にその呼び出しに到達することを確認することが重要だ。最も確実な検証方法は、プッシュ通知の呼び出し箇所にログ出力を追加し、各処理パスに対してテストを実行することだ。例えば、「インスタントアラートをディスパッチしています」といったログが出力されることを確認し、さらに単体テストで、すべての注文エントリーパスがプッシュ通知をディスパッチしたことを検証するアサーションを追加する。このテストがあれば、将来誰かが誤ってアラートをスキップするようなコード変更を行った場合でも、すぐに不具合を検出できる。

この「デッドコード」や「未実行の副作用」の問題は、プッシュ通知に限った話ではない。これは「ある処理が、どこか別の場所で誰かに処理されるはずだ」という仮定が原因で発生する、コードパスの監査に関する一般的な問題だ。例えば、特定の機能が実装されているにも関わらず、どこからも呼び出されない「クリーンアップルーチン」、特定のエラーブランチでしか実行されない「ログ出力」、定義されているだけで決して値が増えない「メトリクス」、あるいは使われていない古いクライアントにアタッチされたままの「リトライハンドラ」など、さまざまな形で現れる。

どのようなケースであっても、解決のための手順は同じだ。まず、動作するべき関数をリストアップし、その「定義」ではなく「呼び出し箇所」を検索する。呼び出しがゼロであれば、それは例外なくデッドコードとみなす。たとえ「動的に呼び出されているはずだ」という主張があっても、まずはデッドと判断するのが安全だ。呼び出し箇所が見つかっても、それが条件によってガードされている場合は要注意だ。そのガード条件が、実際の運用で満たされることを確認する必要がある。問題が見つかったら、同じロジックが複製されている箇所はすべて一括で修正し、可能であればリファクタリングする。そして最後に、ログ出力やテストを通じて、修正した処理が実際に実行されることを証明するのだ。

この問題で本当に時間とコストがかかったのは、通知メッセージを整形する関数を書くことではなかった。むしろ、「この作業はすでに他の場所で完了している」と書かれた四つのコメントこそが、高価な代償を払わせた原因だ。コメントは決してプログラムを実行しない。実際にシステムを動かすのは、コードの「呼び出し」なのだ。システムエンジニアを目指す上で、コードの定義だけでなく、その「使われ方」にまで目を凝らす習慣を身につけることは、将来のトラブルを未然に防ぐ強力な武器となるだろう。

関連コンテンツ

関連IT用語