Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
俺コン Vol.1: Layered Architecture x RxSwiftを活用した適...
Search
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
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.4k
iOSDC 20190906: 動画アプリの投げ銭機能における 消耗型課金の仕組みと実装 with 発表ノート
nonchalant
2
640
Sign In with Apple
nonchalant
1
2.4k
iOSDC RejectCon 20180915: Factoryの自動生成によりテストを書きやすくする
nonchalant
1
750
iOSDC 20180902: 小さくはじめる端末管理
nonchalant
2
1k
devsap 20180728: コード生成のススメ
nonchalant
0
140
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
AI時代に設計が 最大の生産性レバーになる 意図駆動開発とデータを消さない設計|Don't Delete Your Data or Your Intent — Design as the Deepest Lever in the AI Era
tomohisa
1
630
php-fpmのプロセスが枯渇した日-調査・対処・そして本当にやるべきだったこと-
shibuchaaaan
0
210
What's New in Android 2026
veronikapj
0
250
AI時代のPHPer生存戦略 ~「言語、もうなんでもよくない?」に本気で向き合う~
vivion
0
230
torikago - Ruby::Boxで照らすモジュラモノリスの実行境界
se4weed
1
330
AI Engineeringは、AIプロダクトだけのものか? 〜AIがソフトウェアを作る時代の新しい当たり前〜 / No AI in your product. AI Engineering in your development.
rkaga
4
360
AWS CDK を「作」ってみた 〜フルスクラッチで見えた CDK の裏側〜 / aws-cdk-from-scratch
gotok365
3
2.8k
The Past, Present, and Future of Enterprise Java
ivargrimstad
0
520
ここ半年くらいでAIに作らせたR用ツール
eitsupi
0
360
そこに3びきプロダクトがいるじゃろう——生成AI時代における“価値が届かない理由”の構造
kosuket
0
400
Welcome to the "Parametricity" 🏙️ − Generic だけど Specific な世界 −
guvalif
PRO
1
200
Claude CodeとAgentCore Gatewayを繋ぐ際の認証認可 / Authentication and authorization when connecting Claude Code with AgentCore Gateway
har1101
0
150
Featured
See All Featured
Introduction to Domain-Driven Design and Collaborative software design
baasie
1
920
Why Your Marketing Sucks and What You Can Do About It - Sophie Logan
marketingsoph
0
350
Breaking role norms: Why Content Design is so much more than writing copy - Taylor Woolridge
uxyall
0
360
Exploring the Power of Turbo Streams & Action Cable | RailsConf2023
kevinliebholz
37
6.5k
Tips & Tricks on How to Get Your First Job In Tech
honzajavorek
1
660
How to build an LLM SEO readiness audit: a practical framework
nmsamuel
1
820
The B2B funnel & how to create a winning content strategy
katarinadahlin
PRO
1
460
How GitHub (no longer) Works
holman
316
150k
Why Our Code Smells
bkeepers
PRO
340
58k
SEO in 2025: How to Prepare for the Future of Search
ipullrank
3
3.7k
Building Better People: How to give real-time feedback that sticks.
wjessup
370
20k
Heart Work Chapter 1 - Part 1
lfama
PRO
8
36k
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ͷܨ͗ࠐΈ֤ϓϩμΫτʹ߹Θͤͨ
ํ๏Λ࠾༻͠·͠ΐ͏