ニュースアプリで起きた不具合から学んだ 最適への一歩

365 Views

April 20, 17

スライド概要

2017/04/19 CAMPFIRE Android #1
https://yj-meetup.connpass.com/event/53419/

profile-image

2023年10月からSpeaker Deckに移行しました。最新情報はこちらをご覧ください。 https://speakerdeck.com/lycorptech_jp

シェア

またはPlayer版

埋め込む »CMSなどでJSが使えない場合

(ダウンロード不可)

関連スライド

各ページのテキスト
1.

ニュースアプリで起きた不具合から学んだ 最適への一歩 2017年4月20日 ヤフー株式会社 矢端 智光 Co p yrig ht © 2 0 1 7 Yaho o Jap an Co rp o ratio n. All Rig hts Reserved .

2.

自己紹介 • • • • 矢端 智光 (ヤバタ トモミツ) 2012新卒 エンジニア Android開発歴 4年ぐらい 直近1年はアプリAPI等の開発で NodeJsさわったりchefさわったりしてました • 趣味はゲームとテニス 無(理のない)課金勢 Co p yrig ht © 2 0 1 7 Yaho o Jap an Co rp o ratio n. All Rig hts Reserved .

3.

Yahoo!ニュースアプリの中の人です Co p yrig ht © 2 0 1 7 Yaho o Jap an Co rp o ratio n. All Rig hts Reserved .

4.

もくじ • 最適0歩目 -「最適」について考える • 最適1歩目 - バグの事例を振り返る • Volleyとの別れを決めた夜 • LooperとHandlerの深い関係を語る • 最適n(>1)歩目 - まとめ Co p yrig ht © 2 0 1 7 Yaho o Jap an Co rp o ratio n. All Rig hts Reserved .

5.

最適0歩目 「最適」について考える Co p yrig ht © 2 0 1 7 Yaho o Jap an Co rp o ratio n. All Rig hts Reserved .

6.

なんだかんだ3周年も過ぎていた • 2013年11月20日にAndroid版の1.0.0をリリース • インストール数(GooglePlayストアの数字) 5,000,000~10,000,000 • 2016年3月にはTVCMも流れました Co p yrig ht © 2 0 1 7 Yaho o Jap an Co rp o ratio n. All Rig hts Reserved .

7.

「最適」について考えてみた • ユーザーに対して • プロダクションに対して • 開発者に対して Co p yrig ht © 2 0 1 7 Yaho o Jap an Co rp o ratio n. All Rig hts Reserved .

8.

おざなりにしてきた所 • ユーザーに対して • プロダクションに対して • 開発者に対して Co p yrig ht © 2 0 1 7 Yaho o Jap an Co rp o ratio n. All Rig hts Reserved .

9.

おざなりにしてた理由 • プロダクション優先・ユーザー優先 • Yahoo!ニュースアプリの歴史はまだ短い • 開発体制の定期的な変化 • 業務委託さんがいた時代 • オフショア開発をした時代 • 人がいなくなった時代 Co p yrig ht © 2 0 1 7 Yaho o Jap an Co rp o ratio n. All Rig hts Reserved .

10.

いつの時代にもニュースアプリには この男がいた Co p yrig ht © 2 0 1 7 Yaho o Jap an Co rp o ratio n. All Rig hts Reserved .

11.

この男がやってきたこと • • • • 2016/7までのニュースアプリ開発の大半は関わった 良いコードもクソコードも生み出してきた バグもひたすら殴り合いした 定期的なリファクタリングや 設計の見直しなどもやってきた • テストコードも少しずつ拡充 Co p yrig ht © 2 0 1 7 Yaho o Jap an Co rp o ratio n. All Rig hts Reserved .

12.

この男の最大の反省点 • 直したバグをPRとともに投げ捨て …てはいないですが 事例をまとめて整理していなかった • 多分PRにしか残っていないので 類似の事象が発生した時に過去の資料を探す 無駄な時間がかかっているというのを Android開発から離れて気づいた Co p yrig ht © 2 0 1 7 Yaho o Jap an Co rp o ratio n. All Rig hts Reserved .

13.

おざなりにしてきた所(再掲) • ユーザーに対して • プロダクションに対して • 開発者に対して Co p yrig ht © 2 0 1 7 Yaho o Jap an Co rp o ratio n. All Rig hts Reserved .

14.

最適1歩目 バグの事例を振り返る Co p yrig ht © 2 0 1 7 Yaho o Jap an Co rp o ratio n. All Rig hts Reserved .

15.

Chapter 1 Volleyとの別れを決めた夜 Co p yrig ht © 2 0 1 7 Yaho o Jap an Co rp o ratio n. All Rig hts Reserved .

16.

