Slide 1

Slide 1 text

Layered Architecture x RxSwift Λ׆༻ͨ͠ ద੾ͳΤϥʔϋϯυϦϯά @nonchalant0303 Զίϯ Vol.1 / Day. 1

Slide 2

Slide 2 text

ࣗݾ঺հ • Takeshi Ihara • Recruit Marketing Partners • iOS Engineer • Twitter: @nonchalant0303 • GitHub: Nonchalant

Slide 3

Slide 3 text

OSS https://github.com/Nonchalant/AppIcon

Slide 4

Slide 4 text

Kyobashi.swift

Slide 5

Slide 5 text

ΤϥʔϋϯυϦϯά

Slide 6

Slide 6 text

ΤϥʔϋϯυϦϯά ϓϩάϥϜͷॲཧதʹॲཧ͕๦͛ΒΕΔࣄ৅͕ ൃੜͨ͠ࡍɺͦͷॲཧΛΤϥʔͱͯ͠ରॲ͢Δ ॲཧͷ͜ͱͰ͋Δɻྫ֎ॲཧͱ΋ݺ͹ΕΔɻ

Slide 7

Slide 7 text

Α͋͘ΔΤϥʔ

Slide 8

Slide 8 text

No content

Slide 9

Slide 9 text

Xcode

Slide 10

Slide 10 text

ͱΓ͋͑ͣ࠶ىಈ ͢Ε͹͍͍͔

Slide 11

Slide 11 text

ͳͥ࠶ىಈ͠Α͏ͱߟ͑ͨͷ͔ʁ աڈʹମݧͨ͜͠ͱ͕͋Δ ͦͷࡍʹ࠶ىಈͨ͠Β࣏ͬͨͨΊ

Slide 12

Slide 12 text

No content

Slide 13

Slide 13 text

ϝʔϧΞυϨε͕ ؒҧ͍ͬͯΔʁ ύεϫʔυ͕ ؒҧ͍ͬͯΔʁ

Slide 14

Slide 14 text

ϝʔϧΞυϨε͕ ؒҧ͍ͬͯΔʁ ύεϫʔυ͕ ؒҧ͍ͬͯΔʁ αʔϏε յΕͯΔʂ αʔϏε յΕͯΔʂ

Slide 15

Slide 15 text

αʔϏε཭Ε

Slide 16

Slide 16 text

Ϣʔβʔ͸༷ʑ • ITϦςϥγʔ͕ߴ͍͔௿͍͔ • αʔϏεʹ׳Ε਌͠ΜͰ͍Δ͔Ͳ͏͔ • …

Slide 17

Slide 17 text

No content

Slide 18

Slide 18 text

࣍ʹ͢΂͖ߦಈ͕ ෼͔Δ

Slide 19

Slide 19 text

ద੾ͳΤϥʔ

Slide 20

Slide 20 text

No content

Slide 21

Slide 21 text

࣍ʹ͢΂͖ߦಈ͕ ෼͔Βͳ͍

Slide 22

Slide 22 text

ෆద੾ͳΤϥʔ

Slide 23

Slide 23 text

No content

Slide 24

Slide 24 text

ϝʔϧΞυϨε͕ ؒҧ͍ͬͯΔʁ ύεϫʔυ͕ ؒҧ͍ͬͯΔʁ αʔϏε յΕͯΔʂ αʔϏε յΕͯΔʂ

Slide 25

Slide 25 text

࣍ʹ͢΂͖ߦಈ͕ ෼͔Δ

Slide 26

Slide 26 text

ద੾ͳΤϥʔ

Slide 27

Slide 27 text

ΤϥʔϋϯυϦϯά ൃੜͨ͠ΤϥʔʹԠͯ͡ɺϢʔβʔʹݱࡏͷঢ় ଶΛࣔ͠ɺඞཁʹԠͯ࣍͡ͷߦಈΛࣔ͢͜ͱ

Slide 28

Slide 28 text

