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
Designable Archetecture
Search
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
to4iki
October 17, 2017
Programming
110
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Designable Archetecture
WIP
to4iki
October 17, 2017
More Decks by to4iki
See All by to4iki
Claude Code の活用事例
to4iki
0
180
Swift Concurrencyを利用したUIViewController表示の排他制御の実装
to4iki
0
3.7k
ケースに応じたUICollectionViewのレイアウト実装パターン
to4iki
1
5.8k
ビューインプレッションの計測方法
to4iki
1
1.1k
秘伝の `gitconfig`
to4iki
1
470
Abema iOS Architecture
to4iki
12
3.6k
timetable-bot
to4iki
0
15k
BLoC Pattern Introduction with Swift
to4iki
2
1.4k
nel
to4iki
0
200
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
740
生成AI導入の「期待外れ」を乗り越える ー 開発フロー改革が目指す、真の組織変革
starfish719
0
4.1k
霧の中の代数的エフェクト
funnyycat
1
490
作るコストが小さくなった時代 幸せに働くために改めて考えたいこと 〜エンジニアとして価値を出し続けるために注視している二分野〜
yuppeeng
0
190
Cloudflare is Agents
chimame
0
150
メールのエイリアス機能を履き違えない
isshinfunada
0
230
Built Our Own Background Agent at LayerX
layerx
PRO
9
5.1k
変わらないものが、変わるものを決める — 意図駆動開発 × イベントソーシング × イミュータブル | What Doesn't Change Decides What Can — IDD × Event Sourcing × Immutability
tomohisa
0
1.4k
使いながら育てる Claude Code — 開発フローの1コマンド化 × 繰り返し指摘の自動仕組み化
shiki_kakaku
0
1.7k
S3 を使うアプリケーションをローカル完結で動かすことに全力を注いでみた / Running S3 Apps Offline
contour_gara
0
400
2年かけて Deno に DOMMatrix を実装した話 / How I implemented DOMMatrix in Deno over two years
petamoriken
0
210
ビデオ通話が繋がる0.2秒で何が起きているのか
supurazako
2
180
Featured
See All Featured
The State of eCommerce SEO: How to Win in Today's Products SERPs - #SEOweek
aleyda
2
11k
ピンチをチャンスに:未来をつくるプロダクトロードマップ #pmconf2020
aki_iinuma
128
56k
Digital Ethics as a Driver of Design Innovation
axbom
PRO
1
360
The Limits of Empathy - UXLibs8
cassininazir
1
600
Information Architects: The Missing Link in Design Systems
soysaucechin
0
1.1k
CoffeeScript is Beautiful & I Never Want to Write Plain JavaScript Again
sstephenson
162
16k
Exploring the Power of Turbo Streams & Action Cable | RailsConf2023
kevinliebholz
37
6.5k
Mozcon NYC 2025: Stop Losing SEO Traffic
samtorres
1
480
SERP Conf. Vienna - Web Accessibility: Optimizing for Inclusivity and SEO
sarafernandez
2
1.5k
Why Mistakes Are the Best Teachers: Turning Failure into a Pathway for Growth
auna
0
200
End of SEO as We Know It (SMX Advanced Version)
ipullrank
3
4.3k
Easily Structure & Communicate Ideas using Wireframe
afnizarnur
194
17k
Transcript
Designable Architecture Shinjuku.LT#13 @to4iki 1
Profile 4 @to4iki 4 iOS Developer ! 2
Agenda 4 Կނઃܭ͢Δͷ͔ 4 Ͳ͏ઃܭ͖͔͢ 4 ϞόΠϧʹ͓͚Δઃܭ 3
Կނઃܭ͢Δͷ͔ 4
୯७ͳΞϓϦέʔγϣϯ 4 શମ૾͕Ѳ͍͢͠ 4 1ਓͰಇ͘ͳΒɺԿΛߦ͏ͷ͔͙ʹѲͰ͖ Δ 5
ෳࡶͳΞϓϦέʔγϣϯ 4 શମ૾͕ҰʹѲͣ͠Β͍ 4 େͰಇ͘ͳΒɺ୭͔͕ԿΛ͍ͯ͠Δͷ͔Ѳ ͮ͠Β͍ 6
ෳࡶͳ֓೦Λ ׂͯ͠ཧ͍ͨ͠ 7
ෳࡶͳ֓೦ͷׂ 4 ը໘͝ͱ? 4 ػೳ͝ͱ? 4 ׂͷํ༷ʑͰɺ͜ΕΛܾΊΔͷ͕ઃܭ 8
ιϑτ(มߋ͕؆୯ͳ)ΣΞ() ϋʔυ(มߋ͕͍͠)ΣΞ() 9
ιϑτΣΞ "มߋ͕؆୯ʹͰ͖Δ" Α͏ʹ࡞Βͳ͚ΕͳΒͳ͍ 10
ͳͥઃܭ͢Δͷ͔ ؆୯ʹιϑτΣΞ ΛมߋͰ͖ΔΑ͏ɺ ෳࡶͳ֓೦Λׂ͠ ͍ͨ 11
Ͳ͏ઃܭ͖͔͢ 12
Presentation Domain Separation(PDS)1 4 UIʹؔΘΔͷͱɺͦΕҎ֎ͱͰׂ͠Α͏ 4 ͦΕҎ֎ = ڊେͳModelͱͯ͠Γग़͢ 1
https://martinfowler.com/bliki/PresentationDomainSeparation.html 13
PDSͷϝϦοτ 4 PresentationϩδοΫͱDomainϩδοΫ͕ ͔Ε͍ͯΔͱɺཧղ͍͢͠ 4 View͔Γ͍͢(HTML, JSON, ViewController) 4 UIςετ͕͠ʹ͍ͨ͘ΊɺͦΕΛ͢Δࣄ
ͰςετՄೳͳϩδοΫ෦ʹूதͰ͖Δ 14
PDSΛͲ͏࣮ݱ͢Δ͔ 15
࣮ݱํ๏ 4 MVW 4 MVC 4 MVP 4 MVVM 4
CleanArchitecture 4 Flux 4 etc 16
৭ʑ͋Δ 17
ϞόΠϧͷจ຺Ͱߟ͑ͯΈΔ = ϞόΠϧʹ͓͚Δઃܭ 18
બ͢Δʹ͋ͨͬ ͯ......Ͳ͏͍ͬͨ՝ ͕͋Δ͔Λੳ͢ Δ 19
ϞόΠϧ։ൃͷ՝(͍͠ ॴ) 1. APIͷϨεϙϯεΛͲͷΑ͏ʹViewʹө͢Δ ͔ 2. ෳࡶʹՄม͠͏Δσʔλͷঢ়ଶΛͲͷΑ͏ʹ Viewʹө͢Δ͔ 3. 1ͭͷσʔλมߋॲཧʹରͯ͠ෳͷModel͕
ؔ࿈͠߹͏ͷΛͲ͏ཧ͢Δ͔ 20
͜ΕΒͷΛղܾ ͢Δઃܭύλʔϯ͕ ཉ͍͠ʂ 21
1. APIͷϨεϙϯε ΛͲͷΑ͏ʹViewʹ ө͢Δ͔ 22
ex. Α͋͘Δ࣮ 4 RESTͷAPIͰ͋ΕϦιʔε୯ҐͰϨεϙϯ εʹ֘͢ΔΦϒδΣΫτΛ࡞ 4 ෳͷϦιʔεΛجʹը໘Λߏ͢ΔͷͰ͋Ε ɺͦΕΒΛݸผʹϦΫΤετ͠ඳը͢Δ 4 ඳը༻ͷModelʹม͢Δʁ
4 ͲͷϨΠϠʔͰߦ͏ʁͲͷΫϥε͕ͦΕΛ ߦ͏ʁ 23
24
ͭΒ͍ 25
ը໘୯ҐͷϨεϙϯεͩͬͨΒ ࡉ͔͍ࣄߟ͑ͳͯ͘ࡁΉͷͰ 26
27
ཧܗ 4 Read͕ϝΠϯͷΞϓϦͰ͋ΕɺσʔλΛͦ ͷ··Viewʹө͢Δ͚ͩͰΑ͍ͣ 4 APIଆͰ࠷దͳσʔλߏͰฦ͢ඞཁ͕͋Δ 4 ͘͠ΫϥΠΞϯτͰฒྻͰϦΫΤετ Λ͛ϖʔδใͱͯ͠ܗ͢Δ 28
29
ཧܗ 4 σʔλͷ࣋ͪํʹؔͯ͠ϨεϙϯεΛϖʔδ ใʹ࠷దԽͰ͖Εɺෳࡶͳෆཁ ʹͳΔ 4 Write͕ʹؔͯ͠ϑΥʔϜModelΛͲͷΑ͏ ʹͯ͠ӬଓԽ༻ͷModelʹม͢ΔʁReadͷ Modelͱಉ͡ߏʹ͢Δ?RͱWͷಉظ?ͳͲ ߟ͑Δ͜ͱ͕ଟ͍
=> ex. CQRS(ࠓճ۷ΓԼ͛ͳ͍ɺษڧ͠· 30
2. ෳࡶʹՄม͠͏ Δσʔλͷঢ়ଶΛͲ ͷΑ͏ʹViewʹө ͢Δ͔ 31
ex. Α͋͘Δ࣮ 4 खಈͰViewͷঢ়ଶͱσʔλΛಉظ͢Δ 4 ಉظͷॲཧ͕ࢄΒΓɺ͍ͭͲ͜ͰԿ͕Ͳ ͏มΘΔͷ͔͕༧ଌͮ͠Β͍ 4 DelegateύλʔϯʹΑΔ࣮ͩͱɺͲͷλΠ ϛϯάͰ࣮ߦ͞ΕΔͷ͔ͳͲ͕ݺͼग़͠ଆͱ࣮
ߦଆͰίʔυͷཧతͳڑ͕Ε͓ͯΓɺ Ѳ͢Δͷʹ͕͔͔࣌ؒΔ 32
ͭΒ͍ 33
MVVM 34
35
MVVM2 4 ViewModelViewͷͨΊͷঢ়ଶετΞ 4 ViewViewModelʹґଘ͠ɺViewModel Modelʹґଘ͢Δ(୯ํͷґଘ) 4 ViewϢʔβʔ͔ΒͷΞΫγϣϯΛड͚ͯɺ ͦͷΠϕϯτΛViewModelʹbind͢Δɻͦ͠ ͯͦͷbind͞ΕͨΠϕϯτʹΑͬͯ
2 https://speakerdeck.com/koutalou/manehuowadofalseshe-ji-hefalseapuroti 36
37
ViewModel 38
class SearchRepositoryViewModel { ... func fetchRepositories(with query: String) { //
obserberΛ४උ͢Δ isLoding.value = true let request = GitHubAPI.SearchRepositoriesRequest(query: query, page: 1) Session.shared.rx.send(request) .subscribe( onSuccess: { [unowned self] response in self.repositories.value += response self.isLoding.value = false }, onError: { [unowned self] (error) in self.isLoding.value = false // Τϥʔॲཧ }) .addDisposableTo(disposeBag) } } 39
View 40
class SearchRepositoryViewController: UIViewController { ... override func viewDidLoad() { super.viewDidLoad()
// UISearchBarͷೖྗΛߪಡ searchBar.rx.text.orEmpty.asDriver() .skip(1) .debounce(0.3) .distinctUntilChanged() .drive(onNext: { [unowned self] query in self.viewModel.fetchRepositories(with: query) }) .addDisposableTo(disposeBag) // ViewModelͷisLodingΛߪಡ viewModel.isLoding.asDriver() .drive(indicatorView.rx.isAnimating) .addDisposableTo(disposeBag) } } 41
MVVMͷخ͠͞ 4 σʔλ<->Viewͷಉظॲཧ͕ҰՕॴʹू͞ ΕͨࣄʹΑΓɺͲ͏͍ͬͨঢ়ଶͰͲͷΑ͏ͳৼ Δ͍Λߦ͏ͷ͔Ѳ͘͠ͳΔ 4 ViewModelදࣔʹؔ͢ΔϩδοΫ͚ͩɺUI ʹ͍ͭͯԿΒͳ͍ => ςελϏϦςΟ͕
ߴ͍ 42
3. σʔλมߋॲཧ ʹରͯ͠ෳͷ Model͕ؔ࿈͠߹͏ 43
ಥવͰ͕͢ɺ͜ͷΑ ͏ͳϢʔεέʔεΛ ߟ͑ͯΈ·͠ΐ͏ 44
45
MVVMͰ࣮ݱͯ͠ΈΔͱɺ 46
47
ͭΒΈ 4 ViewModel͕ෳͷModelΛࢀর͢Δ͜ͱʹ ͳΓɺґଘ͕ؔෳࡶʹͳΓ͏Δ 4 ͋Δఔͷنʹͳͬͯ͘Δͱʮෳͷը໘Ͱ σʔλΛڞ༗͍ͨ͠ʯʮAͷঢ়ଶΛBʹ͑ͨ ͍ʯͱ͍ͬͨΑ͏ͳʹ໘ 4 ઢෳࡶ
4 EventBus? NotificationManager? 48
ͭΒ͍ 49
Flux 50
Data in a Flux application flows in a single direction3
3 https://facebook.github.io/flux/docs/in-depth-overview.html#content 51
Flux(redux)ͷՁ 4 ୯ํͷσʔλϑϩʔΛڧ੍͢Δ 4 Single Store 52
struct CounterActionIncrease: Action {} struct CounterActionDecrease: Action {} class CounterViewController:
UIViewController, StoreSubscriber { ... @IBAction func increaseButtonTapped(sender: UIButton) { store.dispatch(CounterActionIncrease()) } 53
struct Store { // ActionʹԠͯ͡ঢ়ଶΛmutate // มߋΛdispatch(publish)͢Δ } class CounterViewController:
UIViewController, StoreSubscriber { ... // ߪಡ override func viewWillAppear(animated: Bool) { store.subscribe(self) } // storeʹมߋ͕͋ͬͨΒݺΕΔ func newState(state: AppState) { counterLabel.text = "\(state.counter)" } 54
MVC୯ํͷσʔλϑϩʔͷ ͣ ! 55
4 MVC + Observerύλʔϯ 4 Viewͷঢ়ଶͷྲྀΕΛ୯ํʹ͠ɺॲཧʹΑΔ ঢ়ଶͷมԽΛ༧ଌ͘͢͠ͳΔ 4 ͨͪͦΜͳҙਂ͘ͳ͍ɻ୯ํͷσʔλ ϑϩʔΛڧ੍͢Δͷ͕Fluxͷخ͠͞
4 View͕σʔλͷঢ়ଶΛࢹ͠ɺมߋ͋ͬͨΑ ͱ௨Λड͚औΓඳը͢͠ 4 ௨Λड͚औΓɺࠩඳը͢ΔͨΊʹ VirtualDOMͷΈΛ͍ͬͯΔ 56
Flux(redux)ͷՁ 4 ୯ํͷσʔλϑϩʔΛڧ੍͢Δ 4 Single Store 57
ݴ͍͑Εɺ Մมͳ Global Singleton 58
4 σʔλͷཧStoreʹͤɺActionͷΓ औΓʹΑͬͯͷΈσʔλΛߋ৽͢Δ 4 ετΞViewͰ͏σʔλΛڙڅ͢Δ 4 ετΞΛҰͭͷModelͱଊ͑Δ(PDSͷDͷ෦ ) 4 άϩʔόϧγϯάϧτϯ
4 ୯ҰͷετΞΛෳͷViewModelͰڞ༗ 4 ΞϓϦશମͷঢ়ଶΛѲ͍͢͠ 59
ΞϓϦશମͷঢ়ଶΛ ੍ޚԼʹ͓͚Δͷ ɺશೳײ͋Δʂ 60
ͱ͍͑ɺάϩʔόϧͳঢ়ଶม ͬͯͲ͏ͳͷʁ 4 StoreΛߋ৽Ͱ͖ΔͷStore͚ͩ 4 ΞΫγϣϯΛड͚औΓΓͷͳ͍ϝιο υΛݺͼग़͚ͩ͢ 4 ࢠͷετΞΛ࡞ׂ͢͠Δ 4
͜͜Λ୭͕ঢ়ଶΛߋ৽͢Δ͔ͳͲߏԽ͠ ͨͷ͕Redux 61
Store͕ࣗStoreΛߋ৽͢Δ 62
StoreͷߏԽ4 4 http://slides.com/jenyaterpil/redux-from-twitter-hype-to-production#/9 63
Storeͷׂํ๏ʹؔͯ͠ PDSͰ͍͏Domainͷઃܭʹͳ Δɻؤுͬͯ͜ ݸਓతʹ͜ͷྖҬϞό ΠϧͰෳࡶʹͳΒͳ͍ࣄ ͕ଟ͍ͱࢥ͏ 64
࠷ޙʹɺ ”ઃܭ”ͱ… 65
ઃܭ = ઓུ(త + ࢿݯ) 66
࠷খݶͷίετͰ྆ํຬͨ͢ͷ͕ ઃܭ ⭐ త(ചΕΔϓϩμΫτΛ࡞Δ) ⭐ ࢿݯ(࠷খݶͷϦιʔε) ઃܭɺArt(ࣗΑ͕Γͷͷ)Ͱͳ͘ Design(୭͔/Կ͔ͷͨΊʹߦ͏) 67
Conclusion 4 ͳͥઃܭ͢Δͷ͔: ෳࡶ͞Λղܾ͢ΔͨΊʹ 4 Ͳ͏ઃܭ͢Δͷ͔: ৭ʑ͋Δ(ࠓճPDSΛ հ) 4 ΞϓϦͰͲ͏ઃܭ͢Δͷ͔:
4 ඳըʹదͨ͠ϨεϙϯεΛ࡞Δ 4 σʔλ<->ViewͷಉظΛએݴతʹ(ex. MVVM/Flux) 68
De(൱ఆ)Sign(ϞϠϞϠ) ෳࡶͳͷΛ͖ͬ Γͤ͞Α͏ 69
See also ! Vue.jsͰ࣮ݱ͢ΔMVVMύλʔϯ FluxΞʔΩς Ϋνϟͱͷڑ http://techblog.reraku.co.jp/entry/ 2016/12/13/080000 ෳࡶͳJavaScriptΞϓϦέʔγϣϯʹཱ͔ͪ ͏ͨΊͷΞʔΩςΫνϟ
http://techblog.reraku.co.jp/entry/ 2017/08/08/184313 70
See also ! ϚωʔϑΥϫʔυͷઃܭͷΞϓϩʔν https://speakerdeck.com/koutalou/ manehuowadofalseshe-ji-hefalseapuroti 71