Designable Archetecture

3925ee6eaa41031bac799de0f4f528ec?s=47 to4iki
October 17, 2017

Designable Archetecture

WIP

3925ee6eaa41031bac799de0f4f528ec?s=128

to4iki

October 17, 2017
Tweet

Transcript

  1. Designable Architecture Shinjuku.LT#13 @to4iki 1

  2. Profile 4 @to4iki 4 iOS Developer ! 2

  3. Agenda 4 Կނઃܭ͢Δͷ͔ 4 Ͳ͏ઃܭ͢΂͖͔ 4 ϞόΠϧʹ͓͚Δઃܭ 3

  4. Կނઃܭ͢Δͷ͔ 4

  5. ୯७ͳΞϓϦέʔγϣϯ 4 શମ૾͕೺Ѳ͠΍͍͢ 4 1ਓͰಇ͘ͳΒɺԿΛߦ͏ͷ͔௚͙ʹ೺ѲͰ͖ Δ 5

  6. ෳࡶͳΞϓϦέʔγϣϯ 4 શମ૾͕Ұ౓ʹ͸೺Ѳͣ͠Β͍ 4 େ੎Ͱಇ͘ͳΒɺ୭͔͕ԿΛ͍ͯ͠Δͷ͔೺Ѳ ͮ͠Β͍ 6

  7. ෳࡶͳ֓೦Λ ෼ׂͯ͠؅ཧ͍ͨ͠ 7

  8. ෳࡶͳ֓೦ͷ෼ׂ 4 ը໘͝ͱ? 4 ػೳ͝ͱ? 4 ෼ׂͷ࢓ํ͸༷ʑͰɺ͜ΕΛܾΊΔͷ͕ઃܭ 8

  9. ιϑτ(มߋ͕؆୯ͳ)΢ΣΞ(੡඼) ϋʔυ(มߋ͕೉͍͠)΢ΣΞ(੡඼) 9

  10. ιϑτ΢ΣΞ͸ "มߋ͕؆୯ʹͰ͖Δ" Α͏ʹ࡞Βͳ͚Ε͹ͳΒͳ͍ 10

  11. ͳͥઃܭ͢Δͷ͔ ؆୯ʹιϑτ΢ΣΞ ΛมߋͰ͖ΔΑ͏ɺ ෳࡶͳ֓೦Λ෼ׂ͠ ͍ͨ 11

  12. Ͳ͏ઃܭ͢΂͖͔ 12

  13. Presentation Domain Separation(PDS)1 4 UIʹؔΘΔ΋ͷͱɺͦΕҎ֎ͱͰ෼ׂ͠Α͏ 4 ͦΕҎ֎ = ڊେͳModelͱͯ͠੾Γग़͢ 1

    https://martinfowler.com/bliki/PresentationDomainSeparation.html 13
  14. PDSͷϝϦοτ 4 PresentationϩδοΫͱDomainϩδοΫ͕ ෼͔Ε͍ͯΔͱɺཧղ͠΍͍͢ 4 View͸෼͔Γ΍͍͢(HTML, JSON, ViewController) 4 UI͸ςετ͕͠ʹ͍ͨ͘ΊɺͦΕΛ෼཭͢Δࣄ

    ͰςετՄೳͳϩδοΫ෦෼ʹूதͰ͖Δ 14
  15. PDSΛͲ͏࣮ݱ͢Δ͔ 15

  16. ࣮ݱํ๏ 4 MVW 4 MVC 4 MVP 4 MVVM 4

    CleanArchitecture 4 Flux 4 etc 16
  17. ৭ʑ͋Δ 17

  18. ϞόΠϧͷจ຺Ͱߟ͑ͯΈΔ = ϞόΠϧʹ͓͚Δઃܭ 18

  19. બ୒͢Δʹ͋ͨͬ ͯ......Ͳ͏͍ͬͨ՝ ୊͕͋Δ͔Λ෼ੳ͢ Δ 19

  20. ϞόΠϧ։ൃͷ՝୊(೉͍͠ ॴ) 1. APIͷϨεϙϯεΛͲͷΑ͏ʹViewʹ൓ө͢Δ ͔ 2. ෳࡶʹՄม͠͏Δσʔλͷঢ়ଶΛͲͷΑ͏ʹ Viewʹ൓ө͢Δ͔ 3. 1ͭͷσʔλมߋॲཧʹରͯ͠ෳ਺ͷModel͕

    ؔ࿈͠߹͏ͷΛͲ͏؅ཧ͢Δ͔ 20
  21. ͜ΕΒͷ໰୊Λղܾ ͢Δઃܭύλʔϯ͕ ཉ͍͠ʂ 21

  22. 1. APIͷϨεϙϯε ΛͲͷΑ͏ʹViewʹ ൓ө͢Δ͔ 22

  23. ex. Α͋͘Δ࣮૷ 4 RESTͷAPIͰ͋Ε͹Ϧιʔε୯ҐͰϨεϙϯ εʹ֘౰͢ΔΦϒδΣΫτΛ࡞੒ 4 ෳ਺ͷϦιʔεΛجʹը໘Λߏ੒͢ΔͷͰ͋Ε ͹ɺͦΕΒΛݸผʹϦΫΤετ͠ඳը͢Δ 4 ඳը༻ͷModelʹม׵͢Δʁ

    4 ͲͷϨΠϠʔͰߦ͏ʁͲͷΫϥε͕ͦΕΛ ߦ͏ʁ 23
  24. 24

  25. ͭΒ͍ 25

  26. ը໘୯ҐͷϨεϙϯεͩͬͨΒ ࡉ͔͍ࣄߟ͑ͳͯ͘ࡁΉͷͰ͸ 26

  27. 27

  28. ཧ૝ܗ 4 Read͕ϝΠϯͷΞϓϦͰ͋Ε͹ɺσʔλΛͦ ͷ··Viewʹ൓ө͢Δ͚ͩͰΑ͍͸ͣ 4 APIଆͰ࠷దͳσʔλߏ଄Ͱฦ͢ඞཁ͕͋Δ 4 ΋͘͠͸ΫϥΠΞϯτͰฒྻͰϦΫΤετ Λ౤͛ϖʔδ৘ใͱͯ͠੔ܗ͢Δ 28

  29. 29

  30. ཧ૝ܗ 4 σʔλͷ࣋ͪํʹؔͯ͠͸ϨεϙϯεΛϖʔδ ৘ใʹ࠷దԽͰ͖Ε͹ɺෳࡶͳ੹຿෼཭͸ෆཁ ʹͳΔ 4 Write͕ʹؔͯ͠͸ϑΥʔϜModelΛͲͷΑ͏ ʹͯ͠ӬଓԽ༻ͷModelʹม׵͢ΔʁReadͷ Modelͱಉ͡ߏ଄ʹ͢Δ?RͱWͷಉظ͸?ͳͲ ߟ͑Δ͜ͱ͕ଟ͍

    => ex. CQRS(ࠓճ͸۷ΓԼ͛ͳ͍ɺษڧ͠· 30
  31. 2. ෳࡶʹՄม͠͏ Δσʔλͷঢ়ଶΛͲ ͷΑ͏ʹViewʹ൓ө ͢Δ͔ 31

  32. ex. Α͋͘Δ࣮૷ 4 खಈͰViewͷঢ়ଶͱσʔλΛಉظ͢Δ 4 ಉظͷॲཧ͕ࢄΒ͹Γɺ͍ͭͲ͜ͰԿ͕Ͳ ͏มΘΔͷ͔͕༧ଌͮ͠Β͍ 4 DelegateύλʔϯʹΑΔ࣮૷ͩͱɺͲͷλΠ ϛϯάͰ࣮ߦ͞ΕΔͷ͔ͳͲ͕ݺͼग़͠ଆͱ࣮

    ߦଆͰίʔυͷ෺ཧతͳڑ཭͕཭Ε͓ͯΓɺ೺ Ѳ͢Δͷʹ͕͔͔࣌ؒΔ 32
  33. ͭΒ͍ 33

  34. MVVM 34

  35. 35

  36. MVVM2 4 ViewModel͸ViewͷͨΊͷঢ়ଶετΞ 4 View͸ViewModelʹґଘ͠ɺViewModel͸ Modelʹґଘ͢Δ(୯ํ޲ͷґଘ) 4 View͸Ϣʔβʔ͔ΒͷΞΫγϣϯΛड͚ͯɺ ͦͷΠϕϯτΛViewModelʹbind͢Δɻͦ͠ ͯͦͷbind͞ΕͨΠϕϯτʹΑͬͯ

    2 https://speakerdeck.com/koutalou/manehuowadofalseshe-ji-hefalseapuroti 36
  37. 37

  38. ViewModel 38

  39. 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
  40. View 40

  41. 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
  42. MVVMͷخ͠͞ 4 σʔλ<->Viewͷಉظॲཧ͕ҰՕॴʹू໿͞ ΕͨࣄʹΑΓɺͲ͏͍ͬͨঢ়ଶͰͲͷΑ͏ͳৼ Δ෣͍Λߦ͏ͷ͔೺Ѳ͠΍͘ͳΔ 4 ViewModel͸දࣔʹؔ͢ΔϩδοΫ͚ͩɺUI ʹ͍ͭͯ͸Կ΋஌Βͳ͍ => ςελϏϦςΟ͕

    ߴ͍ 42
  43. 3. σʔλมߋॲཧ ʹରͯ͠ෳ਺ͷ Model͕ؔ࿈͠߹͏ 43

  44. ಥવͰ͕͢ɺ͜ͷΑ ͏ͳϢʔεέʔεΛ ߟ͑ͯΈ·͠ΐ͏ 44

  45. 45

  46. MVVMͰ࣮ݱͯ͠ΈΔͱɺ 46

  47. 47

  48. ͭΒΈ 4 ViewModel͕ෳ਺ͷModelΛࢀর͢Δ͜ͱʹ ͳΓɺґଘؔ܎͕ෳࡶʹͳΓ͏Δ 4 ͋Δఔ౓ͷن໛ʹͳͬͯ͘Δͱʮෳ਺ͷը໘Ͱ σʔλΛڞ༗͍ͨ͠ʯʮAͷঢ়ଶΛBʹ఻͑ͨ ͍ʯͱ͍ͬͨΑ͏ͳ໰୊ʹ௚໘ 4 ഑ઢෳࡶ໰୊

    4 EventBus? NotificationManager? 48
  49. ͭΒ͍ 49

  50. Flux 50

  51. Data in a Flux application flows in a single direction3

    3 https://facebook.github.io/flux/docs/in-depth-overview.html#content 51
  52. Flux(redux)ͷՁ஋ 4 ୯ํ޲ͷσʔλϑϩʔΛڧ੍͢Δ 4 Single Store 52

  53. struct CounterActionIncrease: Action {} struct CounterActionDecrease: Action {} class CounterViewController:

    UIViewController, StoreSubscriber { ... @IBAction func increaseButtonTapped(sender: UIButton) { store.dispatch(CounterActionIncrease()) } 53
  54. 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
  55. MVC΋୯ํ޲ͷσʔλϑϩʔͷ ͸ͣ ! 55

  56. 4 MVC + Observerύλʔϯ 4 Viewͷঢ়ଶͷྲྀΕΛ୯ํ޲ʹ͠ɺॲཧʹΑΔ ঢ়ଶͷมԽΛ༧ଌ͠΍͘͢ͳΔ 4 ๻ͨͪ͸ͦΜͳ஫ҙਂ͘ͳ͍ɻ୯ํ޲ͷσʔλ ϑϩʔΛڧ੍͢Δͷ͕Fluxͷخ͠͞

    4 View͕σʔλͷঢ়ଶΛ؂ࢹ͠ɺมߋ͋ͬͨΑ ͱ௨஌Λड͚औΓඳը͠௚͢ 4 ௨஌Λड͚औΓɺࠩ෼ඳը͢ΔͨΊʹ VirtualDOMͷ࢓૊ΈΛ࢖͍ͬͯΔ 56
  57. Flux(redux)ͷՁ஋ 4 ୯ํ޲ͷσʔλϑϩʔΛڧ੍͢Δ 4 Single Store 57

  58. ݴ͍׵͑Ε͹ɺ Մมͳ Global Singleton 58

  59. 4 σʔλͷ؅ཧ͸Storeʹ೚ͤɺActionͷ΍Γ औΓʹΑͬͯͷΈσʔλΛߋ৽͢Δ 4 ετΞ͸ViewͰ࢖͏σʔλΛڙڅ͢Δ 4 ετΞΛҰͭͷModelͱଊ͑Δ(PDSͷDͷ෦ ෼) 4 άϩʔόϧγϯάϧτϯ

    4 ୯ҰͷετΞΛෳ਺ͷViewModelͰڞ༗ 4 ΞϓϦશମͷঢ়ଶΛ೺Ѳ͠΍͍͢ 59
  60. ΞϓϦશମͷঢ়ଶΛ ੍ޚԼʹ͓͚Δͷ ͸ɺશೳײ͋Δʂ 60

  61. ͱ͸͍͑ɺάϩʔόϧͳঢ়ଶม ਺ͬͯͲ͏ͳͷʁ 4 StoreΛߋ৽Ͱ͖Δͷ͸Store͚ͩ 4 ΞΫγϣϯΛड͚औΓ໭Γ஋ͷͳ͍ϝιο υΛݺͼग़͚ͩ͢ 4 ࢠͷετΞΛ࡞੒͠෼ׂ͢Δ 4

    ͜͜Λ୭͕ঢ়ଶΛߋ৽͢Δ͔ͳͲߏ଄Խ͠ ͨͷ͕Redux 61
  62. Storeࣗ਎͕StoreΛߋ৽͢Δ 62

  63. Storeͷߏ଄Խ4 4 http://slides.com/jenyaterpil/redux-from-twitter-hype-to-production#/9 63

  64. Storeͷ෼ׂํ๏ʹؔͯ͠͸ PDSͰ͍͏Domainͷઃܭʹͳ Δɻؤுͬͯ͜ ݸਓతʹ͸͜ͷྖҬ͸Ϟό ΠϧͰ͸ෳࡶʹͳΒͳ͍ࣄ ͕ଟ͍ͱࢥ͏ 64

  65. ࠷ޙʹɺ ”ઃܭ”ͱ͸… 65

  66. ઃܭ = ઓུ(໨త + ࢿݯ) 66

  67. ࠷খݶͷίετͰ྆ํຬͨ͢ͷ͕ ઃܭ ⭐ ໨త(ചΕΔϓϩμΫτΛ࡞Δ) ⭐ ࢿݯ(࠷খݶͷϦιʔε) ઃܭ͸ɺArt(ࣗ෼Α͕Γͷ΋ͷ)Ͱ͸ͳ͘ Design(୭͔/Կ͔ͷͨΊʹߦ͏) 67

  68. Conclusion 4 ͳͥઃܭ͢Δͷ͔: ෳࡶ͞Λղܾ͢ΔͨΊʹ 4 Ͳ͏ઃܭ͢Δͷ͔: ৭ʑ͋Δ(ࠓճ͸PDSΛ঺ հ) 4 ΞϓϦͰ͸Ͳ͏ઃܭ͢Δͷ͔:

    4 ඳըʹదͨ͠ϨεϙϯεΛ࡞Δ 4 σʔλ<->ViewͷಉظΛએݴతʹ(ex. MVVM/Flux) 68
  69. De(൱ఆ)Sign(ϞϠϞϠ) ෳࡶͳ΋ͷΛ͸͖ͬ Γͤ͞Α͏ 69

  70. 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
  71. See also ! ϚωʔϑΥϫʔυͷઃܭ΁ͷΞϓϩʔν https://speakerdeck.com/koutalou/ manehuowadofalseshe-ji-hefalseapuroti 71