決別の理由 • 2013年から愛をこめて?使ってきたvolleyですが さすがに3年以上たつと色々な物を直したり追加したり …さすがに手が入りすぎて刷新する必要があった • 今は Okhttp + retrofitの構成です (一部volley残っていますが) Co p yrig ht © 2 0 1 7 Yaho o Jap an Co rp o ratio n. All Rig hts Reserved .

17.

つぎはぎしてきた項目 • レスポンスをGzipで取得するための処理 • レスポンスヘッダのキーが大文字小文字関係なく取得 できるように • ニュースのためのNetworkImageView • 特定機種やOSで発生する意図せぬエラーの ハンドリングなど …etc Co p yrig ht © 2 0 1 7 Yaho o Jap an Co rp o ratio n. All Rig hts Reserved .

18.

バグ事例1 ユーザーレビューより データが取得できない!エラーになる! 文字化けしてる! Co p yrig ht © 2 0 1 7 Yaho o Jap an Co rp o ratio n. All Rig hts Reserved .

19.

再現性がないバグ • レビューしてくださったユーザーと同じ端末・OSで APIのデータをとっても問題なし • 調査も難航 Co p yrig ht © 2 0 1 7 Yaho o Jap an Co rp o ratio n. All Rig hts Reserved .

20.

そんな中 • ある有力な手がかりがレビューに!!! 某通信量軽減アプリと併用をすると、 ニュースが引けなくなりました • 再現!! Co p yrig ht © 2 0 1 7 Yaho o Jap an Co rp o ratio n. All Rig hts Reserved .

21.

原因判明 ニュースアプリAPI • 原因は通信量軽減アプリが、 専用サーバをVPN起動で経由させ、 ニュースアプリAPIにアクセス • APIのレスポンスが加工される過程で ヘッダのキー値が全て小文字にかわる • 正常にレスポンスヘッダの値が取得できず、 文字化けしたり、デコードに失敗していた Co p yrig ht © 2 0 1 7 Yaho o Jap an Co rp o ratio n. All Rig hts Reserved . Content-Type 通信量軽減アプリ のサーバ content-type

22.

Chapter 2 LooperとHandlerの深い関係を語る Co p yrig ht © 2 0 1 7 Yaho o Jap an Co rp o ratio n. All Rig hts Reserved .

23.

