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

Lessons In Swift Error Handling And Resilience

Lessons In Swift Error Handling And Resilience

Christopher Rogers

March 03, 2017
Tweet

Other Decks in Programming

Transcript

  1. LESSONS IN SWIFT ERROR HANDLING MOTIVATION ▸ Stable, correctly behaving

    code ▸ A codebase that allows us to continue to move at a fast pace ▸ Graceful recovery from “unexpected” errors while minimizing user impact ▸ No “denial of service” crashing ▸ Avoid asking the user to try reinstalling the app ▸ ҆ఆత͔ͭਖ਼ৗʹಈ࡞͢Δίʔυ ▸ ։ൃεϐʔυΛམͱͣ͞ʹਐΊΒΕΔ ▸ ͍ΘΏΔ༧ظ͠ͳ͍ෆ۩߹͔Β෮ؼ͠, Ϣʔβʔ΁ͷӨڹൣғΛ࠷খݶʹ ▸ DoS తʹམͪͳ͍Α͏ʹ஫ҙ͢Δ ▸ ΞϓϦͷ࠶ΠϯετʔϧΛͳΔ΂͘
 ͤ͞ͳ͍Α͏ʹ എܠ
  2. CORRECT CODE INPUT ▸ Explicit ▸ Function parameters ▸ self

    ▸ Implicit ▸ a.k.a. “state” ▸ ໌ࣔత ▸ ؔ਺ͷҾ਺ ▸ self ▸ ҉໧త ▸ ঢ়ଶ ೖྗ
  3. CORRECT CODE STATE ▸ Temporal ▸ The code being executed

    at any given time ▸ Mostly defined by order of imperative code ▸ Usually implicit, but can be made more explicit ▸ Comments ▸ Not being compilable in incorrect order ▸ ࣌ؒత ▸ ͋Δ࣌ؒͰ࣮ߦ͞Ε͍ͯΔίʔυΛࣔ͢ ▸ ໋ྩܕίʔυͷॱ൪ʹΑͬͯఆٛ͞ΕΔ ▸ େ֓͸҉໧త͕ͩɺΑΓ໌ࣔతʹ͢Δ͜ͱ ΋Մೳ ▸ ίϝϯτ ▸ ؒҧͬͨॱ൪ͰίϯύΠϧͰ͖ͳ͍Α ͏ʹ͢Δ͜ͱ ঢ়ଶ
  4. CORRECT CODE 1 2 3 1 3 2 2 1

    3 2 3 1 3 1 2 3 2 1
  5. CORRECT CODE func f() -> Int { let a =

    foo() let b = bar(“b”) doSomething() let c = bar(a) return b + c }
  6. CORRECT CODE STATE ▸ State from the “real world” ▸

    Filesystem & network ▸ Previous executions/versions of your code ▸ Previous buggy versions ▸ Data from long lost & forgotten specs ▸ ϦΞϧੈքͷঢ়ଶ ▸ ϑΝΠϧγεςϜ΍ωοτϫʔΫ ▸ Ҏલͷίʔυͷ࣮ߦग़ྗ ▸ όά͍ͬͯͨίʔυ ▸ ๨ΕΒΕͨ࢓༷ ঢ়ଶ
  7. CORRECT CODE import Foundation final class ThemeSubsystem { init() {

    let theme = UserDefaults.standard.string(forKey: "theme") // … } } DATA FORMAT MIGRATION σʔλܗࣜͷҠߦॲཧ
  8. CORRECT CODE: EXAMPLE DATA FORMAT MIGRATION ▸ The value in

    stored in user defaults. ▸ It should be migrated on first launch after upgrading the app. ▸ User defaults ʹ֨ೲ͞Εͨ஋͕ର৅ɻ ▸ ΞϓϦͷΞοϓσʔτޙͷॳظىಈ࣌ ʹҠߦ͢Δɻ σʔλܗࣜͷҠߦॲཧ
  9. CORRECT CODE: EXAMPLE DATA FORMAT MIGRATION ▸ However, the value

    was used prior to migration. ▸ Shared state + ambiguous dependency ▸ How do we go about fixing it? ▸ How do we prevent similar mistakes? ▸ Ҡߦ͢Δલʹར༻͞Εͯ͠·ͬͨɻ ▸ ڞ༗ঢ়ଶͱᐆດͳґଘؔ܎ ▸ मਖ਼ํ๏͸ʁ ▸ ࠶ൃ๷ࢭ͸ʁ σʔλܗࣜͷҠߦॲཧ
  10. CORRECT CODE: EXAMPLE EXPLICIT DEPENDENCIES WITH TYPES ▸ If you

    don't have an instance of a type, you can't call a function that requires it as input. ▸ Create the type to represent the transition into a certain state. ▸ Requiring an instance of that type as a function parameter allows you to specify the state that the type represents as a prerequisite. ▸ ܕͷΠϯελϯε͕ͳ͚Ε͹ͦΕΛҾ਺ͱ͢ Δؔ਺Λݺͼग़͢͜ͱ͕Ͱ͖ͳ͍ɻ ▸ ಛఆͷঢ়ଶ΁ͷભҠΛද͢ܕΛ࡞Δɻ ▸ ͦͷܕͷΠϯελϯεΛҾ਺ͱͯ͠ड͚औΔ ͜ͱʹΑͬͯͦͷܕ͕ද͢ঢ়ଶΛલఏ৚݅ͱ ͯ͠ఆٛ͢Δ͜ͱ͕Ͱ͖Δɻ ܕʹΑΔ໌ࣔతͳґଘؔ܎
  11. CORRECT CODE import Foundation final class ThemeSubsystem { init(_: SetupComplete)

    { let theme = UserDefaults.standard.string(forKey: "theme") // … } } EXPLICIT DEPENDENCIES WITH TYPES ܕʹΑΔ໌ࣔతͳґଘؔ܎
  12. OPTIONAL VS. ERROR WHEN TO USE OPTIONAL ▸ “Right or

    wrong”, “present or not present” semantics as output ▸ As input, “optional” semantics ▸ Swift’s syntax makes it easy to safely handle. ▸ The “go to” choice ▸ ग़ྗͷ஋ͱͯ͠͸ʮਖ਼͍͔͠ਖ਼͘͠ͳ͍ʯ ΍ʮ༗Γ͔ແ͠ʯͷҙຯ ▸ ೖྗͷ஋ͱͯ͠͸ʮ೚ҙʯͷҙຯ ▸ ҆શʹѻ͏͜ͱ͕༰қʹͰ͖Δ ▸ େ఍ͷ৔߹͸ Optional ܕ͕ਖ਼ղ
  13. OPTIONAL VS. ERROR WHEN TO USE ERROR ▸ Similar “wrong”,

    “unable to complete successfully” semantics ▸ Often used for “fatal errors” ▸ Syntax lets you pretend nothing will go wrong at the call site of throwing functions. ▸ Best suited for handling low- probability, high-impact errors. ▸ ಉ͡Α͏ͳʮෆਖ਼ղʯ΍ʮਖ਼ৗʹॲཧ Ͱ͖ͳ͔ͬͨʯҙຯ ▸ க໋తͳ໰୊ʹ࢖ΘΕΔ͜ͱ͕ଟ͍ ▸ εϩʔ͢Δؔ਺ͷݺͼग़͠ଆ͸ਖ਼ৗʹ ॲཧ͞ΕΔৼΔ෣͍͕Ͱ͖Δ ▸ ൃੜ཰͕௿͘Өڹൣғ͕޿͍Τϥʔʹ ར༻͢Δͷ͕ద੾ ERROR ͷ࢖͍ಓ
  14. WHEN TO USE ERROR OPTIONAL VS. ERROR struct ChatID {

    let type: ChatIDType let stringValue: String init?(_ string: String) { } } ERROR ͷ࢖͍ಓ
  15. WHEN TO USE ERROR OPTIONAL VS. ERROR struct ChatID {

    let type: ChatIDType let stringValue: String init(_ string: String) throws { } } ERROR ͷ࢖͍ಓ
  16. LESSONS IN SWIFT ERROR HANDLING AND RESILIENCE RECAP ▸ Being

    cognizant of input/output flow leads to more robust code. ▸ Be aware of code critically important. ▸ Use Optional for lightweight, low- context, somewhat likely errors. ▸ Use Error for heavyweight, high- context, and unlikely errors. ▸ ೖग़ྗͷྲྀΕΛҙ͍ࣝͯ͠Ε͹͋ΒΏ ΔΤϥʔঢ়ଶΛରॲͰ͖ΔΑ͏ʹίʔ υ͕ͳ͍ͬͯ͘ɻ ▸ ඇৗʹॏཁͳίʔυʹؾΛ͚ͭΔ͜ͱ ▸ Optional͸৘ใྔ͕গͳ͍ൃੜස౓ ͕΍΍ى͜Γ͕ͪͳΤϥʔʹ ▸ Error ͸৘ใྔ͕ଟ͍كͳΤϥʔʹ ·ͱΊ