Slide 1

Slide 1 text

࣮ફత BOUNDARIES IN PRACTICE TRY! SWIFT 2016

Slide 2

Slide 2 text

HI, I’M AYAKA. A.K.A. ࠼Ֆ @AYANONAGON

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

FUNCTIONAL CORE IMPERATIVE SHELL

Slide 5

Slide 5 text

FUNCTIONAL CORE

Slide 6

Slide 6 text

APP = MANY FUNCTIONAL CORES

Slide 7

Slide 7 text

WITH IMPERATIVE SHELLS

Slide 8

Slide 8 text

“ALL YOU REALLY KNOW MAYBE IS THAT YOUR TASTE IS IMPROVING A LOT FASTER THAN YOUR ABILITY.” ANDY MATUSCHAK, ADVANCED IOS APPLICATION ARCHITECTURE AND PATTERNS (WWDC 2014)

Slide 9

Slide 9 text

࣮ફత BOUNDARIES IN PRACTICE TRY! SWIFT 2016

Slide 10

Slide 10 text

ୈҰ IMMUTABLE CORE NETWORK-Y SHELL ෆมͳਊɺωοτϫʔΫͬΆ͍ද໘

Slide 11

Slide 11 text

No content

Slide 12

Slide 12 text

No content

Slide 13

Slide 13 text