ΤϥʔϋϯυϦϯά͸೉͍͠

Slide 29

Slide 29 text

Τϥʔͷछྨ͕ଟ͍ • ωοτϫʔΫͷ઀ଓΤϥʔ • ೖྗ߲໨ͷؒҧ͍ʹΑΔΤϥʔ • λΠϜΞ΢τʹΑΔΤϥʔ • …

Slide 30

Slide 30 text

1. ΤϥʔΛͻͨ͢Βચ͍ग़͢ ൈ͚࿙Ε͸ڐ༰͢Δ

Slide 31

Slide 31 text

2. ΤϥʔΛ෼ྨ͢Δ

Slide 32

Slide 32 text

2. ΤϥʔΛ෼ྨ͢Δ Πϯϑϥܥ ϏδωεϩδοΫܥ ωοτϫʔΫ઀ଓΤϥʔ ೖྗ߲໨ͷؒҧ͍ʹΑΔΤϥʔ λΠϜΞ΢τʹΑΔΤϥʔ ϢʔβʔͷݖݶΤϥʔ ʜ ʜ

Slide 33

Slide 33 text

Layered Architecture *OGSBTUSVDUVSF 1SFTFOUBUJPO %PNBJO

Slide 34

Slide 34 text

Infrastructure Πϯϑϥܥ ωοτϫʔΫ઀ଓΤϥʔ λΠϜΞ΢τʹΑΔΤϥʔ ʜ enum InfrastructureError: Error { case connection case timeout … case unknown }

Slide 35

Slide 35 text

Domain ϏδωεϩδοΫܥ ೖྗ߲໨ͷؒҧ͍ʹΑΔΤϥʔ ϢʔβʔͷݖݶΤϥʔ ʜ enum DomainError: Error { case input case permission ... case unknown }

Slide 36

Slide 36 text

Layered Architectureͷݪଇ ԼͷϨΠϠʔͷਓ͸্ͷϨΠϠʔ͕ެ։͍ͯ͠ ΔJOUFSGBDF͚ͩΛ஌͍ͬͯΔ

Slide 37

Slide 37 text

ݪଇʹ൓ͯ͠ࢀরͰ͖Δ *OGSBTUSVDUVSF 1SFTFOUBUJPO %PNBJO

Slide 38

Slide 38 text

Embedded Framework *OGSBTUSVDUVSF 1SFTFOUBUJPO %PNBJO

Slide 39

Slide 39 text

[Pros] Embedded Framework • Layerͷґଘؔ܎͕໌֬ʹͳΔ • ࠩ෼Ϗϧυ͕ಇ͖΍͘͢ͳΔ • ෆඞཁͳϥΠϒϥϦ͕ࢀরͰ͖ͳ͘ͳΔ • ModuleຖʹݴޠͷMigration͕Ͱ͖Δ

Slide 40

Slide 40 text

ϨΠϠʔؒͷܨ͗ࠐΈ *OGSBTUSVDUVSF 1SFTFOUBUJPO %PNBJO *OGSBTUSVDUVSF&SSPS %PNBJO&SSPS

Slide 41

Slide 41 text

InfrastructureErrorΛ Presentationʹ఻ൖͰ͖ͳ͍ InfrastructureErrorΛ DomainErrorʹม׵͢Δඞཁ͕͋Δ

Slide 42

Slide 42 text

InfrastructureError → DomainError *OGSBTUSVDUVSF&SSPS %PNBJO&SSPS DPOOFDUJPO DPOOFDUJPO UJNFPVU ʜ JOQVU ʜ QFSNJTTJPO

Slide 43

Slide 43 text

ϩάΠϯ 1. ϝʔϧΞυϨεͱύεϫʔυೖྗ 2. ϩάΠϯ͢Δ 3. Success or Failure

Slide 44

Slide 44 text

• ྫ֎ΛUISPX͢Δ • force-tryΛ༻͍ͳ͍ͱࢀর͢Δϝιου ͢΂ͯʹthrows͕ඞཁʹͳΔ 1. try-catch

