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
mrbgem 三角測量 開発
ogom
0
200
Agentic Software Factoryに、すごく賢いIF文を。 / super smart IF statement into the Agentic Software Factory.
rkaga
7
1.8k
Ghostty + Neovimで作る 透明でカッコ良い開発環境
j341nono
0
150
re:Inventに行く前に知っておきたい現地参加のノウハウ
nokomoro3
0
360
設計次第でAIコードの読む量は減らせる / designing-for-code-reading
minodriven
34
15k
Verilogで学ぶCPU自作入門.pdf
uyuki234
8
4k
パズルゲームの作り方 / how to make puzzle games
kaityo256
PRO
2
270
テストを司るデーモンに会いに行く 〜隔離した仮想マシンでテストを通すまで〜
h1d3mun3
1
620
iOSDC2026登壇資料.pdf
riofujimon
0
210
Everything will be SERVERLESS — 信じて運用した10年の経験値 / Everything Will be Serverless — Lessons Learned from 10 Years of Operational Experience
seike460
PRO
1
740
Androidだけじゃない、DroidKaigiで広がった私の技術スタック
akkeylab
0
120
C#の現在地 進化の歴史と、AI時代の.NET Everywhere
neuecc
5
4.9k
Featured
See All Featured
sira's awesome portfolio website redesign presentation
elsirapls
0
440
Taking LLMs out of the black box: A practical guide to human-in-the-loop distillation
inesmontani
PRO
3
2.4k
Automating Front-end Workflow
addyosmani
1369
210k
How to Ace a Technical Interview
jacobian
280
24k
Into the Great Unknown - MozCon
thekraken
41
2.8k
Cheating the UX When There Is Nothing More to Optimize - PixelPioneers
stephaniewalter
287
14k
The Spectacular Lies of Maps
axbom
PRO
1
1.1k
A Soul's Torment
seathinner
8
3.7k
ReactJS: Keep Simple. Everything can be a component!
pedronauck
666
130k
We Are The Robots
honzajavorek
0
380
From Legacy to Launchpad: Building Startup-Ready Communities
dugsong
0
350
Test your architecture with Archunit
thirion
2
2.4k
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ͷܨ͗ࠐΈ֤ϓϩμΫτʹ߹Θͤͨ
ํ๏Λ࠾༻͠·͠ΐ͏