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.4k
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
AI駆動開発にグラフDBを重ねてみた
satoshi256kbyte
2
790
Jetpack Compose メカニズム
skydoves
0
370
Go × SIMDで高速化するベクトル検索 ~ルーフラインモデルでSIMDが効く境界を探れ! ~
po3rin
1
480
大喜利で理解するLLM as a Judge / Understanding LLM-as-a-Judge through Ogiri
rockname
0
100
AGENTS.md Is Not Enough:Build Skills, Don't Download Them
lx_t
0
110
TiDB Cloudのカスタムコントローラーによるオートスケール対応
takaidohigasi
0
110
市販E-Readerを乗っ取れ 〜Embedded Swiftで電子ペーパーガジェットを制御する〜
trickart
0
190
AWS Step Functions 大規模並列の壁を越える / jaws-sonic-2026-niigata-step-functions
kasacchiful
PRO
1
450
Foundry Localでエージェント開発
seosoft
0
190
JPUG勉強会 OSSデータベースの内部構造を理解しよう(第2回)
oga5
0
200
GKE で Pod の見方を変えたら、スケールアウト時の挙動を真に捉えられた話
stkk
0
120
選挙速報を多くのユーザーへ 届ける Live Activities 設計
hamayokokuririn
0
140
Featured
See All Featured
Between Models and Reality
mayunak
4
460
HU Berlin: Industrial-Strength Natural Language Processing with spaCy and Prodigy
inesmontani
PRO
0
700
Visual Storytelling: How to be a Superhuman Communicator
reverentgeek
2
660
KATA
mclloyd
PRO
35
15k
Design of three-dimensional binary manipulators for pick-and-place task avoiding obstacles (IECON2024)
konakalab
0
590
Art, The Web, and Tiny UX
lynnandtonic
304
22k
Rebuilding a faster, lazier Slack
samanthasiow
85
9.6k
So, you think you're a good person
axbom
PRO
2
2.2k
How to optimise 3,500 product descriptions for ecommerce in one day using ChatGPT
katarinadahlin
PRO
2
3.8k
Large-scale JavaScript Application Architecture
addyosmani
515
110k
Dealing with People You Can't Stand - Big Design 2015
cassininazir
367
27k
[RailsConf 2023 Opening Keynote] The Magic of Rails
eileencodes
31
10k
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ͷܨ͗ࠐΈ֤ϓϩμΫτʹ߹Θͤͨ
ํ๏Λ࠾༻͠·͠ΐ͏