Slide 45

Slide 45 text

*OGSB 1SFTFOUBUJPO %PNBJO ϩάΠϯ public protocol PublishRepository { func login(email: String, password: String) throws -> User } public protocol LoginUseCase { func login(email: String, password: String) throws } public protocol LoginPresenter { func login(email: String, password: String) throws }

Slide 46

Slide 46 text

• ྫ֎Λ'BJMVSFઅʹ౉͢ • Switch-caseΛຖճॻ͘ඞཁ͕͋Δ • ม׵ॲཧΛ͠ͳ͍৔߹Ͱ΋DBTFจ͕ඞཁʹͳ Δ 2. Result

Slide 47

Slide 47 text

*OGSB 1SFTFOUBUJPO %PNBJO ϩάΠϯ public protocol PublishRepository { func login(email: String, password: String) -> Result } public protocol LoginUseCase { func login(email: String, password: String) -> Result } public protocol LoginPresenter { func login(email: String, password: String) -> Result }

Slide 48

Slide 48 text

• ྫ֎ΛPO&SSPSઅʹ౉͢ • catchErrorઅͰΤϥʔϋϯυϦϯά͢Δ • catchErrorઅ͕ͳ͍৔߹͸ͦͷ··ྫ֎͕ ԼྲྀʹྲྀΕΔ 3. RxSwift

Slide 49

Slide 49 text

*OGSB 1SFTFOUBUJPO %PNBJO ϩάΠϯ public protocol PublishRepository { func login(email: String, password: String) -> Single } public protocol LoginUseCase { func login(email: String, password: String) -> Completable } public protocol LoginPresenter { func login(email: String, password: String) -> Completable }

Slide 50

Slide 50 text

*OGSBTUSVDUVSF&SSPS %PNBJO&SSPS 1SFTFOUBUJPO&SSPS DPOOFDUJPO DPOOFDUJPO DPOOFDUJPO QFSNJTTJPO QFSNJTTJPO UFNQPSBSZ1BTTXPSE &YQJSFE UFNQPSBSZ1BTTXPSE &YQJSFE BQJ3FQPOTF SFTQPOTF SFTQPOTF JOUFSOBMTFSWFSFSSPS VOLOPXO VOLOPXO USBOTMBUJPO

Slide 51

Slide 51 text

struct PublishRepositoryImpl: PublishRepository { func login(email: String, password: String) -> Single { return apiClient.create( with: PublishRequest(email: email, password: password) ) } } Infrastructure

Slide 52

Slide 52 text

struct LoginUseCaseImpl: LoginUseCase { func login(email: String, password: String) -> Completable { return repository.login(email: email, password: password) .asObservable() .catchError { error -> Observable in return Observable.error(DomainError.create(with: error)) } .flatMap { user -> Observable in guard user.hasPermission else { throw DomainError.permission } guard !user.isTemporaryPasswordExpired else { throw DomainError.temporaryPasswordExpired } return Observable.empty() } .asCompletable() } } Domain

Slide 53

Slide 53 text

struct LoginPresenterImpl: LoginPresenter { func login(email: String, password: String) -> Completable { return useCase.login(email: email, password: password) .catchError { error -> Completable in return Completable.error(PresentationError.create(with: error)) } } } Presentation

Slide 54

Slide 54 text

֤ϨΠϠʔͰ ΤϥʔϋϯυϦϯάΛߦ͏

Slide 55

Slide 55 text

·ͱΊ • ΤϥʔͷೝࣝΛἧ͑Δ͜ͱʹΑΓυΩϡϝ ϯτԽͰ͖Δ • Embedded FrameworkʹΑΓΤϥʔʹ Layerͷ஌ࣝΛ෇༩Ͱ͖Δ • Layerͷܨ͗ࠐΈ͸֤ϓϩμΫτʹ߹Θͤͨ ํ๏Λ࠾༻͠·͠ΐ͏