Slide 1

Slide 1 text

Declarative UI Patterns 김남현 (VCNC)

Slide 2

Slide 2 text

Declarative UI Patterns 김남현, VCNC nate@vcnc.co.kr

Slide 3

Slide 3 text

Contents 1. What is declarative UI pattern? 2. Why a declarative UI? 3. Flutter as a declarative framework 4. State management in Flutter 5. Declarative programming on other platforms 6. Wrap up

Slide 4

Slide 4 text

What is declarative UI pattern?

Slide 5

Slide 5 text

Declarative Programming ● Describes what a computation should perform ○ Not how to accomplish it ● Expresses the logic of a computation without describing its control flow Like SQL, HTML, XAML

Slide 6

Slide 6 text

Imperative Addition class Number { num n; Number(num n) { this.n = n; } add(num n) { this.n += n; } } var my = Number(5); My.add(2); print(my) var sum = (a) => (b) => a + b; print(sum (5) (2)); Declarative Addition

Slide 7

Slide 7 text

Imperative Addition class Number { num n; Number(num n) { this.n = n; } add(num n) { this.n += n; } } var my = Number(5); my.add(2); print(my) var sum = (a) => (b) => a + b; print(sum (5) (2)); Declarative Addition

Slide 8

Slide 8 text

Declarative UI Pattern Describes ● What elements you need in UI ● How they should look like

Slide 9

Slide 9 text

Declarative UI Pattern Describes ● What elements you need in UI ● How they should look like Nowadays - Separation of behavior from UI

Slide 10

Slide 10 text

var b = ViewB(...) b.setColor(red)) b.clearChildren() var c3 = ViewC(...) b.add(c3) Imperative Style Describes how to achieve what you want

Slide 11

Slide 11 text

return ViewB( color: red, child: ViewC(...), ); Declarative Style Describes what you want

Slide 12

Slide 12 text

return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: Center( child: Column(mainAxisAlignment: MainAxisAlignment.center, children: [ Text('Text1',), Text('Text2', style: Theme.of(context).textTheme.display1,), ], ), ), );

Slide 13

Slide 13 text

Why a declarative UI?

Slide 14

Slide 14 text

ViewA a ViewB b ViewC c1 ViewC c2 ViewA a ViewB b ViewC c3

Slide 15

Slide 15 text

b.setColor(red)) b.clearChildren() var c3 = ViewC(...) b.add(c3) Imperative Style ViewA a ViewB b ViewC c1 ViewC c2 ViewA a ViewB b ViewC c3

Slide 16

Slide 16 text

return ViewB( color: red, child: ViewC(...), ); Declarative Style ViewA a ViewB b ViewC c1 ViewC c2 ViewA a ViewB b ViewC c3

Slide 17

Slide 17 text

Declarative UI framework ● Lightens the burden on developers from having to program how to transition between various UI states ● Lets the developer describe the current state ● Lets the developer leaves the transitioning to the framework

Slide 18

Slide 18 text

● Takes care of the details for what exactly it takes to render elements ● Allows us to focus on the functionality of your app Declarative UI framework

Slide 19

Slide 19 text

Avocado toast https://www.self.com/recipe/hummus-avocado-toast

Slide 20

Slide 20 text

1. Prepare ingredients: avocado, bread, almond butter, sea salt, red pepper flakes. 2. Gather equipment: toaster, plate, butter knife. 3. Lightly toast a slice of bread. 4. Place toast on plate. 5. Spread thin layer of almond butter over toast 6. Cut avocado in half on its longer axis. 7. Remove avocado core. Imperative avocado toast

Slide 21

Slide 21 text

4. Place toast on plate. 5. Spread thin layer of almond butter over toast 6. Cut avocado in half on its longer axis. 7. Remove avocado core. 8. Slice single avocado half into half-centimeter slices. 9. Place avocado slices with 50% overlap over toast. 10. Apply three dashes of sea salt. 11. Apply five dashes of red pepper flakes. 12. Clean toaster and butter knife. 13. Eat avocado toast.

Slide 22

Slide 22 text

“ I’d like some avocado toast on charred sourdough with almond butter, sea salt, and red pepper flakes.” Declarative avocado toast

Slide 23

Slide 23 text

Declarative UI much less code much more predictable

Slide 24

Slide 24 text

Your App Basic features Custom features!

Slide 25

Slide 25 text

Your App Basic features Custom features!

Slide 26

Slide 26 text

