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

Clean Architecture 2

Clean Architecture 2

Takuma Shimizu

August 29, 2018
Tweet

More Decks by Takuma Shimizu

Other Decks in Programming

Transcript

  1. ΫϦʔϯΞʔΩςΫνϟ
    ࣮ફͷࣄ࢝Ί
    ٕज़ษڧձ

    View Slide

  2. લճͷ࿩୊
    w ΫϦʔϯΞʔΩςΫνϟͷ؊
    w #VTJOFTT3VMFT
    w &OUJUZ
    $SJUJDBM

    w 6TF$BTF "QQMJDBUJPOTQFDJpD

    w ґଘΛҰํ޲ʹอͭ

    View Slide

  3. ࠓճͷ࿩୊
    w &OUJUZ $SJUJDBM

    w 6TF$BTF "QQMJDBUJPOTQFDJpD

    w ࣸਅͷ&YJG΍.FUBEBUBΛѻ͏ΞϓϦ
    w -FWFM ϨΠϠʔ
    ؒͷσʔλͷड͚౉͠ํ๏

    View Slide

  4. ໨ඪ
    ୲౰Ҋ݅ͷ
    &OUJUZͱ6TF$BTF
    Λ۠ผͰ͖Δؾ͕͢Δ

    View Slide

  5. γφϦΦ
    w ࣸਅͷϝλσʔλΛ͚ͩͻͨ͢Βྻڍ͢ΔΞϓϦͷ࡞੒
    ґཔ
    w ࣸਅͷฒͼ͸ॱෆಉͰߏΘͳ͍
    w ίʔυྫͷෳࡶ͞Λͳͨ͘͢Ίʹ
    ࣸਅࣗମ͸දࣔ͠ͳ͍

    View Slide

  6. <&OUJUZ>
    .FUBEBUB
    <6TF$BTF>
    .FUBEBUB-JTU
    6TF$BTF
    <*OQVU>
    .FUBEBUB-JTU
    *OUFSBDUPS
    <0VUQVU>
    .FUBEBUB-JTU
    0VUQVU
    <%BUB4USVDU>
    #SPXTJOH
    .FUBEBUB
    6*

    View Slide

  7. <&OUJUZ>
    .FUBEBUB
    <6TF$BTF>
    .FUBEBUB-JTU
    6TF$BTF
    <*OQVU>
    .FUBEBUB-JTU
    *OUFSBDUPS
    <0VUQVU>
    .FUBEBUB-JTU
    0VUQVU
    <%BUB4USVDU>
    #SPXTJOH
    .FUBEBUB
    6*

    View Slide

  8. <&OUJUZ>
    .FUBEBUB
    <6TF$BTF>
    .FUBEBUB-JTU
    6TF$BTF
    <*OQVU>
    .FUBEBUB-JTU
    *OUFSBDUPS
    <0VUQVU>
    .FUBEBUB-JTU
    0VUQVU
    <%BUB4USVDU>
    #SPXTJOH
    .FUBEBUB
    6*

    View Slide

  9. <&OUJUZ>
    .FUBEBUB
    <6TF$BTF>
    .FUBEBUB-JTU
    6TF$BTF
    <*OQVU>
    .FUBEBUB-JTU
    *OUFSBDUPS
    <0VUQVU>
    .FUBEBUB-JTU
    0VUQVU
    <%BUB4USVDU>
    #SPXTJOH
    .FUBEBUB
    6*

    View Slide

  10. <&OUJUZ>
    .FUBEBUB
    <6TF$BTF>
    .FUBEBUB-JTU
    6TF$BTF
    <*OQVU>
    .FUBEBUB-JTU
    *OUFSBDUPS
    <0VUQVU>
    .FUBEBUB-JTU
    0VUQVU
    <%BUB4USVDU>
    #SPXTJOH
    .FUBEBUB
    6*

    View Slide

  11. <&OUJUZ>
    .FUBEBUB
    <6TF$BTF>
    .FUBEBUB-JTU
    6TF$BTF
    <*OQVU>
    .FUBEBUB-JTU
    *OUFSBDUPS
    <0VUQVU>
    .FUBEBUB-JTU
    0VUQVU
    <%BUB4USVDU>
    #SPXTJOH
    .FUBEBUB
    6*

    View Slide

  12. <&OUJUZ>
    .FUBEBUB
    <6TF$BTF>
    .FUBEBUB-JTU
    6TF$BTF
    <*OQVU>
    .FUBEBUB-JTU
    *OUFSBDUPS
    <0VUQVU>
    .FUBEBUB-JTU
    0VUQVU
    <%BUB4USVDU>
    #SPXTJOH
    .FUBEBUB
    6*

    View Slide

  13. <&OUJUZ>
    .FUBEBUB
    <6TF$BTF>
    .FUBEBUB-JTU
    6TF$BTF
    <*OQVU>
    .FUBEBUB-JTU
    *OUFSBDUPS
    <0VUQVU>
    .FUBEBUB-JTU
    0VUQVU
    <%BUB4USVDU>
    #SPXTJOH
    .FUBEBUB
    6*

    View Slide

  14. <&OUJUZ>
    .FUBEBUB
    <6TF$BTF>
    .FUBEBUB-JTU
    6TF$BTF
    <*OQVU>
    .FUBEBUB-JTU
    *OUFSBDUPS
    <0VUQVU>
    .FUBEBUB-JTU
    0VUQVU
    <%BUB4USVDU>
    #SPXTJOH
    .FUBEBUB
    6*

    View Slide

  15. <&OUJUZ>
    .FUBEBUB
    <6TF$BTF>
    .FUBEBUB-JTU
    6TF$BTF
    <*OQVU>
    .FUBEBUB-JTU
    *OUFSBDUPS
    <0VUQVU>
    .FUBEBUB-JTU
    0VUQVU
    <%BUB4USVDU>
    #SPXTJOH
    .FUBEBUB
    6*

    View Slide

  16. <&OUJUZ>
    .FUBEBUB
    <6TF$BTF>
    .FUBEBUB-JTU
    6TF$BTF
    <*OQVU>
    .FUBEBUB-JTU
    *OUFSBDUPS
    <0VUQVU>
    .FUBEBUB-JTU
    0VUQVU
    <%BUB4USVDU>
    #SPXTJOH
    .FUBEBUB
    6*

    View Slide

  17. <&OUJUZ>
    .FUBEBUB
    <6TF$BTF>
    .FUBEBUB-JTU
    6TF$BTF
    <*OQVU>
    .FUBEBUB-JTU
    *OUFSBDUPS
    <0VUQVU>
    .FUBEBUB-JTU
    0VUQVU
    <%BUB4USVDU>
    #SPXTJOH
    .FUBEBUB
    6*

    View Slide

  18. &OUJUZ
    struct Metadata: Comparable {
    enum FlashMode {
    case none, normal, redEye
    }
    init(properties: [CFString : Any])
    var localIdentifier: String { get }
    var iso: Float { get }
    var focalLength: Float { get }
    var exposureValue: Float { get }
    var lensAperture: Float { get }
    var exposureDuration: CMTime { get }
    var flashMode: FlashMode { get }
    ŋ
    ŋ
    ŋ
    }

    View Slide

  19. 6TF$BTF *'

    public protocol MetadataListInteractor {
    func browseMetadata()
    }
    public protocol MetadataListOutput : AnyObject {
    func didProvideMetadataToBrowse(_: [BrowsingMetadata])
    }
    • MetadataListInteractor
    w "EBQUFS૚ͷ$POUSPMMFS͔Βར༻
    • MetadataListOutput
    w "EBQUFS૚ͷ1SFTFOUFSͰ࣮૷
    w 6TF$BTF *OUFSBDUPSͷ࣮૷
    ͔Βར༻

    View Slide

  20. 6TF$BTF *NQ

    struct MetadataListUseCase: MetadataListInteractor {
    private let output: MetadataListOutput
    func browseMetadata() {
    let metadata = repository.fetchMetadata()
    let metadataToBrowse
    = metadata.map(BrowsingMetadata.init(_:))
    output.didProvideMetadataToBrowse(metadataToBrowse)
    }
    }

    View Slide

  21. 6TF$BTF *NQ

    struct MetadataListUseCase: MetadataListInteractor {
    private let output: MetadataListOutput
    func browseMetadata() {
    let metadata = repository.fetchMetadata()
    let metadataToBrowse
    = metadata.map(BrowsingMetadata.init(_:))
    output.didProvideMetadataToBrowse(metadataToBrowse)
    }
    }

    View Slide

  22. %BUB4USVDUVSF
    public struct BrowsingMetadata {
    public var localIdentifier: String { get }
    public var iso: Float { get }
    public var focalLength: Float? { get }
    public var exposureValue: Float { get }
    public var lensAperture: Float? { get }
    public var exposureDuration: CMTime { get }
    }
    extension BrowsingMetadata {
    private init(_ metadata: Metadata)
    }

    View Slide

  23. %BUB4USVDUVSF
    public struct BrowsingMetadata {
    public var localIdentifier: String { get }
    public var iso: Float { get }
    public var focalLength: Float? { get }
    public var exposureValue: Float { get }
    public var lensAperture: Float? { get }
    public var exposureDuration: CMTime { get }
    }
    extension BrowsingMetadata {
    private init(_ metadata: Metadata)
    }

    View Slide

  24. %BUB4USVDUVSF
    extension BrowsingMetadata {
    private init(_ metadata: Metadata)
    }
    w ϨϕϧؒΛ·͙ͨσʔλߏ଄ମͷड౉͠
    w ԼҐϨϕϧ 6TF$BTF
    ্͕ҐϨϕϧͷ&OUJUZΛม׵
    w .FNCFSXJTFJOJUJBMJ[FS *OUFSOBM

    w ςετίʔυͷͨΊʹ࢒͓ͯ͘͠
    w !UFTUBCMFJNQPSUͰར༻

    View Slide

  25. <&OUJUZ>
    .FUBEBUB
    <6TF$BTF>
    .FUBEBUB-JTU
    6TF$BTF
    <*OQVU>
    .FUBEBUB-JTU
    *OUFSBDUPS
    <0VUQVU>
    .FUBEBUB-JTU
    0VUQVU
    <%BUB4USVDU>
    #SPXTJOH
    .FUBEBUB
    6*

    View Slide

  26. γφϦΦ
    w ΍ͬͺΓιʔτػೳͷ௥Ճґཔ
    w ࢦఆ͞ΕͨϝλσʔλͰฒͼସ͑
    w ॳظදࣔ͸γφϦΦͷॱෆಉͰͷฒͼʹͳΔ

    View Slide

  27. <&OUJUZ>
    .FUBEBUB
    <6TF$BTF>
    0SEFSFE-JTU
    6TF$BTF
    <*OQVU>
    0SEFSFE-JTU
    *OUFSBDUPS
    <0VUQVU>
    0SEFSFE-JTU
    0VUQVU
    <%BUB4USVDU>
    #SPXTJOH
    .FUBEBUB
    6*
    .FUBEBUB-JTU
    6$ *0

    View Slide

  28. <&OUJUZ>
    .FUBEBUB
    <6TF$BTF>
    0SEFSFE-JTU
    6TF$BTF
    <*OQVU>
    0SEFSFE-JTU
    *OUFSBDUPS
    <0VUQVU>
    0SEFSFE-JTU
    0VUQVU
    <%BUB4USVDU>
    #SPXTJOH
    .FUBEBUB
    6*
    .FUBEBUB-JTU
    6$ *0

    View Slide

  29. <&OUJUZ>
    .FUBEBUB
    <6TF$BTF>
    0SEFSFE-JTU
    6TF$BTF
    <*OQVU>
    0SEFSFE-JTU
    *OUFSBDUPS
    <0VUQVU>
    0SEFSFE-JTU
    0VUQVU
    <%BUB4USVDU>
    #SPXTJOH
    .FUBEBUB
    6*

    View Slide

  30. <&OUJUZ>
    .FUBEBUB
    <6TF$BTF>
    0SEFSFE-JTU
    6TF$BTF
    <*OQVU>
    0SEFSFE-JTU
    *OUFSBDUPS
    <0VUQVU>
    0SEFSFE-JTU
    0VUQVU
    <%BUB4USVDU>
    #SPXTJOH
    .FUBEBUB
    6*

    View Slide

  31. <&OUJUZ>
    .FUBEBUB
    <6TF$BTF>
    0SEFSFE-JTU
    6TF$BTF
    <*OQVU>
    0SEFSFE-JTU
    *OUFSBDUPS
    <0VUQVU>
    0SEFSFE-JTU
    0VUQVU
    <%BUB4USVDU>
    #SPXTJOH
    .FUBEBUB
    6*

    View Slide

  32. มߋͳ͠
    w ػೳͷมߋͰ͸ͳ͘ɺૢ࡞ํ๏ͷมߋ
    w ૢ࡞ํ๏ͷมߋͷӨڹ͸6TF$BTF΄Ͳड͚ʹ͍͘
    &OUJUZ

    View Slide

  33. 6TF$BTF ௥Ճ

    public protocol OrderedMetadataListInteractor {
    func browseSortKeys()
    func browseOrderedMetadata(by key: MetadataListSortKey)
    }
    public protocol OrderedMetadataListOutput : AnyObject {
    func didProvideSortKeys(_: [MetadataListSortKey])
    func didProvideSortedMetadataToBrowse(_: [BrowsingMetadata])
    }
    public enum MetadataListSortKey {
    case iso, focalLength, exposureValue
    case lensAperture, exposureDuration
    }
    internal extension MetadataListSortKey : CaseIterable {
    }

    View Slide

  34. 6TF$BTF ௥Ճ

    internal extension MetadataListSortKey : CaseIterable {
    }
    public protocol OrderedMetadataListInteractor {
    func browseSortKeys()
    }
    public protocol OrderedMetadataListOutput : AnyObject {
    func didProvideSortKeys(_: [MetadataListSortKey])
    }

    View Slide

  35. 6TF$BTF ௥Ճ

    public enum MetadataListSortKey {
    case iso, focalLength, exposureValue
    case lensAperture, exposureDuration
    }
    public protocol OrderedMetadataListInteractor {
    func browseOrderedMetadata(by key: MetadataListSortKey)
    }
    public protocol OrderedMetadataListOutput : AnyObject {
    func didProvideSortedMetadataToBrowse(_: [BrowsingMetadata])
    }

    View Slide

  36. "EBQUFSͰ͸
    • MetadataListInteractor ͱ
    OrderedMetadataListInteractor
    w ಉҰͷ$POUSPMMFS͔Βར༻
    w $POUSPMMFS͕ͭͷ*OUFSBDUPSΛ࣋ͬͨঢ়ଶ
    • MetadataListOutput ͱ
    OrderedMetadataListOutput
    w ಉҰͷ1SFTFOUFSͰ࣮૷
    w 1SFTFOUFS͕ͭͷ0VUQVUʹ४ڌͨ͠ঢ়ଶ

    View Slide

  37. "EBQUFSͰ͸
    w $POUSPMMFS͕ͭͷ*OUFSBDUPSΛ࣋ͬͨঢ়ଶ
    w 1SFTFOUFS͕ͭͷ0VUQVUʹ४ڌͨ͠ঢ়ଶ
    w 6TF$BTF಺Ͱ΋มߋස౓͕ҟͳΔ΋ͷ͸෼཭
    w ࠓճͷྫͰ͸ඍົ͔΋

    View Slide

  38. <&OUJUZ>
    .FUBEBUB
    <6TF$BTF>
    0SEFSFE-JTU
    6TF$BTF
    <*OQVU>
    0SEFSFE-JTU
    *OUFSBDUPS
    <0VUQVU>
    0SEFSFE-JTU
    0VUQVU
    <%BUB4USVDU>
    #SPXTJOH
    .FUBEBUB
    6*
    .FUBEBUB-JTU
    6$ *0

    View Slide

  39. γφϦΦ
    w ϝλσʔλΛվ͟ΜͰ͖Δػೳͷ௥Ճґཔ
    w ಛఆͷϝλσʔλ͚͕ͩฤूՄೳ
    w ݩͷࣸਅͱஔ͖׵͑ͯอଘ

    View Slide

  40. <&OUJUZ>
    .FUBEBUB
    <6TF$BTF>
    .PEJpDBUJPO
    6TF$BTF
    <*OQVU>
    .PEJpDBUJPO
    *OUFSBDUPS
    <0VUQVU>
    .PEJpDBUJPO
    0VUQVU
    <%BUB4USVDU>
    .PEJGZJOH
    .FUBEBUB
    6*
    .FUBEBUB-JTU
    6$ *0
    0SEFSFE-JTU
    6$ *0

    View Slide

  41. <&OUJUZ>
    .FUBEBUB
    <6TF$BTF>
    .PEJpDBUJPO
    6TF$BTF
    <*OQVU>
    .PEJpDBUJPO
    *OUFSBDUPS
    <0VUQVU>
    .PEJpDBUJPO
    0VUQVU
    <%BUB4USVDU>
    .PEJGZJOH
    .FUBEBUB
    6*
    .FUBEBUB-JTU
    6$ *0
    0SEFSFE-JTU
    6$ *0

    View Slide

  42. <&OUJUZ>
    .FUBEBUB
    <6TF$BTF>
    .PEJpDBUJPO
    6TF$BTF
    <*OQVU>
    .PEJpDBUJPO
    *OUFSBDUPS
    <0VUQVU>
    .PEJpDBUJPO
    0VUQVU
    <%BUB4USVDU>
    .PEJGZJOH
    .FUBEBUB
    6*

    View Slide

  43. <&OUJUZ>
    .FUBEBUB
    <6TF$BTF>
    .PEJpDBUJPO
    6TF$BTF
    <*OQVU>
    .PEJpDBUJPO
    *OUFSBDUPS
    <0VUQVU>
    .PEJpDBUJPO
    0VUQVU
    <%BUB4USVDU>
    .PEJGZJOH
    .FUBEBUB
    6*

    View Slide

  44. <&OUJUZ>
    .FUBEBUB
    <6TF$BTF>
    .PEJpDBUJPO
    6TF$BTF
    <*OQVU>
    .PEJpDBUJPO
    *OUFSBDUPS
    <0VUQVU>
    .PEJpDBUJPO
    0VUQVU
    <%BUB4USVDU>
    .PEJGZJOH
    .FUBEBUB
    6*

    View Slide

  45. &OUJUZ
    extension Metadata {
    func validate() -> Bool
    }
    w ػೳͷ௥Ճ͸ɺ&OUJUZʹ΋Өڹ͕ͰΔ
    w ػೳͷมߋ΋ಉ༷

    View Slide

  46. 6TF$BTF *'

    public struct ModifyingMetadata {
    public var localIdentifier: String { get }
    public var exposureValue: Float { get set }
    public var exposureDuration: CMTime { get set }
    }
    extension ModifyingMetadata {
    internal init(_ source: Metadata)
    }
    public protocol MetadataModificationInteractor {
    func requestToModifyMetadata(ofIdentifier localID: String)
    func modify(with modifyingMetadata: ModifyingMetadata)
    }
    public protocol MetadataModificationOutput : AnyObject {
    func didProvideMetadataToModify(_: inout ModifyingMetadata)
    func didModifyMetadata(_: ModifyingMetadata)
    func didFailToModifyMetadata(_: ModifyingMetadata)
    }

    View Slide

  47. 6TF$BTF *NQ

    struct MetadataModificationUseCase:
    MetadataModificationInteractor {
    private let output: MetadataModificationOutput
    func requestToModifyMetadata(ofIdentifier localID: String) {
    let source = repository.fetchMetadata(
    ofIdentifier: localID
    )
    var metadataToModify = ModifyingMetadata(source)
    output.didProvideMetadataToModify(&metadataToModify)
    }
    }

    View Slide

  48. 6TF$BTF *NQ

    struct MetadataModificationUseCase:
    MetadataModificationInteractor {
    func modify(with modifyingMetadata: ModifyingMetadata) {
    let source = repository.fetchMetadata(
    ofIdentifier: modifyingMetadata.localIdentifier
    )
    source.exposureValue
    = modifyingMetadata.exposureValue
    source.exposureDuration
    = modifyingMetadata.exposureDuration
    guard source.valiate() else {
    output.didFailToModifyMetadata(modifyingMetadata)
    return
    }
    repository.updatePhoto(with: source)
    output.didModifyMetadata(modifyingMetadata)
    }
    }

    View Slide

  49. %BUB4USVDUVSF
    public struct ModifyingMetadata {
    public var localIdentifier: String { get }
    public var exposureValue: Float { get set }
    public var exposureDuration: CMTime { get set }
    }

    View Slide

  50. %BUB4USVDUVSF
    public struct ModifyingMetadata {
    public var localIdentifier: String { get }
    public var exposureValue: Float { get set }
    public var exposureDuration: CMTime { get set }
    }

    View Slide

  51. %BUB4USVDUVSF
    w 6TF$BTF಺Ͱ΋มߋස౓͕ҟͳΔ΋ͷ͸෼཭
    w ͦͷ෼཭ʹଇͬͯσʔλߏ଄ମ΋෼཭
    w ઈରͰ͸ͳ͍ɻ΍Γ͗͢஫ҙ
    w ͲΜͳʹ෼཭ͯ͠΋

    6TF$BTFಉ࢜ͷׯব͕ආ͚ΒΕͳ͍৔߹΋͋Δ
    w σʔλߏ଄ମΛڞ༗͍ͯ͠Δ6TF$BTF΋ҶͮΔࣜʹมߋ

    View Slide

  52. <&OUJUZ>
    .FUBEBUB
    <6TF$BTF>
    .PEJpDBUJPO
    6TF$BTF
    <*OQVU>
    .PEJpDBUJPO
    *OUFSBDUPS
    <0VUQVU>
    .PEJpDBUJPO
    0VUQVU
    <%BUB4USVDU>
    .PEJGZJOH
    .FUBEBUB
    6*
    .FUBEBUB-JTU
    6$ *0
    0SEFSFE-JTU
    6$ *0

    View Slide

  53. γφϦΦͷ·ͱΊ
    w ૢ࡞खॱͷ௥Ճɾมߋ͸ɺ6TF$BTFͷ௥ՃɾมߋͰରԠ
    w ػೳͷ௥Ճɾมߋ͸ɺ&OUJUZͱ6TF$BTFͷ௥ՃɾมߋͰରԠ
    w ʮͱΓ͋͑ͣ࡞ͬͯɺ͋ͱ͔ΒΞοϓσʔτʯʹϚον㾗
    w ϨϕϧؒͰड͚౉͞ΕΔσʔλߏ଄ମ͸ɺ4XJGUͷTUSVDU͕ศར

    View Slide

  54. ͦͷଞͷ
    &OUJUZͱ6TF$BTF

    View Slide

  55. "MFSU$POUSPMMFS J04

    w 1SFTFOUFSͰ"MFSU$POUSPMMFSΛੜ੒͢Δ৔߹
    w 7JFXͰ"MFSU$POUSPMMFSΛੜ੒ɾදࣔ͢Δ৔߹

    View Slide

  56. "MFSU$POUSPMMFS J04

    w 1SFTFOUFSͰ"MFSU$POUSPMMFSΛੜ੒͢Δ৔߹
    protocol UserInformationUpdateOutput: AnyObject {
    func didFailToUpdateUserInformation(
    with error: Error, retrying: @escaping (Bool) -> Void
    )
    }
    final class UserInformationPresenter: UserInformationUpdateOutput {
    func didFailToUpdateUserInformation(
    with error: Error, retrying: @escaping (Bool) -> Void) {
    let alert = // ...
    let retryAction = UIAlertAction(title: "Retry", style: .default) { _ in
    retrying(true)
    }
    alert.addAction(retryAction)
    let cancelAction = UIAlertAction(title: "Close", style: .cancel) { _ in
    retrying(false)
    }
    alert.addAction(cancelAction)
    view.show(alert)
    }
    }

    View Slide

  57. "MFSU$POUSPMMFS J04

    w 1SFTFOUFSͰ"MFSU$POUSPMMFSΛੜ੒͢Δ৔߹
    final class UserInformationUpdateUseCase: UserInfoUpdateInteractor {
    let output: UserInformationUpdateOutput
    func update(_ user: UserInformationUpdateOutput) {
    // ...
    let error = // ...
    output.didFailToUpdateUserInformation(with: error) {
    [weak self] isRetried in
    if isRetried {
    self?.update(user)
    }
    }
    }
    }

    View Slide

  58. "MFSU$POUSPMMFS J04

    w 7JFXͰ"MFSU$POUSPMMFSΛੜ੒ɾදࣔ͢Δ৔߹
    final class UserInformationPresenter: UserInfoUpdateOutput {
    let view: UserInformationView
    func didFailToUpdateUserInformation(with error: Error) {
    view.showError(withMessage: error.localizedDescription)
    }
    }
    final class UserInformationVC: UIVC, UserInfoView {
    func showError(withMessage message: String) {
    let alert = // ...
    let retry = UIAlertAction(title: "Retry", style: .default) { _ in
    controller.retry()
    }
    alert.addAction(retry)
    // ...
    present(alert, animated: true)
    }
    }

    View Slide

  59. "MFSU$POUSPMMFS J04

    w 7JFXͰ"MFSU$POUSPMMFSΛੜ੒ɾදࣔ͢Δ৔߹
    final class UserInformationUpdateUseCase: UserInfoUpdateInteractor {
    let output: UserInformationUpdateOutput
    func update(_ user: UserInformationUpdateOutput) {
    // ...
    let error = // ...
    output.didFailToUpdateUserInformation(with: error)
    }
    }

    View Slide

  60. "MFSU$POUSPMMFS J04

    w 1SFTFOUFSͰ"MFSU$POUSPMMFSΛੜ੒͢Δ৔߹
    w 7JFXͰ"MFSU$POUSPMMFSΛੜ੒ɾදࣔ͢Δ৔߹
    w 6TF$BTF͕6*૚ͷӨڹΛड͚ͯ͠·͍ͬͯΔ
    w ํ਑ΛܾΊͯͲͷํ๏Ͱ࣮ݱ͢Δ͔Λ౷Ұ
    w ଥڠϙΠϯτ

    View Slide

  61. όϦσʔγϣϯ
    w &OUJUZͱ6TF$BTFͷͲͪΒͰόϦσʔτΛ͢΂͖͔
    ˠͲͪΒ΋ߦ͏Մೳੑ͕͋Δ

    ྫɿೖྗϑΥʔϜ͔Βͷೖྗ஋Ͱϝλσʔλͷ஋Λߋ৽

    View Slide

  62. όϦσʔγϣϯ
    w ਺஋Λظ଴͢ΔϑΥʔϜͷೖྗ஋ 4USJOH
    ͷݕূ
    ˠ6TF$BTF͕୲౰͢Δ
    w &OUJUZΑΓ΋ೖྗʹ͍ۙ ԼҐϨϕϧ

    w ͲΜͳૢ࡞ํ๏Ͱೖྗ͞ΕΔͷ͔͸γεςϜͷཁ݅

    View Slide

  63. όϦσʔγϣϯ
    w ೖྗ஋ ਺஋
    ͰϝλσʔλΛߋ৽͢Δࡍͷଥ౰ੑ
    ˠ&OUJUZ͕୲౰͢Δ
    w ϝλσʔλͷ஋ͷ༗ޮൣғ͸γεςϜ͔Βಠཱͨ͠ఆٛ
    w &OUJUZ͸ࣗ਎ͷ੔߹ੑΛ୲อ %%%తͳࢹ఺

    View Slide

  64. l-FWFMzͰ͓͞Β͍
    w Ϣʔβʔ΍γεςϜͷೖྗͱग़ྗ͔Β཭Ε͍ͯΔ΄Ͳ

    Ϩϕϧ͕ߴ͍
    w όϦσʔγϣϯͷྫ
    w Ϩϕϧ͕ҟͳΕ͹มߋස౓ɾཧ༝΋ҟͳΔ
    w ϝλσʔλӾཡɾฤूͷྫ

    w ΑΓ-FWFM͕ߴ͍΄͏Λ&OUJUZʹ෼཭

    View Slide

  65. ໨ඪ
    ୲౰Ҋ݅ͷ
    &OUJUZͱ6TF$BTF
    Λ۠ผͰ͖Δؾ͕͢Δ

    View Slide

  66. *0ͷڑ཭ͱϨϕϧ
    ೖग़ྗͷڑ཭ͰϨϕϧΛ෼͚Δཧ༝
    w ೖग़ྗͷํ๏͸6*ͷઃܭ΍ɺࣄۀઓུͳͲͷཧ༝͞ΕΔ
    w ೖग़ྗ͸ɺ֎తͳཁҼͷӨڹΛड͚΍͍͢

    ˠߋ৽ස౓͕ߴ͍
    w ೖग़ྗͷ͔Βڑ཭ΛऔΓɺ֎తཁҼͷӨڹൣғΛڱΊΔ
    w ϨϕϧʹΑΔ໌ࣔతͳ۠ผ

    View Slide

  67. ೖग़ྗͱ௚઀ؔ܎͢Δ΋ͷͱɺͦ͏Ͱͳ͍΋ͷΛ෼͚Δ
    ௚઀ؔ܎͠ͳ͍΋ͷ͔Β6TF$BTFͱ&OUJUZΛݟ͚ͭΔ

    View Slide

  68. ໨ඪ
    ୲౰Ҋ݅ͷ
    &OUJUZͱ6TF$BTF
    Λ۠ผͰ͖Δؾ͕͢Δ

    View Slide