Upgrade to Pro — share decks privately, control downloads, hide ads and more …

iOS アプリエラー監視の設計とその効果

Kuniwak
November 20, 2017

iOS アプリエラー監視の設計とその効果

Kuniwak

November 20, 2017
Tweet

More Decks by Kuniwak

Other Decks in Programming

Transcript

  1. ߏจϋΠϥΠτ Ϧϯτ ੩తܕݕࠪ ୯ମɾ݁߹ςετ 6*ςετ ςελʔʹΑΔಈ࡞֬ೝ Τϥʔ؂ࢹ Ϣʔβʔ͔Βͷ͓໰͍߹Θͤ ༧໿ޠλΠϙ ม਺໊λΠϙ

    ϓϩύςΟ໊
 λΠϙ ෼ذߟྀ࿙Ε ίϯϙʔωϯτ
 ࢓༷ͷෆ੔߹ ࢓༷΁ͷޡղ ಛघͳ؀ڥͰ͔͠
 ࠶ݱ͠ͳ͍Τϥʔ ҋ ཧ૝ͷόάݕ஌ͷ࢟
  2. ߏจϋΠϥΠτ Ϧϯτ ੩తܕݕࠪ ୯ମɾ݁߹ςετ 6*ςετ ςελʔʹΑΔಈ࡞֬ೝ Τϥʔ؂ࢹ Ϣʔβʔ͔Βͷ͓໰͍߹Θͤ ༧໿ޠλΠϙ ม਺໊λΠϙ

    ϓϩύςΟ໊
 λΠϙ ෼ذߟྀ࿙Ε ίϯϙʔωϯτ
 ࢓༷ͷෆ੔߹ ࢓༷΁ͷޡղ ಛघͳ؀ڥͰ͔͠
 ࠶ݱ͠ͳ͍Τϥʔ ҋ όά͕Լͷ૚·Ͱ
 ಥ͖ൈ͚ͯ͠·͏ͷͰ
 ݪҼڀ໌ʹ͕͔͔࣌ؒΔ μϝͳόάݕ஌ͷ࢟
  3. ߏจϋΠϥΠτ Ϧϯτ ੩తܕݕࠪ ୯ମɾ݁߹ςετ 6*ςετ ςελʔʹΑΔಈ࡞֬ೝ Τϥʔ؂ࢹ Ϣʔβʔ͔Βͷ͓໰͍߹Θͤ ༧໿ޠλΠϙ ม਺໊λΠϙ

    ϓϩύςΟ໊
 λΠϙ ෼ذߟྀ࿙Ε ίϯϙʔωϯτ
 ࢓༷ͷෆ੔߹ ࢓༷΁ͷޡղ ಛघͳ؀ڥͰ͔͠
 ࠶ݱ͠ͳ͍Τϥʔ ҋ ཧ૝ͷόάݕ஌ͷ࢟
  4. ߏจϋΠϥΠτ Ϧϯτ ੩తܕݕࠪ ୯ମɾ݁߹ςετ 6*ςετ ςελʔʹΑΔಈ࡞֬ೝ Τϥʔ؂ࢹ Ϣʔβʔ͔Βͷ͓໰͍߹Θͤ ༧໿ޠλΠϙ ม਺໊λΠϙ

    ϓϩύςΟ໊
 λΠϙ ෼ذߟྀ࿙Ε ίϯϙʔωϯτ
 ࢓༷ͷෆ੔߹ ࢓༷΁ͷޡղ ಛघͳ؀ڥͰ͔͠
 ࠶ݱ͠ͳ͍Τϥʔ ҋ Τϥʔ؂ࢹͰݕ஌͢΂͖
 Τϥʔ͸͜ͷ͋ͨΓ
  5. class CrashlyticsErrorReporter { private let crashlytics = Crashlytics.sharedInstance() func report(error:

    Error, from reporter: Any) { #if DEBUG let prefix = "DEBUG " #else let prefix = "" #endif let detailedError = NSError( domain: "\(prefix)\(type(of: reporter))", code: CrashlyticsErrorTracker.getNSErrorCode(bySwiftError: error), userInfo: [ NSLocalizedDescriptionKey: "\(error)", ] ) self.crashlytics.recordError(detailedError) } private static func getNSErrorCode(bySwiftError error: Error) -> Int { let bridgedError = error as NSError return bridgedError.code } } %&#6(ϏϧυΛ۠ผͰ͖ΔΑ͏ʹ͓ͯ͘͠ͱ
 ຊ൪؀ڥͱ։ൃ؀ڥΛ۠ผ͠΍͘͢ͳΔ ΤϥʔϨϙʔλʔʹͲͷΑ͏ʹ
 ूܭ͞ΕΔ͔Λҙࣝ͢Δ ྫ͑͹ɺ$SBTIMZUJDT͸/4&SSPSͷ
 EPNBJOͱDPEFͷ૊ͰΤϥʔΛ
 άϧʔϐϯά͢ΔͷͰɺͦΕͧΕ
 Τϥʔ*%ͱൃੜݩΛࢦఆ͢Δͱ
 ៉ྷʹΤϥʔ͕·ͱ·Δ Τϥʔͷશจ͸άϧʔϐϯάʹ࢖Θͳ͍Α͏ʹ͢Δ
 ʢϢʔβʔ*%ͱ͔͕ೖΔͱݸผͷΤϥʔʹͳͬͯ
 ૯਺Λ೺ѲͰ͖ͳ͘ͳΔͷͰʣ $SBTIMZUJDT༻ͷΤϥʔϨϙʔλʔΛ࡞੒ SFQPSUؔ਺ΛݺͿͱΤϥʔϨϙʔτ͕
 ૹ৴͞ΕΔΑ͏ʹ࣮૷͍ͯ͠Δ ΤϥʔͱҰॹʹൃੜݩ͕
 Θ͔ΔΑ͏ʹ͓ͯ͘͠ͱ
 ݪҼͷݟ౰͕͖ͭ΍͘͢ͳΔ
  6. class UserApiRepository: UserRepositoryProtocol { private let api: GitHubApiClientProtocol func get(by

    id: GitHubUser.Id) -> Promise<GitHubUser> { return self.api .fetch( endpoint: GitHubApiEndpoint(path: "/user/" + id.text), headers: [:], parameters: [] ) .then { data -> GitHubUser in let response: GitHubUserResponse = try unbox(data: data) return response.user } .catch { error in ErrorReporter.shared.report( error: error, reporter: self ) } } } Τϥʔ͕ฦ͖ͬͯͨΒ
 ΤϥʔϨϙʔτΛૹ৴
 ʢͭ·Γϋʔυίʔυʣ "1*ݺͼग़͠ͷίʔυ
  7. func fetch() { switch self.currentState { case .fetching: return case

    .fetched: self.stateMachine.transit(to: .fetching) self.repository.get(by: self.id) .then { user in self.stateMachine.transit(to: .fetched( result: .success(user) )) } .catch { error in self.stateMachine.transit(to: .fetched( result: .failure(.unspecified(debugInfo: "\(error) )) } } } ͜ͷ.PEFM͸"1*ݺͼग़͕͠Τϥʔʹ
 ͳͬͨΒΤϥʔঢ়ଶ΁มԽ͢Δ ͦͷͨΊɺΤϥʔϨϙʔλʔ͔Β؂ࢹ͠΍͍͢ .PEFM૚ͷ"1*ݺͼग़͠ͷίʔυ ͜ͷΑ͏ͳ.PEFM૚ͷઃܭͷৄࡉ͸IUUQTHPPHM1G'+-Λࢀর͍ͯͩ͘͠͞
  8. class UserModelErrorReporter { private let model: UserModelProtocol private let errorReporter:

    ErrorReporterProtocol private let disposeBag = RxSwift.DisposeBag() init( observing model: UserModelProtocol, reportingBy errorReporter: ErrorReporterProtocol ) { self.model = model self.errorReporter = errorReporter self.model.didChange .subscribe(onNext: { [weak self] (state: UserModelState) in guard let `self` = self else { return } switch state { case let .fetched(result: .failure(error)): self.errorReporter.report(error: error, reporter: self) default: return } }) .disposed(by: disposeBag) } } .PEFM͕Τϥʔঢ়ଶʹͳͬͨΒ
 ΤϥʔϨϙʔτΛૹ৴ .PEFMͷঢ়ଶભҠΛ؂ࢹ .PEFMΛ؂ࢹ͢ΔΤϥʔϨϙʔλʔΛ࡞੒
  9. func example(input: String) -> String? { guard validate1(input) else {

    return nil } guard validate2(input) else { return nil } guard validate3(input) else { return nil } return "OK! Hello \(input)" } ݪҼڀ໌Λ஗͘͢Δѱ͍ྫ ࣦഊͨ͠ݪҼ͕۠ผͰ͖ͳ͍
  10. enum ExampleError: Error { case validate1(debugInfo: String) case validate2(debugInfo: String)

    case validate3(debugInfo: String) } ͦ͏͍͏࣌͸FOVNͰΤϥʔΛ۠ผͰ͖ΔΑ͏ʹ͢Δ
  11. func example(input: String) -> Result<String> { guard validate1(input) else {

    return .failure(.validate1(debugInfo: input)) } guard validate2(input) else { return .failure(.validate2(debugInfo: input)) } guard validate3(input) else { return .failure(.validate3(debugInfo: input)) } return .success("OK! Hello \(input)") } ΤϥʔΛ۠ผ͠΍͍͢Α͍ྫ ࣦഊͨ͠ݪҼ͕۠ผͰ͖Δ ࣦഊͨ͠ࡍͷೖྗ΋ೖखͰ͖Δ