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

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

Avatar for Kuniwak Kuniwak
November 20, 2017

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

Avatar for Kuniwak

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)") } ΤϥʔΛ۠ผ͠΍͍͢Α͍ྫ ࣦഊͨ͠ݪҼ͕۠ผͰ͖Δ ࣦഊͨ͠ࡍͷೖྗ΋ೖखͰ͖Δ