struct Story { let ID: String let title: String let message: String let sender: User let recipient: User let date: NSDate // ... }

Slide 14

Slide 14 text

class StoriesViewController: UIViewController { let stories: [Story] // ... }

Slide 15

Slide 15 text

class StoryDetailViewController: UIViewController { init(story: Story) }

Slide 16

Slide 16 text

class StoryDetailViewController: UIViewController { private let titleView: StoryTitleView private let senderView: AvatarView private let recipientView: AvatarView private let dateLabel: DateLabel init(story: Story) { titleView = StoryTitleView(story: story) senderView = AvatarView(user: story.sender) recipientView = AvatarView(user: story.recipient) dateLabel = DateLabel(date: story.date) } // ... }

Slide 17

Slide 17 text

url_scheme://stories/12345

Slide 18

Slide 18 text

class StoryDetailViewController: UIViewController { init(story: Story) }

Slide 19

Slide 19 text

class StoryDetailViewController: UIViewController { init(story: Story) init(storyID: String) }

Slide 20

Slide 20 text

class StoryDetailViewController: UIViewController { private let titleView: StoryTitleView private let senderView: AvatarView private let recipientView: AvatarView private let dateLabel: DateLabel init(story: Story) { /* Same as before લͱಉ͡ */ } init(storyID: String) { // Hmmmmmmm.ɹ͜ΕԿͩΖ͏ʁ } }

Slide 21

Slide 21 text

class StoryDetailViewController: UIViewController { let storyID: String private var titleView: StoryTitleView? private var senderView: AvatarView? private var recipientView: AvatarView? private var dateLabel: DateLabel? init(story: Story) { /* Same as before લͱಉ͡ */ } init(storyID: String) { self.storyID = storyID titleView = nil senderView = nil recipientView = nil dataLabel = nil } // Load everything from API in viewDidLoad? // viewDidLoadͰAPI͔Βϩʔυʁ!ɹ }

Slide 22

Slide 22 text

class StoryContainerViewController: UIViewController { let storyID: String init(storyID: String) { self.storyID = storyID } override func viewDidLoad() { client.showStory(ID: storyID) { result in switch result { case .Success(let story): let viewController = StoryDetailViewController(story: story) self.addChildViewController(viewController) self.view.addSubview(viewController.view) viewController.view.frame = view.bounds viewController.didMoveToParentViewController(self) case .Error(let error): // Show errorɹΤϥʔදࣔ } } } }

Slide 23

Slide 23 text

url_scheme://stories/12345 StoryContainerViewController(storyID: "12345")

Slide 24

Slide 24 text

url_scheme://stories/12345

Slide 25

Slide 25 text

url_scheme://stories/12345 url_scheme://users/007

Slide 26

Slide 26 text

url_scheme://stories/12345 url_scheme://users/007 url_scheme://messages/9876

Slide 27

Slide 27 text

protocol RemoteContentProviding { typealias Content func fetchContent(completion: Result -> Void) func viewControllerForContent(content: Result) -> UIViewController }

Slide 28

Slide 28 text

class RemoteContentContainerViewController: UIViewController { let provider: T init(provider: T) { self.remoteContentProvider = remoteContentProvider super.init(nibName: nil, bundle: nil) } override func viewDidLoad() { super.viewDidLoad() provider.fetchContent { content in let viewController = self.provider.viewControllerForContent(content) self.addChildViewController(viewController) self.view.addSubview(viewController.view) viewController.view.frame = view.bounds viewController.didMoveToParentViewController(self) } } }

Slide 29

Slide 29 text

struct StoryProvider: RemoteContentProviding { let ID: String func fetchContent(completion: Result -> Void) { client.showStory(ID: ID, completion: completion) } func viewControllerForContent(content: Result) -> UIViewController { switch content { case .Success(let story): return StoryDetailViewController(story: story) case .Error(_): return ErrorViewController(title: "Could not find story.") } } }

Slide 30

Slide 30 text

url_scheme://stories/12345 let provider = StoryProvider(ID: "12345") RemoteContentContainerViewController(provider: provider)

Slide 31

Slide 31 text

url_scheme://users/007 let provider = UserProvider(ID: "007") RemoteContentContainerViewController(provider: provider)

Slide 32

Slide 32 text

url_scheme://messages/9876 let provider = MessageProvider(ID: "9876") RemoteContentContainerViewController(provider: provider)

Slide 33

Slide 33 text

class StoryDetailViewController: UIViewController { let storyID: String private var titleView: StoryTitleView? private var senderView: AvatarView? private var recipientView: AvatarView? private var dateLabel: DateLabel? init(story: Story) { /* Same as before */ } init(storyID: String) { self.storyID = storyID titleView = nil senderView = nil recipientView = nil dataLabel = nil } // Load everything from API in viewDidLoad? // viewDidLoadͰAPI͔Βϩʔυʁ! }

Slide 34

Slide 34 text

No content

Slide 35

Slide 35 text

class StoryDetailViewController: UIViewController { private let titleView: StoryTitleView private let senderView: AvatarView private let recipientView: AvatarView private let dateLabel: DateLabel init(story: Story) { titleView = StoryTitleView(story: story) senderView = AvatarView(user: story.sender) recipientView = AvatarView(user: story.recipient) dateLabel = DateLabel(date: story.date) } // ... }

Slide 36

Slide 36 text

No content

Slide 37

Slide 37 text

ୈೋ INDEPENDENT CORES CONNECTIVE SHELL ಠཱͨ͠ਊͱܨ͛Δද໘

Slide 38

Slide 38 text

No content

Slide 39

Slide 39 text

COORDINATORS SOROUSH KHANLOU @ NSSPAIN

Slide 40

Slide 40 text

VIEW CONTROLLERS DON’T KNOW ABOUT OTHER VIEW CONTROLLERS

Slide 41

Slide 41 text

@UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? private lazy var applicationCoordinator: ApplicationCoordinator = { return ApplicationCoordinator(window: self.window!) }() func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { window = UIWindow(frame: UIScreen.mainScreen().bounds) applicationCoordinator.start() return true } }

Slide 42

Slide 42 text

protocol Coordinator { func start() }

Slide 43

Slide 43 text

class ApplicationCoordinator: Coordinator { let window: UIWindow let rootViewController = UITabBarController() let wordsNavigationController = UINavigationController() let phrasesNavigationController = UINavigationController() let wordsCoordinator: WordsCoordinator let phrasesCoordinator: PhrasesCoordinator init(window: UIWindow) { self.window = window let viewControllers = [wordsNavigationController, phrasesNavigationController] self.rootViewController.setViewControllers(viewControllers, animated: false) self.wordsCoordinator = WordsCoordinator(presenter: wordsNavigationController) self.phrasesCoordinator = PhrasesCoordinator(presenter: phrasesNavigationController) } func start() { window.rootViewController = rootViewController wordsCoordinator.start() phrasesCoordinator.start() window.makeKeyAndVisible() } }

Slide 44

Slide 44 text

class WordsCoordinator: Coordinator { let presenter: UINavigationController private let listViewController: ListViewController private let dataSource: WordsDataSource init(presenter: UINavigationController) { self.presenter = presenter self.dataSource = WordsDataSource() self.listViewController = ListViewController() self.listViewController.title = "Words" self.listViewController.items = dataSource.words self.listViewController.configureCell = { cell, item in cell.item = item } self.listViewController.didSelectItem = { item in presenter.pushViewController(WordViewController(word: item), animated: true) } } func start() { presenter.pushViewController(listViewController, animated: false) } }

Slide 45

Slide 45 text

class PhrasesCoordinator: Coordinator { let presenter: UINavigationController private let listViewController: ListViewController private let dataSource: PhrasesDataSource init(presenter: UINavigationController) { self.presenter = presenter self.dataSource = PhrasesDataSource() self.listViewController = ListViewController() self.listViewController.title = "Phrases" self.listViewController.items = dataSource.phrases self.listViewController.configureCell = { cell, item in cell.item = item } self.listViewController.didSelectItem = { item in presenter.pushViewController(PhraseViewController(phrase: item), animated: true) } } func start() { presenter.pushViewController(listViewController, animated: false) } }

Slide 46

Slide 46 text

ApplicationCoordinator / \ WordsCoordinator PhrasesCoordinator

Slide 47

Slide 47 text

ApplicationCoordinator / \ WordsCoordinator PhrasesCoordinator / SearchCoordinator

Slide 48

Slide 48 text

ApplicationCoordinator / \ DictionaryCoordinator LoginCoordinator / \ WordsCoordinator PhrasesCoordinator / SearchCoordinator

Slide 49

Slide 49 text

ApplicationCoordinator / \ \ DictionaryCoordinator LoginCoordinator SignUpCoordinator / \ WordsCoordinator PhrasesCoordinator / SearchCoordinator

Slide 50

Slide 50 text

No content

Slide 51

Slide 51 text

No content

Slide 52

Slide 52 text

ந৅Խ ABSTRACTION

Slide 53

Slide 53 text

ݎ࣮ SOLID

Slide 54

Slide 54 text

ྲྀಈత FLUID

Slide 55

Slide 55 text

ྲྀಈత 㲗 ݎ࣮ FLUID 㲗 SOLID

Slide 56

Slide 56 text

কདྷੑ FUTURE PROOF

Slide 57

Slide 57 text

THANK YOU ͋Γ͕ͱ͏ʂ

Slide 58

Slide 58 text

No content