Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
俺コン Vol.1: Layered Architecture x RxSwiftを活用した適...
Search
Takeshi Ihara
October 02, 2017
Programming
3.4k
8
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
俺コン Vol.1: Layered Architecture x RxSwiftを活用した適切なエラーハンドリング
https://orecon.connpass.com/event/63769/
Takeshi Ihara
October 02, 2017
More Decks by Takeshi Ihara
See All by Takeshi Ihara
iOSDC20200921: Feature Flagを適切に分類することでA/Bテストの運用コストを下げる
nonchalant
3
1.4k
iOSDC 20190906: 動画アプリの投げ銭機能における 消耗型課金の仕組みと実装
nonchalant
3
6.5k
iOSDC 20190906: 動画アプリの投げ銭機能における 消耗型課金の仕組みと実装 with 発表ノート
nonchalant
2
650
Sign In with Apple
nonchalant
1
2.5k
iOSDC RejectCon 20180915: Factoryの自動生成によりテストを書きやすくする
nonchalant
1
760
iOSDC 20180902: 小さくはじめる端末管理
nonchalant
2
1k
devsap 20180728: コード生成のススメ
nonchalant
0
150
potatotips #50: iOSは自動生成の夢を見るか?
nonchalant
0
2k
try! Swift Tokyo 2018: Best Docker Container in Swift
nonchalant
1
1.4k
Other Decks in Programming
See All in Programming
Unity6 URPによる海底をテーマにしたVJシステムの解説 | Unity Shader 完全に理解した 勉強会
gam0022
0
320
FreeBSDでZabbixを動かす
kenkino
0
350
Agentic Software Factoryに、すごく賢いIF文を。 / super smart IF statement into the Agentic Software Factory.
rkaga
7
1.8k
CodeRabbitの効果検証と過ごしてみた3ヶ月
armondando
0
140
APNsからLive Activityを開始する話
yumnumm
0
150
残高管理から台帳サービスへの進化
artoy
0
140
SalesForceを内製化!? ~ HR事業を支える顧客管理基盤のインフラを大公開 ~
oku053
0
120
GitHubハンズオン講座 — 実務レベルのチーム開発のフローを身につけよう
junhat6
0
120
Turning Architecture into Unit Tests in the AI Era (NSSpain XIV)
steliosf
PRO
1
130
Simple Storage Service(S3) is not simple
iwatsukayura
0
190
見えないものを探る要求要件定義に必要な基本的思考 / invisible-requirement-thinking
minodriven
13
6.6k
[ハンズオン]AIへの指示だけで「五目並べ」を作ってみよう
satoshi256kbyte
1
340
Featured
See All Featured
Amusing Abliteration
ianozsvald
1
330
How to Talk to Developers About Accessibility
jct
2
560
Noah Learner - AI + Me: how we built a GSC Bulk Export data pipeline
techseoconnect
PRO
0
450
Designing for Timeless Needs
cassininazir
1
520
Product Roadmaps are Hard
iamctodd
55
13k
Building Experiences: Design Systems, User Experience, and Full Site Editing
marktimemedia
1
620
Crafting Experiences
bethany
1
370
Deep Space Network (abreviated)
tonyrice
0
350
[Rails World 2023 - Day 1 Closing Keynote] - The Magic of Rails
eileencodes
38
3k
Future Trends and Review - Lecture 12 - Web Technologies (1019888BNR)
signer
PRO
0
3.8k
Reality Check: Gamification 10 Years Later
codingconduct
0
2.3k
Building the Perfect Custom Keyboard
takai
2
890
Transcript
Layered Architecture x RxSwift Λ׆༻ͨ͠ దͳΤϥʔϋϯυϦϯά @nonchalant0303 Զίϯ Vol.1 /
Day. 1
ࣗݾհ • Takeshi Ihara • Recruit Marketing Partners • iOS
Engineer • Twitter: @nonchalant0303 • GitHub: Nonchalant
OSS https://github.com/Nonchalant/AppIcon
Kyobashi.swift
ΤϥʔϋϯυϦϯά
ΤϥʔϋϯυϦϯά ϓϩάϥϜͷॲཧதʹॲཧ͕͛ΒΕΔࣄ͕ ൃੜͨ͠ࡍɺͦͷॲཧΛΤϥʔͱͯ͠ରॲ͢Δ ॲཧͷ͜ͱͰ͋Δɻྫ֎ॲཧͱݺΕΔɻ
Α͋͘ΔΤϥʔ
None
Xcode
ͱΓ͋͑ͣ࠶ىಈ ͢Ε͍͍͔
ͳͥ࠶ىಈ͠Α͏ͱߟ͑ͨͷ͔ʁ աڈʹମݧͨ͜͠ͱ͕͋Δ ͦͷࡍʹ࠶ىಈͨ͠Β࣏ͬͨͨΊ
None
ϝʔϧΞυϨε͕ ؒҧ͍ͬͯΔʁ ύεϫʔυ͕ ؒҧ͍ͬͯΔʁ
ϝʔϧΞυϨε͕ ؒҧ͍ͬͯΔʁ ύεϫʔυ͕ ؒҧ͍ͬͯΔʁ αʔϏε յΕͯΔʂ αʔϏε յΕͯΔʂ
αʔϏεΕ
Ϣʔβʔ༷ʑ • ITϦςϥγʔ͕ߴ͍͔͍͔ • αʔϏεʹ׳Ε͠ΜͰ͍Δ͔Ͳ͏͔ • …
None
࣍ʹ͖͢ߦಈ͕ ͔Δ
దͳΤϥʔ
None
࣍ʹ͖͢ߦಈ͕ ͔Βͳ͍
ෆదͳΤϥʔ
None
ϝʔϧΞυϨε͕ ؒҧ͍ͬͯΔʁ ύεϫʔυ͕ ؒҧ͍ͬͯΔʁ αʔϏε յΕͯΔʂ αʔϏε յΕͯΔʂ
࣍ʹ͖͢ߦಈ͕ ͔Δ
దͳΤϥʔ
ΤϥʔϋϯυϦϯά ൃੜͨ͠ΤϥʔʹԠͯ͡ɺϢʔβʔʹݱࡏͷঢ় ଶΛࣔ͠ɺඞཁʹԠͯ࣍͡ͷߦಈΛࣔ͢͜ͱ
ΤϥʔϋϯυϦϯά͍͠
Τϥʔͷछྨ͕ଟ͍ • ωοτϫʔΫͷଓΤϥʔ • ೖྗ߲ͷؒҧ͍ʹΑΔΤϥʔ • λΠϜΞτʹΑΔΤϥʔ • …
1. ΤϥʔΛͻͨ͢Βચ͍ग़͢ ൈ͚࿙Εڐ༰͢Δ
2. ΤϥʔΛྨ͢Δ
2. ΤϥʔΛྨ͢Δ Πϯϑϥܥ ϏδωεϩδοΫܥ ωοτϫʔΫଓΤϥʔ ೖྗ߲ͷؒҧ͍ʹΑΔΤϥʔ λΠϜΞτʹΑΔΤϥʔ ϢʔβʔͷݖݶΤϥʔ ʜ ʜ
Layered Architecture *OGSBTUSVDUVSF 1SFTFOUBUJPO %PNBJO
Infrastructure Πϯϑϥܥ ωοτϫʔΫଓΤϥʔ λΠϜΞτʹΑΔΤϥʔ ʜ enum InfrastructureError: Error { case
connection case timeout … case unknown }
Domain ϏδωεϩδοΫܥ ೖྗ߲ͷؒҧ͍ʹΑΔΤϥʔ ϢʔβʔͷݖݶΤϥʔ ʜ enum DomainError: Error { case
input case permission ... case unknown }
Layered Architectureͷݪଇ ԼͷϨΠϠʔͷਓ্ͷϨΠϠʔ͕ެ։͍ͯ͠ ΔJOUFSGBDF͚ͩΛ͍ͬͯΔ
ݪଇʹͯ͠ࢀরͰ͖Δ *OGSBTUSVDUVSF 1SFTFOUBUJPO %PNBJO
Embedded Framework *OGSBTUSVDUVSF 1SFTFOUBUJPO %PNBJO
[Pros] Embedded Framework • Layerͷґଘ͕ؔ໌֬ʹͳΔ • ࠩϏϧυ͕ಇ͖͘͢ͳΔ • ෆඞཁͳϥΠϒϥϦ͕ࢀরͰ͖ͳ͘ͳΔ •
ModuleຖʹݴޠͷMigration͕Ͱ͖Δ
ϨΠϠʔؒͷܨ͗ࠐΈ *OGSBTUSVDUVSF 1SFTFOUBUJPO %PNBJO *OGSBTUSVDUVSF&SSPS %PNBJO&SSPS
InfrastructureErrorΛ PresentationʹൖͰ͖ͳ͍ InfrastructureErrorΛ DomainErrorʹม͢Δඞཁ͕͋Δ
InfrastructureError → DomainError *OGSBTUSVDUVSF&SSPS %PNBJO&SSPS DPOOFDUJPO DPOOFDUJPO UJNFPVU ʜ JOQVU
ʜ QFSNJTTJPO
ϩάΠϯ 1. ϝʔϧΞυϨεͱύεϫʔυೖྗ 2. ϩάΠϯ͢Δ 3. Success or Failure
• ྫ֎ΛUISPX͢Δ • force-tryΛ༻͍ͳ͍ͱࢀর͢Δϝιου ͯ͢ʹthrows͕ඞཁʹͳΔ 1. try-catch
*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 }
• ྫ֎Λ'BJMVSFઅʹ͢ • Switch-caseΛຖճॻ͘ඞཁ͕͋Δ • มॲཧΛ͠ͳ͍߹ͰDBTFจ͕ඞཁʹͳ Δ 2. Result
*OGSB 1SFTFOUBUJPO %PNBJO ϩάΠϯ public protocol PublishRepository { func login(email:
String, password: String) -> Result<User> } public protocol LoginUseCase { func login(email: String, password: String) -> Result<Void> } public protocol LoginPresenter { func login(email: String, password: String) -> Result<Void> }
• ྫ֎ΛPO&SSPSઅʹ͢ • catchErrorઅͰΤϥʔϋϯυϦϯά͢Δ • catchErrorઅ͕ͳ͍߹ͦͷ··ྫ֎͕ ԼྲྀʹྲྀΕΔ 3. RxSwift
*OGSB 1SFTFOUBUJPO %PNBJO ϩάΠϯ public protocol PublishRepository { func login(email:
String, password: String) -> Single<User> } public protocol LoginUseCase { func login(email: String, password: String) -> Completable } public protocol LoginPresenter { func login(email: String, password: String) -> Completable }
*OGSBTUSVDUVSF&SSPS %PNBJO&SSPS 1SFTFOUBUJPO&SSPS DPOOFDUJPO DPOOFDUJPO DPOOFDUJPO QFSNJTTJPO QFSNJTTJPO UFNQPSBSZ1BTTXPSE &YQJSFE
UFNQPSBSZ1BTTXPSE &YQJSFE BQJ3FQPOTF SFTQPOTF SFTQPOTF JOUFSOBMTFSWFSFSSPS VOLOPXO VOLOPXO USBOTMBUJPO
struct PublishRepositoryImpl: PublishRepository { func login(email: String, password: String) ->
Single<User> { return apiClient.create( with: PublishRequest(email: email, password: password) ) } } Infrastructure
struct LoginUseCaseImpl: LoginUseCase { func login(email: String, password: String) ->
Completable { return repository.login(email: email, password: password) .asObservable() .catchError { error -> Observable<User> in return Observable.error(DomainError.create(with: error)) } .flatMap { user -> Observable<Never> in guard user.hasPermission else { throw DomainError.permission } guard !user.isTemporaryPasswordExpired else { throw DomainError.temporaryPasswordExpired } return Observable.empty() } .asCompletable() } } Domain
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
֤ϨΠϠʔͰ ΤϥʔϋϯυϦϯάΛߦ͏
·ͱΊ • ΤϥʔͷೝࣝΛἧ͑Δ͜ͱʹΑΓυΩϡϝ ϯτԽͰ͖Δ • Embedded FrameworkʹΑΓΤϥʔʹ LayerͷࣝΛ༩Ͱ͖Δ • Layerͷܨ͗ࠐΈ֤ϓϩμΫτʹ߹Θͤͨ
ํ๏Λ࠾༻͠·͠ΐ͏