Lock in $30 Savings on PRO—Offer Ends Soon! ⏳

モバイルアプリのオブザーバビリティを向上させるプラクティス

nade
September 12, 2022

 モバイルアプリのオブザーバビリティを向上させるプラクティス

https://fortee.jp/iosdc-japan-2022/proposal/6bafac07-06f1-4846-964e-78dccfb29185

【iOSDC Japan 2022 09/12 11:25〜 Track E レギュラートーク(20分)】
近年、SRE(Site Reliability Engineering)の手法をアプリケーションにまで拡大しようといった動きが盛んです

しかし、実際にモバイルアプリの可観測性≒オブザーバビリティを向上させるためには、ネイティブエンジニアの専門性が求められる場面が多く、あまり実際に効果のあった事例が共有されていないように感じます

このトークでは
- アプリ内で計測される指標を用いてSLI / SLOを構成する
- アプリ内でのレスポンスのパースエラー検知
- 問い合わせ調査のオブザーバビリティ向上
- 外部SNSの認証サービスの障害検知
- App Store Connect API 、MeticKitの活用
といった実際にチームで効果のあったプラクティスを紹介したいと思います

nade

September 12, 2022
Tweet

More Decks by nade

Other Decks in Programming

Transcript

  1. ࣗݾ঺հ ͳͰʢ @kazuma_nagano ʣ ॴଐ • αΠόʔΤʔδΣϯτ ◦ λοϓϧ ▪

    SREνʔϜ • iOSΤϯδχΞ • ࠷ۙ͸BFFΛKMMܦ༝ͰiOS͔Βݺͼग़࣮͢૷ΛҰ௨Γ ॻ͘τϦϦϯΨϧͳΤϯδχΞΛ΍ͬͯ·͢
  2. SREॴଐͷϞόΠϧΤϯδχΞʹ • SREνʔϜʹϞ バ ΠϧΤϯ ジ χΞ(iOSɺAndroid֤1ਓ) が ઐଐ で

    ॴଐ͢Δܗ • ϛογϣϯ͸ʮαʔϏεͷ৴པੑͷ޲্ʯ 
 ❌ ϞόΠϧͷج൫։ൃɺϦΞʔΩςΫνϟਪਐɺQA
  3. SREͱ͸ʁ from wikipedia • αΠτɾϦϥΠΞϏϦςΟɾΤϯδχΞϦϯάʢӳɿSite Reliability Engineeringɺ ུɿSREʣ͸ɺGoogle͕ࣾఏএɺ࣮ફ͍ͯ͠ΔγεςϜ؅ཧͱαʔϏεӡ༻ͷํ๏ ࿦Ͱ͋Δ •

    αΠτϦϥΠΞϏϦςΟΤϯδχΞϦϯάΛ୲౰͢ΔΤϯδχΞΛαΠτϦϥΠΞϏ ϦςΟΤϯδχΞʢSREʣͱݺͿ https://ja.wikipedia.org/wiki/αΠτϦϥΠΞϏϦςΟΤϯδχΞϦϯά
  4. Site Reliability Engineering • ʮαΠτɺαʔ ビ εͷ৴པੑΛकΔ ʯ • Googleʹ͓͚ΔDevOpsΛ࣮ફ͢ΔνʔϜ

    ◦ 2004೥͔Β͋ΔΒ͍͠ • ಠࣗͷӡ༻ プ ϥΫςΟε͕·ͱ·ͬͯΔ 
 e.g.) SLI / SLO, SLA, ΤϥʔόδΣοτɺɺɺ 
 → ʮαʔϏεͷՄ༻ੑʯΛͲ͏ଛͳΘͣʹ࡞Γଓ͚Δ͔ʁ
  5. Engineering Reliable Mobile Applications • GoogleͷSREνʔϜͷߟ͑ΔϞ バ ΠϧΞ プ Ϧʹ͓͚Δ

    SREͱ͸Կ͔ʁ • ৴པੑͷ؍఺͔ΒΈͨ࣌ͷWebΞϓϦͱͷҧ͍ • Case Studies https://www.oreilly.com/library/view/engineering-reliable-mobile/9781492057444/
  6. Ϟ バ ΠϧΞ プ ϦͳΒ で ͸ͷ೉͠͞ • デ バ

    Πε਺ɺϞ デ ϧͷछྨଟ͗͢ ◦ ෆ۩߹ͷ࠶ݱ΍ݪҼಛఆ͕ࠔ೉ • ίϯτϩʔϧͰ͖ͳ͗͢͞ ◦ Ϟ バ Πϧ͸Ξο プデ ʔτͷλΠϛϯ グ ΍ద༻͸Ϣʔ ザ ࣍ୈ • ϞχλϦϯάେม͗͢ ◦ ϋʔ ド ΢ΣΞͷछྨɺঢ়ଶɺOSɺෳ਺ バ ʔ ジ ϣϯͱϩ グが ଟ࣍ݩ • มߋ؅ཧΉͣա͗ ◦ Ϟ バ Πϧʹ͸ϩʔϧϑΥϫʔ ド ͔͠ͳ͍ ɺมߋʹඞཁͳϦʔ ド λΠϜ΋௕͍
  7. ΦϒβʔόϏϦςΟͷ޲্ ద੾ͳΦϒβʔόϏϦςΟΛ࣮ݱ͢Δʹ͸ɺ࣍ͷ΋ͷ͕ඞཁ 
 Ϩϙʔτ • γεςϜશମͷঢ়ଶʢػೳ͍ͯ͠Δ͔ɺϦιʔεෆ଍͕ͳ͍͔ʣ • γεςϜͷϢʔβʔମݧʢར༻Ͱ͖Δ͔ʁૢ࡞্ͷ໰୊͸ͳ͍͔ʁʣ ϞχλϦϯά •

    ओͳϏδωεࢦඪͱγεςϜࢦඪ τϨʔε • ຊ൪؀ڥͷγεςϜͷঢ়ଶΛ֬ೝͯ͠σόοάͰ͖Δπʔϧ • ͜Ε·ͰೝࣝͰ͖ͳ͔ͬͨ͜ͱΛ֬ೝͰ͖Δπʔϧ • ຊ൪؀ڥͷ໰୊ͷτϨʔεɺ֬ೝɺ਍அʹ໾ཱͭπʔϧ
  8. ཧ૝తͳΦϒβʔόϏϦςΟ όοΫΤϯυϕʔεͷΦϒβʔόϏϦςΟͱͷൺֱ UI / UX Server Apps Infra • Request

    Latency • Success Rate • CPU Usage • DB Connection ΞϓϦ಺෦Ͱى͖͍ͯΔ໰୊ 
 ࣮ࡍͷϢʔβʔମݧ
  9. ΦϒβʔόϏϦςΟͷ޲্ ద੾ͳΦϒβʔόϏϦςΟΛ࣮ݱ͢Δʹ͸ɺ࣍ͷ΋ͷ͕ඞཁ 
 Ϩϙʔτ • γεςϜશମͷঢ়ଶʢػೳ͍ͯ͠Δ͔ɺϦιʔεෆ଍͕ͳ͍͔ʣ • γεςϜͷϢʔβʔମݧʢར༻Ͱ͖Δ͔ʁૢ࡞্ͷ໰୊͸ͳ͍͔ʁʣ ϞχλϦϯά •

    ओͳϏδωεࢦඪͱγεςϜࢦඪ τϨʔε • ຊ൪؀ڥͷγεςϜͷঢ়ଶΛ֬ೝͯ͠σόοάͰ͖Δπʔϧ • ͜Ε·ͰೝࣝͰ͖ͳ͔ͬͨ͜ͱΛ֬ೝͰ͖Δπʔϧ • ຊ൪؀ڥͷ໰୊ͷτϨʔεɺ֬ೝɺ਍அʹ໾ཱͭπʔϧ
  10. ࢀߟ) ϝτϦΫε֬ೝͰݟ͍ͯΔ΋ͷ ωΠςΟϒ • Firebase Crashlytics ◦ Ϋϥογϡ཰ • Firebase

    Performance ◦ ىಈ଎౓ɺωοτϫʔΫ଎౓ɺϨϯμϦϯά଎౓ • Xcode Metrics ◦ Battery Usage, Disk Write, Hang Rate, Launch Time, Memory, Scrolling, Terminations • ͦͷଞ ◦ ΞϓϦαΠζʢϦϦʔεϏϧυͷipaαΠζʣ
  11. 1ͭͷμογϡϘʔυʹू໿ Firebase Xcode Metrics Firebase Performance Firebase Crashlytics User Crash

    Key Metrics Google Data Portal Auto Export BigQuery Intermediate table BigQuery = Intermediate table BigQuery App Store Connect API Google Data Portal
  12. ΦϒβʔόϏϦςΟͷ޲্ ద੾ͳΦϒβʔόϏϦςΟΛ࣮ݱ͢Δʹ͸ɺ࣍ͷ΋ͷ͕ඞཁ 
 Ϩϙʔτ • γεςϜશମͷঢ়ଶʢػೳ͍ͯ͠Δ͔ɺϦιʔεෆ଍͕ͳ͍͔ʣ • γεςϜͷϢʔβʔମݧʢར༻Ͱ͖Δ͔ʁૢ࡞্ͷ໰୊͸ͳ͍͔ʁʣ ϞχλϦϯά •

    ओͳϏδωεࢦඪͱγεςϜࢦඪ τϨʔε • ຊ൪؀ڥͷγεςϜͷঢ়ଶΛ֬ೝͯ͠σόοάͰ͖Δπʔϧ • ͜Ε·ͰೝࣝͰ͖ͳ͔ͬͨ͜ͱΛ֬ೝͰ͖Δπʔϧ • ຊ൪؀ڥͷ໰୊ͷτϨʔεɺ֬ೝɺ਍அʹ໾ཱͭπʔϧ
  13. ϞόΠϧΞϓϦͷSLI / SLOߏங SLI / SLOͱ͸ SLI(Service Level Indicator) :

    αʔ ビ εͷՄ༻ੑɺ඼࣭Λܭଌ͢Δࢦඪ SLO(Service Level Objective) : ֤SLIʹର͢Δ໨ඪ஋
  14. ϞόΠϧΞϓϦͷSLI / SLOߏங Մ༻ੑͷఆٛΛ޿͛Δ Ξ プ Ϧέʔγϣϯ が ར༻Մೳ で

    ͳ͍ঢ়ଶͷྫ • ΞΠίϯΛλο プ ͨ͠ が ɺΞ プ Ϧ が ͳ͔ͳ͔ىಈ͠ͳ͍ 
 => ىಈ࣌ؒ • ボ λϯΛλο プ ͯ͠΋ɺΞ プ Ϧ が ൓Ԡ͢Δؾ഑ が ͳ͍ 
 => ը໘଺ࡏ࣌ؒ • ͭͶʹԿ΋ͳ͍ը໘ が දࣔ͞Ε͍ͯͯɺίϯςϯπ が ݟΕͳ͍ 
 => ϨεϙϯεͷύʔεΤϥʔ • ಈ͖ が ΋ͬ͞Γ͢͠ ぎ ͯ࢖͍෺ʹͳΒͳ͍ 
 => ϑϨʔϜͷϨϯ ダ Ϧϯ グ ଎౓
  15. ϞόΠϧΞϓϦͷSLI / SLOߏங Մ༻ੑͷఆٛΛ޿͛Δ Ξ プ Ϧέʔγϣϯ が ར༻Մೳ で

    ͳ͍ঢ়ଶͷྫ • ΞΠίϯΛλο プ ͨ͠ が ɺΞ プ Ϧ が ͳ͔ͳ͔ىಈ͠ͳ͍ 
 => ىಈ࣌ؒ • ボ λϯΛλο プ ͯ͠΋ɺΞ プ Ϧ が ൓Ԡ͢Δؾ഑ が ͳ͍ 
 => ը໘଺ࡏ࣌ؒ • ͭͶʹԿ΋ͳ͍ը໘ が දࣔ͞Ε͍ͯͯɺίϯςϯπ が ݟΕͳ͍ 
 => ϨεϙϯεͷύʔεΤϥʔ • ಈ͖ が ΋ͬ͞Γ͢͠ ぎ ͯ࢖͍෺ʹͳΒͳ͍ 
 => ϑϨʔϜͷϨϯ ダ Ϧϯ グ ଎౓
  16. Մ༻ੑΛ΋ͱʹͨ͠SLIΛઃఆ ڞ௨ • Ϋϥογϡ / ANR ػೳ͝ͱͷΩʔϝτϦΫε 
 ྫ) •

    ϝοηʔδ: ಡΈࠐΈ଎౓ • ΧʔυϑϦοΫ: ࠶ϑϦοΫՄೳʹͳΔ·Ͱͷ࣌ؒ
  17. Ϋϥογϡϩάͷ෼ྨ https://firebase.google.com/docs/crashlytics/customize-crash-reports import UIKit import FirebaseCrashlytics final class LoginViewController: UIViewController

    { // ը໘Λදࣔ͢ΔλΠϛϯάͰCrashlyticsʹΧελϜΩʔΛઃఆ override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) Crashlytics.crashlytics().setCustomValue("login", forKey: "domain") } iOSΞϓϦͰͷϩάΠϯը໘ʹର͢Δ࣮૷ྫ ֤ػೳͷը໘දࣔ࣌ʹCrashlyticsʹΧελϜΩʔΛઃఆ͢Δ • ΧελϜΩʔΛ΋ͱʹBigQuery (Data Portal) ্ͰػೳυϝΠϯ͝ͱͷΫϥογϡΛूܭ • ػೳ͝ͱͷΞϥʔτ͸ઃఆͰ͖ͳ͍ ◦ Velocity Alert → μογϡϘʔυͰػೳӨڹ֬ೝ
  18. ΦϒβʔόϏϦςΟͷ޲্ ద੾ͳΦϒβʔόϏϦςΟΛ࣮ݱ͢Δʹ͸ɺ࣍ͷ΋ͷ͕ඞཁ 
 Ϩϙʔτ • γεςϜશମͷঢ়ଶʢػೳ͍ͯ͠Δ͔ɺϦιʔεෆ଍͕ͳ͍͔ʣ • γεςϜͷϢʔβʔମݧʢར༻Ͱ͖Δ͔ʁૢ࡞্ͷ໰୊͸ͳ͍͔ʁʣ ϞχλϦϯά •

    ओͳϏδωεࢦඪͱγεςϜࢦඪ τϨʔε • ຊ൪؀ڥͷγεςϜͷঢ়ଶΛ֬ೝͯ͠σόοάͰ͖Δπʔϧ • ͜Ε·ͰೝࣝͰ͖ͳ͔ͬͨ͜ͱΛ֬ೝͰ͖Δπʔϧ • ຊ൪؀ڥͷ໰୊ͷτϨʔεɺ֬ೝɺ਍அʹ໾ཱͭπʔϧ
  19. ύʔεΤϥʔʹΑΔো֐ͷྫ ϨεϙϯεͷύʔεΤϥʔͷݕ஌ // αʔόʔϦϦʔεલ { "_id": 1234, "name": "user" }

    // αʔόʔϦϦʔεޙ { "id": 1234, "name": "user" } struct User: Codable { let id: Int let name: String } API Response ͷjson ରԠ͢ΔSwiftଆͷCodable
  20. ϨεϙϯεͷύʔεΤϥʔͷݕ஌ do { try JSONDecoder().decode(Response.self, from: data) } catch {

    var errString = error.localizedDescription // dev؀ڥͷΈ࣮ࡍͷϨεϙϯεΛૹ৴ #if DEBUG var jsonString = "" if let json = try? JSONSerialization.jsonObject(with: data, options: .allowFragments) { jsonString = String(describing: json) } errString += ", response: \(jsonString)" #endif // pathதͷidΛਖ਼نԽ let normalizedPath = path // uuidΛਖ਼نԽ .replacingUUID() // numberͷidΛਖ਼نԽ .replacingNumId() Logger.warn(.parseError(endPoint: normalizedPath, message: error.localizedDescription, error: error)
  21. ֎෦ͷೝূαʔϏεͷো֐ݕ஌ Ωϟϯηϧ౳ͷط஌ͷΤϥʔݪҼΛϑΟϧλʔͯ͠ϩάૹ৴Λߦ͏ let authError = error as? ASAuthorizationError switch authError?.code

    { case .canceled: break default: Logger.warn( .snsError(provider: .apple), error: error ) } let errorCode = GIDSignInError.Code(rawValue: error.code) switch authError?.code { case .canceled: break default: Logger.warn( .snsError(provider: .apple), error: error ) Sign in with Apple Google