● Breaking down the work process ○ Data : what drives most business applications ○ User Interface : what makes it meaningful ○ Behaviors : Being applied to enhance the experience ● Separation of these 3 components ensures maximum flexibility Flexibility

Slide 27

Slide 27 text

● Development was placed on hold until the design was completed ● Separation enables a more parallel workflow ● Development is possible having agreed upon what data is needed ○ Even if the interface hasn’t been designed yet Designer - Developer workflow

Slide 28

Slide 28 text

Flutter as a declarative framework

Slide 29

Slide 29 text

User interface in Flutter f( state ) UI

Slide 30

Slide 30 text

User interface in Flutter f( state ) UI The layout on the screen

Slide 31

Slide 31 text

User interface in Flutter f( state ) UI The layout on the screen state The application state

Slide 32

Slide 32 text

User interface in Flutter f( state ) UI The layout on the screen state The application state Your build methods

Slide 33

Slide 33 text

User interface in Flutter Everything is a widget!

Slide 34

Slide 34 text

Flutter Widgets ● Take inspiration from React ● Are the basic building blocks of App’s user interface ● Describe what their view should look like given their current configuration and state ● Immutable declaration of part of the user interface

Slide 35

Slide 35 text

Widget can define ● A structural element (like a button or menu) ● A stylistic element (like a font or color scheme) ● An aspect of layout (like padding) ● And so on...

Slide 36

Slide 36 text

Padding( padding: EdgeInsets.all(10.0), child: Text( 'Text2', style: TextStyle( fontStyle: FontStyle.italic, color: Color(0xff248f3f) ), ), ) Example

Slide 37

Slide 37 text

Composition over inheritance ● Widgets are themselves often composed of many small widgets that combine to produce powerful effects. ● Class hierarchy is shallow and broad to maximize the possible number of combinations. ● e.g. Container is made up of several widgets responsible for layout, painting, positioning, and sizing ( view sourcecode )

Slide 38

Slide 38 text

Widget build(BuildContext context) { ... if (alignment != null) current = Align(alignment: alignment, child: current); if (effectivePadding != null) current = Padding(padding: effectivePadding, child: current); if (decoration != null) current = DecoratedBox(decoration: decoration, child: current); if (constraints != null) current = ConstrainedBox(constraints: constraints, child: current); if (margin != null) current = Padding(padding: margin, child: current); if (transform != null) current = Transform(transform: transform, child: current); return current; } Container

Slide 39

Slide 39 text

Basic widgets ● Text ● AssetImage ● Row, Column ● Stack ● Container ● And so on

Slide 40

Slide 40 text

Flutter system overview

Slide 41

Slide 41 text

Rendering in Flutter ● Flutter render tree ○ Low-level layout and painting system ○ Retained tree of objects that inherit from RenderObject ○ All widgets are handled by the appropriate RenderObject

Slide 42

Slide 42 text

RenderObject ● Layout ● Painting ● Hit-testing ● Expensive to instantiate

Slide 43

Slide 43 text

RenderObject ● Layout ● Painting ● Hit-testing ● Expensive to instantiate Keep RenderObjects in memory as long as possible

Slide 44

Slide 44 text

Padding( padding: EdgeInsets.all(10.0), child: Text( 'Text2', style: TextStyle( fontStyle: FontStyle.italic, color: Color(0xff248f3f) ), ), ) Example

Slide 45

Slide 45 text

App Padding (10, 10, 10, 10) Text text2 Widget Tree

Slide 46

Slide 46 text

App Padding (10, 10, 10, 10) Text text2 AppRender PaddingRender (10, 10, 10, 10) TextRender text2 Widget Tree Render tree

Slide 47

Slide 47 text

App Padding (10, 10, 10, 10) Text text2 AppRender PaddingRender (10, 10, 10, 10) TextRender text2 Widget Tree Render tree Element Element Element Element Tree

Slide 48

Slide 48 text

Element ● For comparing the widget and the render object ● Represents the use of a widget to configure a specific location in the tree ● Keeps a reference to the related Widget, RenderObject

Slide 49

Slide 49 text

Element ● For comparing the widget and the render object ● Represents the use of a widget to configure a specific location in the tree ● Keeps a reference to the related Widget and RenderObject Flutter uses Element tree to compare the new widget tree with the already existing RenderObject tree

Slide 50

Slide 50 text

A basic rule ● Checks if the old and the new widgets are the same type ○ Just updates the RederObject’s configuration ○ Continues travelling down the tree ● Removes the widget ○ Element and RederObject form the tree (including subtrees)

