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
AKIBA.swift: Layered ArchitectureにおけるRxSwiftを用い...
Search
Takeshi Ihara
April 17, 2017
Programming
2.5k
4
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
AKIBA.swift: Layered ArchitectureにおけるRxSwiftを用いたErrorの伝搬
https://classmethod.connpass.com/event/53603/
Takeshi Ihara
April 17, 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
630
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
ローカルLLMでどこまでコードが書けるか -拡張版 / How much code can be written on a local LLM Extended
kishida
12
4.7k
地域 SRE コミュニティ最前線 - ホンマでっかSRE勉強会
tk3fftk
0
220
AIを活用したE2Eテスト実装効率化のあゆみ / ebisu-mobile-14-kotetu
kotetuco
0
170
壊れたパーサから始める関数型設計と構成的なパーサ #fp_matsuri
raiga0310
2
190
Signal Forms: Details & Live Coding @enterJS 2026 in Mannheim
manfredsteyer
PRO
0
230
信頼性について考えてみる(SRE NEXT 2026 miniLT)
hayama17
0
160
継続モナドとリアクティブプログラミング
yukikurage
3
490
1B+ /day規模のログを管理する技術
broadleaf
0
130
コンテキストの使い捨てをやめる — ビジネスルール駆動開発と miko —
ioki
0
270
トークンをケチるな、設計しろ:GitHub Copilotを賢く使うコンテキスト戦略
ochtum
0
310
関数型プログラミングのメリットって何だろう?
wanko_it
0
160
AIキャラアプリkaiwaの低遅延音声通話基盤をどう作ったか - AWS Gravitonで支える低遅延・低コストAI Agent基盤
mogamit
0
170
Featured
See All Featured
Fantastic passwords and where to find them - at NoRuKo
philnash
52
3.8k
For a Future-Friendly Web
brad_frost
183
10k
Visual Storytelling: How to be a Superhuman Communicator
reverentgeek
2
590
How to build a perfect <img>
jonoalderson
1
5.8k
Put a Button on it: Removing Barriers to Going Fast.
kastner
60
4.4k
Between Models and Reality
mayunak
4
370
Digital Projects Gone Horribly Wrong (And the UX Pros Who Still Save the Day) - Dean Schuster
uxyall
1
1.9k
Save Time (by Creating Custom Rails Generators)
garrettdimon
PRO
32
3.7k
How to Get Subject Matter Experts Bought In and Actively Contributing to SEO & PR Initiatives.
livdayseo
0
150
Darren the Foodie - Storyboard
khoart
PRO
3
3.4k
Writing Fast Ruby
sferik
630
63k
Tips & Tricks on How to Get Your First Job In Tech
honzajavorek
1
560
Transcript
Layered Architectureʹ͓͚Δ RxSwiftΛ༻͍ͨErrorͷൖ Kyobashi.swift Recruit Marketing Partners
ࣗݾհ • Takeshi Ihara / @nonchalant0303 • Recruit Marketing Partners
• iOS Engineer
RxSwiftʹContribute͠·ͨ͠
Layered Architecture *OGSB 1SFTFOUBUJPO %PNBJO
Layered Architecture *OGSB "1*3FRVFTU %# 1SFTFOUBUJPO 6* %PNBJO ϏδωεϩδοΫ
Error *OGSB 1SFTFOUBUJPO %PNBJO $POOFDUJPO 6OBVUIPSJ[FE 4FSWFS&SSPS -PHJD 5SBOTMBUJPO
*OGSB 1SFTFOUBUJPO %PNBJO $POOFDUJPO 4FSWFS&SSPS -PHJD 5SBOTMBUJPO 6OBVUIPSJ[FE "MFSU'BMMCBDL "MFSU3FUSZ
Each Error, Each Process
͜ͷ֤ͷErrorΛͲ͏ͬͯ RxSwiftΛͬͯ ϋϯυϦϯά͢Δ͔͕ࠓճͷ
RxSwift Rx is a generic abstraction of computation expressed through
Observable<Element> interface. This is a Swift version of Rx.
class ViewController: UIViewController { … override func viewDidLoad() { super.viewDidLoad()
presenter.prepare() .subscribe( onNext: { domainModel in // Viewʹө }, onError: { error in // Τϥʔॲཧ } ) .addDisposableTo(disposeBag) } } subscribe - onError Ͳ͜Ͱى͖ͨΤϥʔ͔͔Βͳ͍ʜ
·ͣ
֤ͷΤϥʔΛఆٛ [Infra] enum InfrastructureError: Error { case connection case anthorization
} extension InfrastructureError { static func create(error: Error) -> InfrastructureError { ... return infraError } }
֤ͷΤϥʔΛఆٛ [Domain] enum DomainError: Error { case logic case translation
} extension DomainError { static func create(error: Error) -> DomainError { ... return domainError } }
֤ͷΤϥʔΛఆٛ [Presentation] enum PresentationError: Error { case connection case unknown
}
Layered Architecture x RxSwift *OGSB 1SFTFOUBUJPO %PNBJO 0CTFSWBCMF&OUJUZ 0CTFSWBCMF%PNBJO.PEFM "1*3FRVFTU
&WFOU 7JFXʹө
Layered Architecture x RxSwift *OGSB 1SFTFOUBUJPO %PNBJO 0CTFSWBCMF&OUJUZ 0CTFSWBCMF%PNBJO.PEFM "1*3FRVFTU
&WFOU 7JFXʹө *OGSB&SSPS %PNBJO&SSPS
public static func error(_ error: Swift.Error) -> Observable<E> { return
ErrorProducer(error: error) } Observable.error ObservableType.catchError public func catchError(_ handler: @escaping (Error) throws -> RxSwift.Observable<Self.E>) -> RxSwift.Observable<Self.E> 0CTFSWBCMFʹแΜͩΤϥʔΛੜ͢Δ 0CTFSWBCMFͷதͰൃੜͨ͠ΤϥʔΛ $BUDIͯ͠ճ෮ॲཧΛ͢Δ
protocol Repository { func find() -> Observable<Entity> } struct RepositoryImpl:
Repository { … func find() -> Observable<Entity> { return apiClient.send() .catchError { return Observable.error(InfrastructureError.create(error: $0)) } } } %PNBJOʹެ։͢Δ*OUFSGBDF ͜͜Ͱ"1*͔Βฦ͖ͬͯͨ&SSPSΛ *OGSB&SSPSʹม͍ͯ͠Δ *OGSB
struct Translator { static func translate(entity: Entity) throws -> DomainModel
{ ... throw DomainError.translation ... return domainModel } } protocol UseCase { func prepare() -> Observable<DomainModel> } struct UseCaseImpl: UseCase { … func prepare() -> Observable<DomainModel> { return repository.find() .map { try Translator.translate(entity: $0) } } } NBQͰUISPX͞ΕͨΒ 0CTFSWBCMFFSSPSʹͳΔ %PNBJO
struct Presenter { … func prepare() -> Observable<DomainModel> { return
useCase.prepare() .catchError { error in guard let infraError = error as? InfrastructureError else { return Observable.error(PresentationError.unknown) } switch infraError { case .connection: return Observable.error(PresentationError.connection) default: return Observable.error(PresentationError.unknown) } } } } 1SFTFOUBUJPO ಛఆͷ&SSPSܕͷͱ͖ʹ ಛผͳΤϥʔΛฦ͢
͋ͱPresentationErrorͷܕ ΛݟͯݸผͷॲཧΛ͢Ε
*OGSB 1SFTFOUBUJPO %PNBJO $POOFDUJPO 4FSWFS&SSPS -PHJD 5SBOTMBUJPO 6OBVUIPSJ[FE "MFSU'BMMCBDL "MFSU3FUSZ
Each Error, Each Process
·ͱΊ • Layered Architecture x RxSwiftͷΤϥʔ ൖʹ͍ͭͯͷҰྫΛߟ͑ͨ • catchErrorerrorΛฦͣ͞ճ෮ॲཧॻ͚ ΔͷͰҟৗܥ͔Βਖ਼ৗܥʹΔ͜ͱՄೳ