動画広告を最後まで見たのに見返りが渡らない — 犯人は自分が仕掛けた保険だった — 制作日誌 #13
ビジネス

動画広告を最後まで見たのに見返りが渡らない — 犯人は自分が仕掛けた保険だった — 制作日誌 #13

「広告を見たのに機能が解放されない」という不具合。原因は、読み込み失敗に備えて置いた30秒の見切りタイマーが、視聴中も生きていたこと。日本の動画広告は30秒ものが多く、保険が動画と競走していた。

KIYODO00
#個人開発#iOS#広告#設計ミス#制作日誌

自作アプリには、本人が押して見る種類の動画広告がある。最後まで見ると、AIの提案が使える回数が増える。よくある「広告を見て解放」の仕組みだ。

ここに「広告を見たのに解放されない」という不具合があった。しかも毎回ではなく、たまに

保険のつもりで置いたタイマー

動画広告は、読み込みに失敗することがある。在庫が無い、通信が悪い、といった理由だ。何もしないと、読み込み中の表示が出たまま画面が固まってしまう。

そこで見切りタイマーを置いていた。「30秒待っても始まらなければ、失敗として扱って画面を戻す」という保険だ。ここまでは妥当な判断だと思う。

問題はタイマーを止めるタイミングだった。私は読み込めた後もタイマーを動かしたままにしていた。すると、こうなる。

  1. 広告の読み込みを始める。同時に30秒のタイマーを起動
  2. 3秒で読み込みが完了し、動画が再生され始める
  3. タイマーはまだ動いている
  4. 30秒たった時点でタイマーが鳴る。処理は「失敗した」と確定して、見返りを渡さないと決める
  5. その数秒後、動画を見終わった合図が届く。すでに失敗が確定しているので捨てられる

つまり保険が、動画の長さと競走していた。

なぜ「たまに」だったのか

日本で配信される動画広告は、30秒ものがかなり多い。だが15秒や20秒で終わるものもある。

動画の長さ起きること
15〜20秒見終わってからタイマーが鳴る → 正常に見返りが渡る
30秒以上タイマーが先に鳴る → 見たのに渡らない

再現しようとすると、短い広告に当たった回は普通に動いてしまう。「たまに動く」ほど原因の切り分けが難しい状態はない。 動くケースがあるせいで「実装は合っている、たまたま何かがおかしい」と考えてしまうからだ。

そのうえ、この不具合を踏んだ人からは「広告を見たのに消えない」としか見えない。広告が悪いのか、通信が悪いのか、アプリが悪いのかも分からない。苦情の言葉から原因を推測することは、ほぼ不可能だった。

直し方

修正そのものは数行だった。考え方を3つに整理した。

1. 保険は「読み込み中だけ」の保険にする。 読み込み完了の合図が来た時点で、タイマーを必ず解除する。保険が守るべき事故は「始まらないこと」であって、「長いこと」ではない。

2. 見返りは視聴完了の合図が来たその瞬間に渡す。 以前は「広告が閉じた」合図を待ってから渡していた。だが閉じる合図は、端末や配信の都合で遅れたり来なかったりする。視聴完了の合図こそが、渡してよいという唯一の根拠なので、そこで渡す。

3. それでも二重に取る。 「閉じた」でしか判定できない端末のために、そちらの経路も残しておく。ただし付与は1回に絞る。取りこぼしより、渡しすぎのほうが後から直しやすい。

見つけるまでに遠回りした経路

原因にたどり着くまでに、私は関係のない場所を2つ疑っている。記録として残しておく。

遠回り1:広告の在庫を疑った。 「見返りが渡らないのは、そもそも広告が最後まで再生されていないからでは」と考えて、配信側のレポートを見に行った。表示回数は正常に立っていた。ここでアプリの外は無実だと確定できたので、無駄ではなかったが半日使った。

遠回り2:見返りを書き込む側を疑った。 付与の処理は残高を書き換えるので、そこが失敗しているのだと思った。ログを仕込んで確かめると、付与の処理は呼ばれてすらいなかった。呼ばれていないなら原因は手前にある、と分かってようやく上流へ視線が戻った。

この2つを踏んで学んだのは、「呼ばれていない」と「呼ばれたが失敗した」を最初に切り分けると早い、ということだった。前者なら上流、後者なら下流。この一問で調査範囲が半分になる。

学んだこと

  • 保険は、守る対象を限定して書く。 「念のため全体に掛ける」保険は、正常系まで巻き込む。今回まさに正常な視聴を巻き込んでいた
  • タイマーを起動したら、解除する場所を同じ画面内に必ず書く。 起動と解除が離れると、解除の抜けは目視で見つからない
  • 「たまに動く」は最優先の調査対象。 全部壊れているより厄介で、動く回があるせいで実装への疑いが弱まる
  • 時間で判定する処理は、相手の時間を調べてから書く。 30秒という数字は、私が何も調べずに置いた値だった。日本の動画広告の長さを先に知っていれば、そもそもこの数字にはしていない
  • 収益の計上と見返りの付与は別経路にする。 今回は収益の計上だけ無事だったので、被害が片側で止まった

一番効いたのは最後の点だ。「壊れても片方は生きる」という作りにしておくと、壊れたときに何が起きたかを推測しやすくなる。 今回も「収益は立っているのに見返りだけ渡っていない」という形が、原因の範囲を一気に狭めてくれた。

補足:この手の保険を書くときの型

同じ形の処理を書くときに、私が使うようになった順序を残しておく。

  1. 保険が守る事故を1つだけ言葉にする(今回なら「読み込みが始まらない」)
  2. その事故が起きうる区間を決める(読み込み開始から完了まで)
  3. 区間を抜けた瞬間に必ず解除する
  4. 解除の抜けを検出するために、保険が発動したときは必ず記録を残す(発動が想定より多ければ、区間の設定が間違っている)

4つめが特に効く。今回も、保険の発動を記録していれば「読み込みは成功しているのに保険が発動している」という矛盾が数字で見えていたはずだった。

Comments (0)

No comments yet. Be the first to leave one.