バグ事例2 一覧画面のFragmentに機能を追加したらエラーでました(´;ω;`) java.lang.IllegalStateException: Recursive entry to executePendingTransactions Co p yrig ht © 2 0 1 7 Yaho o Jap an Co rp o ratio n. All Rig hts Reserved .

24.

補足 : 実装概略図 主要Fragment ページの位置 ページ番号 都道府県 Fragment Fragment page2 Page n 独自PagerAdapter 独自ViewPager Co p yrig ht © 2 0 1 7 Yaho o Jap an Co rp o ratio n. All Rig hts Reserved . …

25.

補足 : 実装概略図 主要Fragment ページの位置 ページ番号 都道府県 Fragment Fragment page2 Page n 独自PagerAdapter 独自ViewPager Co p yrig ht © 2 0 1 7 Yaho o Jap an Co rp o ratio n. All Rig hts Reserved . …

26.

原因 ViewPager上の2つの画面が 「自分を更新する」メソッドをonResumeのタイミングで同時に呼んだた め ViewPagerAdapter内のFragmentTransaction (FragmentManager#executePendingTransactions) が2度実行され Recursive entry to executePendingTransactions (IllegalStateException) で怒られた Co p yrig ht © 2 0 1 7 Yaho o Jap an Co rp o ratio n. All Rig hts Reserved .

27.

解決 「自分を更新する」メソッドが複数回呼ばれた場合 1度だけ実行される用に修正 ※詳細は後ページ Co p yrig ht © 2 0 1 7 Yaho o Jap an Co rp o ratio n. All Rig hts Reserved .

28.

ここまでは よく見るはなし Co p yrig ht © 2 0 1 7 Yaho o Jap an Co rp o ratio n. All Rig hts Reserved .

29.

解決方法の実装にあたって 「複数回実行しない」を満たすだけなら適当なフラグでも解決はできる …が フラグが氾濫するコードは嫌だ 冗長 Co p yrig ht © 2 0 1 7 Yaho o Jap an Co rp o ratio n. All Rig hts Reserved .

30.

HandlerとLooperのおはなし at android.os.Handler.handleCallback(Handler.java:725) at android.os.Handler.dispatchMessage(Handler.java:92) at android.os.Looper.loop(Looper.java:213) at android.app.ActivityThread.main(ActivityThread.java:5092) at java.lang.reflect.Method.invokeNative(Method.java) at java.lang.reflect.Method.invoke(Method.java:511) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:797) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:564) at dalvik.system.NativeStart.main(NativeStart.java) Co p yrig ht © 2 0 1 7 Yaho o Jap an Co rp o ratio n. All Rig hts Reserved .

31.

HandlerとLooperのお話 • 知ってる人は知っている。知らない人は覚えておくと 実装の幅が広がる気がする話 • Android開発者の誰しもが避けては通れない(たぶん) • メンバーに口頭説明した内容を少しだけ詳細化 • 本題から少し脱線…飲み物を飲みながらお聞きください Co p yrig ht © 2 0 1 7 Yaho o Jap an Co rp o ratio n. All Rig hts Reserved .

32.

Looper • Looper#prepare (prepareMainLooper)でLooper作成 • 実行するタスク(Message)が入る MessageQueueも作成 • Looper#loop -> MessageQueue#nextで MessageQueueを監視 Co p yrig ht © 2 0 1 7 Yaho o Jap an Co rp o ratio n. All Rig hts Reserved . Looper Message Queue

33.

Handler -> Looper Looper • おなじみHandler作成 Handlerにタスク(Message)を 送る対象のLooperを指定 (未指定なら実行スレッド上のLooper) Message Queue Handler Co p yrig ht © 2 0 1 7 Yaho o Jap an Co rp o ratio n. All Rig hts Reserved .

34.

Handler -> Looper Looper MessageやRunnableのインスタンスを Handlerを経由してpostすると MessageQueueにenqueueされる Message Queue Message 1 Handler Message 2 Message 3 Co p yrig ht © 2 0 1 7 Yaho o Jap an Co rp o ratio n. All Rig hts Reserved .

35.

Looper#loop • Queueに入ったタスクをLooperが拾い 順次実行されていく流れとなります Looper Message Queue loop Message 2 Message 3 Co p yrig ht © 2 0 1 7 Yaho o Jap an Co rp o ratio n. All Rig hts Reserved . Message 1

36.

Looper#loop • Queueに入ったタスクをLooperが拾い 順次実行されていく流れとなります シンプルにいこう Looper Message Queue Message 2 Message 3 Co p yrig ht © 2 0 1 7 Yaho o Jap an Co rp o ratio n. All Rig hts Reserved . loop Message 1

37.

細かい事は省略 MainLooper まずはAndroidの処理は 同じUIスレッド上でも細切れ? になってることがわかればOK\(^o^)/ onCreate onResume FragmentTransaction Runnable ・ ・ ・ Co p yrig ht © 2 0 1 7 Yaho o Jap an Co rp o ratio n. All Rig hts Reserved .

38.

原因(再掲) ViewPager上の2つの画面が 「自分を更新する」メソッドをonResumeのタイミングで同時に呼んだた め ViewPagerAdapter内のFragmentTransaction (FragmentManager#executePendingTransactions) が2度実行され Recursive entry to executePendingTransactions で怒られた Co p yrig ht © 2 0 1 7 Yaho o Jap an Co rp o ratio n. All Rig hts Reserved .

39.

溢れ出る冗長感 • どうせなら同じようなタスクは1度だけで 済ませたい • 修正量も少なめで対応したい • そうだHandlerを使おう Co p yrig ht © 2 0 1 7 Yaho o Jap an Co rp o ratio n. All Rig hts Reserved .

40.

Handlerで 実行するRunnableを制御 • ページから更新要求があったら handlerでRunnableをpostする • postしたRunnableが実行される前に 再度要求があっても無視をする MainLooper onResume 更新処理 更新処理‘ Co p yrig ht © 2 0 1 7 Yaho o Jap an Co rp o ratio n. All Rig hts Reserved .

41.

コード(概略) final Message message = _mHandler.obtainMessage(); if (!_mHandler.hasMessages(message.what)) { _mHandler.post(new Runnable() { // 更新処理 }) } Co p yrig ht © 2 0 1 7 Yaho o Jap an Co rp o ratio n. All Rig hts Reserved .

42.

解決 • ただし処理をずらすので、 書き方次第では実行されるまでの間に 参照している値やメソッドの返り値に変更が発生する 可能性があることは念頭においておきましょう Co p yrig ht © 2 0 1 7 Yaho o Jap an Co rp o ratio n. All Rig hts Reserved .

43.

最適n歩目 まとめ Co p yrig ht © 2 0 1 7 Yaho o Jap an Co rp o ratio n. All Rig hts Reserved .

44.

集合知の大切 • 「バグは恥ずかしい」かもしれない でも「バグ恥ずかしいから誰にも聞けない」 にならないといいですね • 周りのできる人も手を差し伸べてあげてください • 不具合に対するナレッジも共有していくことで 最適への一歩を踏み出し Androidの開発力をUPDATEしていっていただければいいなと思い ます Co p yrig ht © 2 0 1 7 Yaho o Jap an Co rp o ratio n. All Rig hts Reserved .

45.

Fin Co p yrig ht © 2 0 1 7 Yaho o Jap an Co rp o ratio n. All Rig hts Reserved .