Slide 1

Slide 1 text

REVISITED Storyboards @paulstringer | Head of Mobile, Equal Experts.

Slide 2

Slide 2 text

–Johnny Appleseed “A storyboard file captures your entire user interface in one place and lets you define both the individual view controllers and the transitions between those view controllers. As a result, storyboards capture the flow of your overall user interface in addition to the content you present.”

Slide 3

Slide 3 text

“Metaprogramming” Put abstractions in code, details in metadata

Slide 4

Slide 4 text

– The Pragmatic Programmer, Andy Hunt, David Thomas. “You may be able to implement several different projects using the same application engine, but with different metadata.”

Slide 5

Slide 5 text

Storyboards • Far less boiler-plate code to read, write, maintain • Powerful tool for creating and previewing layout • Quickly visualise the flow of the User Interface • Expressed in a way that’s closest to the domain

Slide 6

Slide 6 text

No content

Slide 7

Slide 7 text

No content

Slide 8

Slide 8 text

No content

Slide 9

Slide 9 text

Why?

Slide 10

Slide 10 text

The ‘Segwayue’ Problem override func prepare(for segue: UIStoryboardSegue, sender: Any?) { switch segue.identifier! { case "showDetail": let editorViewController = segue.destination as! DetailViewController ... break; default: break; } }

Slide 11

Slide 11 text

The ‘Segue’ Problem • ‘String-Typing' identifier based code • View Controller code dependant on Storyboards • View Controllers dependant on other View Controllers • Lots of Switch statements

Slide 12

Slide 12 text

Nonorthogonal Design Changes in our Storyboard Require Changes in our View Controllers

Slide 13

Slide 13 text

–The Pragmatic Progammer, Metaprogramming, Andy Hunt, David Thomas. “Our goal is to think declaratively (specifying what is to be done, not how) and to create highly dynamic and adaptable programs. - We do this by programming for the general case and put the specifics somewhere else”

Slide 14

Slide 14 text

Highly Dynamic and Adaptable • Generalise handling of Segue code • Remove Switch statements • Move specifics outside of View Controllers • Make Storyboards ‘Orthogonal’ to the code

Slide 15

Slide 15 text

ViewController ViewController prepare(for segue: sender:) Strongly Coupled View Controllers Configuring Destination View Controllers

Slide 16

Slide 16 text

override func prepare(for segue: UIStoryboardSegue, sender: Any?) { let destination = segue.destination as! DetailViewController let object = objectForRowAtSelectedIndexPath() destination.model = DetailViewModel(name: object.name) } private func objectForRowAtSelectedIndexPath() -> DetailEntityObject { … } Strongly Coupled View Controllers Configuring Destination View Controllers

Slide 17

Slide 17 text

Strongly Coupled View Controllers ViewController DetailViewModel DetailEntityObject Source Destination Configuring Destination View Controllers

Slide 18

Slide 18 text

Configuring Destination View Controllers Strongly Coupled View Controllers ViewController ViewController DetailViewModel DetailEntityObject Source Destination

Slide 19

Slide 19 text

–David Wheeler “All problems in computer science can be solved by another level of indirection… …except for the problem of too many levels of indirection”

Slide 20

Slide 20 text

Configuring Destination View Controllers Strongly Coupled View Controllers ViewController ViewController DetailViewModel DetailEntityObject Source Destination

Slide 21

Slide 21 text

Decoupling View Controllers ViewController ViewController ViewModel EntityObject ? Source Destination Configuring Destination View Controllers

Slide 22

Slide 22 text

Highly Dynamic and Adaptable 1. Introduce a new ‘intermediary’ to coordinate segues 2. Move responsibility for prepare(for segue:) to the intermediary 3. Determine the correct code path to prepare for the destination 4. Without String-Typing, Switch Statements, Forced Casts!

Slide 23

Slide 23 text

Orthogonal Design Changes in our Storyboard Should Not Require Changes in Code

Slide 24

Slide 24 text

Meet Crusty Don’t call him “Jerome” Call Crusty! WWDC Protocol-Oriented Programming

Slide 25

Slide 25 text

Design Patterns, Elements of Reusable Object-Orientated Software Gamma, Helm,Johnson, Vlissides “Visitor pattern lets you add operations to classes without changing them. Visitor achieves this by using a technique called double-dispatch. “The operation that gets executed depends on both the type of Visitor and the type of Element it visits.” The Visitor Pattern

Slide 26

Slide 26 text

No content

Slide 27

Slide 27 text

No content

Slide 28

Slide 28 text

No content

Slide 29

Slide 29 text

Refactoring Segues ChooseBeverageViewController OrderSummaryViewController

Slide 30

Slide 30 text

class ChooseBeverageViewController: UIViewController { override func prepare(for segue: UIStoryboardSegue, sender: Any?) { // Prepare OrderSummaryViewController ... } … } Refactoring Segues Move Responsibility for prepare(for segue:)

Slide 31

Slide 31 text

class ChooseBeverageViewController: StoryboardViewController { … } class StoryboardViewController { var sceneVisitor: StoryboardSceneVisitor? override func prepare(for segue: UIStoryboardSegue, sender: Any?) { sceneVisitor?.prepare(for: segue) } } Refactoring Segues Delegate Segue Responsibilities to the Visitor

Slide 32

Slide 32 text

struct StoryboardSceneVisitor { func prepare(for segue: UIStoryboardSegue) { guard let destination = segue.destination as? StoryboardVisitableScene else { return } destination.accept(visitor: self) } } Refactoring Segues Dispatching the Visitor to the Destination public protocol StoryboardVisitableScene { func accept(visitor: StoryboardSceneVisitor) }

Slide 33

Slide 33 text

extension OrderSummaryViewController: StoryboardVisitableScene { func accept(visitor: StoryboardSceneVisitor) { visitor.visit(self) } } Refactoring Segues Add conformance to destination View Controller and extend Visitor extension StoryboardSceneVisitor { func visit(_ scene: OrderSummaryViewController) { // Prepare OrderSummaryViewController ... } }

Slide 34

Slide 34 text

Demo Github - github.com/paulstringer/storyboardsrevisited"

Slide 35

Slide 35 text

Orthogonal Design • Using Storyboards we remain close to the domain • Metaprogramming suggested we move details outside of code • Using classic Design Patterns we added flexibility to our code • Changes in Storyboards don’t require changes in our code

Slide 36

Slide 36 text

–The Pragmatic Programmer “If we were using the same kind of tools that produced the basic dumb-terminal applications 20 years ago, we’d never get anything done.”

Slide 37

Slide 37 text

Storyboards Revisited More Information: @paulstringer paulstringer/storyboardsrevisited equalexperts.com