Slide 51

Slide 51 text

App Padding (10, 10, 10, 10) Text text2 AppRender PaddingRender (10, 10, 10, 10) TextRender text2 Widget Tree Render tree Element Element Element Element Tree

Slide 52

Slide 52 text

App Padding (5, 5, 5, 5) Text text2 AppRender PaddingRender (10, 10, 10, 10) TextRender text2 Widget Tree Render tree Element Element Element Element Tree

Slide 53

Slide 53 text

App Padding (5, 5, 5, 5) Text text2 AppRender PaddingRender (5, 5, 5, 5) TextRender text2 Widget Tree Render tree Element Element Element Element Tree

Slide 54

Slide 54 text

App Padding (5, 5, 5, 5) Text text2 AppRender PaddingRender (5, 5, 5, 5) TextRender text2 Widget Tree Render tree Element Element Element Element Tree

Slide 55

Slide 55 text

FlatButton( child: Text("Click!"), color: Color(0xff9d4038), onPressed: () => print("ok!"), ) Example

Slide 56

Slide 56 text

App FlatButton Text Click! AppRender PaddingRender (10, 10, 10, 10) TextRender text2 Widget Tree Render tree Element Element Element Element Tree

Slide 57

Slide 57 text

App FlatButton Text Click! AppRender Widget Tree Render tree Element Element Tree

Slide 58

Slide 58 text

App FlatButton Text Click! AppRender FlatButtonRender TextRender Click! Widget Tree Render tree Element Element Element Element Tree

Slide 59

Slide 59 text

Advanced ● Keys ● Global keys ● Sublinear layout ● Sublinear widget building

Slide 60

Slide 60 text

State management in Flutter

Slide 61

Slide 61 text

The trouble with android.widgets Views own state and make their own changes Most view state changes have optional listeners

Slide 62

Slide 62 text

spinner.onItemSelectedListener = object: AdapterView.OnItemSelectedListener { override fun onNothingSelected(parent: AdapterView<*>?) { value = null } override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) { value = parent?.getItemAtPosition(position) } } The trouble with android.widget.Spinners

Slide 63

Slide 63 text

The trouble with android.widget.Spinners onSelectedItemChanged tells us when the user changed the value

Slide 64

Slide 64 text

The trouble with android.widget.Spinners onSelectedItemChanged tells us when the user changed the value .. but it happens after the value has been changed

Slide 65

Slide 65 text

The trouble with android.widget.Spinners onSelectedItemChanged tells us when the user changed the value .. but it happens after the value has been changed Now, we have to update the state afterwards

Slide 66

Slide 66 text

The trouble with UIKit Views own state and make their own changes Most views send a message by target-action pattern

Slide 67

Slide 67 text

let control = UISwitch() control.addTarget( self, action: #selector(onSwitchValueChanged(sender:)), for: .valueChanged ) @objc func onSwitchValueChanged(sender: UISwitch) { isOn = sender.isOn } The trouble with UISwitch

Slide 68

Slide 68 text

The trouble with UISwitch The selector (action) is triggered when the user changed the value

Slide 69

Slide 69 text

The trouble with UISwitch The selector (action) is triggered when the user changed the value .. but it happens after the value has been changed

Slide 70

Slide 70 text

The trouble with UISwitch The selector (action) is triggered when the user changed the value .. but it happens after the value has been changed Now, we have to update the state afterwards

Slide 71

Slide 71 text

Data flow What is the source of truth? Who owns it? Who updates it?

Slide 72

Slide 72 text

Multiple sources of truth Widget App State

Slide 73

Slide 73 text

Multiple sources of truth Widget App State

Slide 74

Slide 74 text

Multiple sources of truth Widget State App State

Slide 75

Slide 75 text

The trouble on android / iOS UI widgets have their own behavior!

Slide 76

Slide 76 text

User interface in Flutter f( state ) UI The layout on the screen state The application state Your build methods

Slide 77

Slide 77 text

Data flow in Flutter Single source of truth

Slide 78

Slide 78 text

Single source of truth Every piece of state has one owner Only the owner can make changes to state Owner listens to events and makes changes in response

Slide 79

Slide 79 text

Single source of truth

Slide 80

Slide 80 text

Screen Request Builder Vehicle Request Builder Request Monitor

Slide 81

Slide 81 text

Top-down Data Flow Screen Request Builder Vehicle Request Builder Data Request

Slide 82

Slide 82 text

Top-down Data Flow Screen Request Builder Vehicle Request Builder Data Request

Slide 83

Slide 83 text

Bottom-up Data Flow Screen Request Builder Vehicle Request Builder Event Event

Slide 84

Slide 84 text

Bottom-up Data Flow Screen Request Builder Vehicle Request Builder Event Event

Slide 85

Slide 85 text

Demo

Slide 86

Slide 86 text

Screen Request Builder Request Monitor

Slide 87

Slide 87 text

Screen Request Builder Request Monitor

Slide 88

Slide 88 text

Screen Request Builder Request Monitor Request

Slide 89

Slide 89 text

Screen Request Builder Request Monitor Request

Slide 90

Slide 90 text

Demo

Slide 91

Slide 91 text

Declarative programming on other platforms

Slide 92

Slide 92 text

React ● A JavaScript library for building user interface ● Declarative and component-based library ● Flutter’s architecture is inspired by React ○ Stateful Component & Stateless Component

Slide 93

Slide 93 text

render() { return (

TODO

What needs to be done? Add #{this.state.items.length + 1}
); }

Slide 94

Slide 94 text

Reconciliation ● The state of the art algorithms have a O(n^3) complexity ● React implements a heuristic O(n) algorithm ○ Assumptions ■ Two elements of different types will produce different trees ■ The developer can hint at which child elements may be stable across different renders with a key prop.

Slide 95

Slide 95 text

The Diffing Algorithm ● Elements of different types ○ Tears down the old tree and builds the new tree from scratch ● DOM elements of the same type ○ Looks at the attributes of both ○ Only updates the changed attributes ● Component elements of the same type ○ Updates the props of the underlying component to match the new element

Slide 96

Slide 96 text

Batching ● React batches updates inside event handlers ● Excutes all event handlers first ● Then triggers a single re-render batching all of updates together

Slide 97

Slide 97 text

Jetpack Compose ● Google introduced Jetpack compose at Google I/O 2019 ● Declarative style with annotation ● A super experimental feature

Slide 98

Slide 98 text

Google’s API Regrets ● Bundled ● Complicated ● Too many lines of code ● Multiple data flow

Slide 99

Slide 99 text

Goals ● Unbundle from platform releases ● Fewer technology stack flowcharts ● Write less lines of code ● Clarify state ownership and event handling

Slide 100

Slide 100 text

Jetpack Compose ● UI as a function ○ Takes data as input ○ Emits UI hierarchy when invoked

Slide 101

Slide 101 text

Jetpack Compose ● UI as a function ○ Takes data as input ○ Emits UI hierarchy when invoked Declarative UI pattern!

Slide 102

Slide 102 text

@Composable fun NewsFeed(stories: List) { for (story in stories) { StoryWidget(story) } } @Composable fun StoryWidget(story: StoryData) { Padding(8.dp) { Column { Title(story.title) Image(story.image) Text(story.content) } } }

Slide 103

Slide 103 text

SwiftUI ● Apple introduced SwiftUI at WWDC 2019 ● Declarative syntax ● iOS13+

Slide 104

Slide 104 text

Problems ● Multiple source of truths ● Limitation of Storyboards, Interface builder

Slide 105

Slide 105 text

View ● Protocol ○ Composition over inheritance ● Value type ● SwiftUI prefers smaller and single-purposed Views

Slide 106

Slide 106 text

SwiftUI ● Declares View with Modifier Text(name) .font(.caption) .foregroundColor(.blue) ● SwiftUI optimizes the process down behind the scenes.

Slide 107

Slide 107 text

VStack { Text("Hi") .font(.system(size: 15)) .foregroundColor(.red) Text(name) .font(.caption) .foregroundColor(.blue) Button(action: { self.isPlaying.toggle() }) { HStack { Image(systemName: "pause.circel") Text("play") } } }

Slide 108

Slide 108 text

Wrap up

Slide 109

Slide 109 text

return ViewB( color: red, child: ViewC(...), ); Declarative UI pattern

Slide 110

Slide 110 text

Why a declarative UI? ● Less lines of code ● Predictability ● Efficient workflow ● Flexibility

Slide 111

Slide 111 text

Flutter as a declarative framework ● UI = f( state ) ● Widget ● Widget tree ● Element tree ● Render tree

Slide 112

Slide 112 text

State management in Flutter ● Dataflow ● Single source of truth ● ChangeNotifierProvider

Slide 113

Slide 113 text

Declarative programming on other platforms ● React ● Jetpack Compose ● SwiftUI

Slide 114

Slide 114 text

No content