FRONTEND AT SCALE Designing abstractions for big teams @joshduck - - PowerPoint PPT Presentation

frontend at scale
SMART_READER_LITE
LIVE PREVIEW

FRONTEND AT SCALE Designing abstractions for big teams @joshduck - - PowerPoint PPT Presentation

FRONTEND AT SCALE Designing abstractions for big teams @joshduck What front-end abstractions have we built? And how did we do it? Server rendered desktop site Less memory, bandwidth, and latency Device constraints More products Multiple


slide-1
SLIDE 1

FRONTEND AT SCALE

Designing abstractions for big teams @joshduck

slide-2
SLIDE 2

What front-end abstractions have we built? And how did we do it?

slide-3
SLIDE 3

Server rendered desktop site

slide-4
SLIDE 4
slide-5
SLIDE 5
slide-6
SLIDE 6

Less memory, bandwidth, and latency

slide-7
SLIDE 7
slide-8
SLIDE 8

Device constraints × More products × Multiple platforms × Product depth Lots of complexity

slide-9
SLIDE 9

Hardware Data storage Web framework UI rendering Business logic Runtimes

Common infrastructure

Product UI

Product code

slide-10
SLIDE 10

Common infrastructure

Products teams can focus on products We can chase long tail of optimizations Knowledge is transferable Shared tooling and processes

slide-11
SLIDE 11

The right solution changes over time

slide-12
SLIDE 12

Specialize

slide-13
SLIDE 13

Specialize Simplify

slide-14
SLIDE 14

Simplify Specialize Replace

slide-15
SLIDE 15
slide-16
SLIDE 16

Turn data into markup Strings and concatenation Goal: Medium:

Server rendering

slide-17
SLIDE 17

String escaping Cross-site scripting HTML syntax HTML tags

echo "<div class=\"dashboard-box\"> 
 Hello, $name. 
 </div>";


slide-18
SLIDE 18
slide-19
SLIDE 19

$welcome = new UIDashboard(); 
 $welcome->setTitle('Hello, ' . $name); 
 $welcome->setIcon('event'); 
 $welcome->setContent($body); 
 echo $welcome->render();

Object composition is better than string concatenation

slide-20
SLIDE 20

$welcome = 
 <dashboard title={"Hello, $name"}> 
 {$body} 
 <button use="primary" /> 
 </dashboard>; 
 


XHP is a DSL for components

slide-21
SLIDE 21

$welcome = 
 <dashboard title={"Hello, $name"}> 
 {$body} 
 <button use="primary" /> 
 </dashboard>; 
 


XHP is a DSL for components

slide-22
SLIDE 22

class :dashboard { 
 function render() { 
 return 
 <card> 
 <icon type={$this->icon} /> 
 <div>{$this->:title}</div> 
 </card>; 
 } 
 }

It's XHP all the way down 🐣

slide-23
SLIDE 23

Components are a massive win for code quality

They encourage engineers to create decoupled, reusable units of code

slide-24
SLIDE 24

The pit of success

slide-25
SLIDE 25

class :dashboard implements AsyncXHP { 
 async function render() { 
 $text = await getDashboard($this->:id);
 return <card>{$data->text}</card>; 
 } 
 }

Retrofitting async rendering

slide-26
SLIDE 26
slide-27
SLIDE 27
slide-28
SLIDE 28
slide-29
SLIDE 29
slide-30
SLIDE 30

A declarative interface leaves the door open for future changes

slide-31
SLIDE 31

Synchronizing state with a UI DOM nodes and APIs Goal: Medium:

Client rendering

slide-32
SLIDE 32

{liked: } false

slide-33
SLIDE 33

{liked: } true

slide-34
SLIDE 34

{liked: } false

slide-35
SLIDE 35

var liked = false; 
 var like = container.children[0]; 
 var unlike = container.children[1];
 
 container.addEventListener('click', (e) => { liked = !liked;
 like.style.display = liked ? 'none' : 'block'; 
 unlike.style.display = liked ? 'block' : 'none'; 
 });

DOM APIs Browser compatibility Bookkeeping

slide-36
SLIDE 36

$('.like-button').click(function() { 
 $(container).find('.like').toggle(); 
 $(container).find('.unlike').toggle(); 
 });

jQuery simplifies the DOM APIs

slide-37
SLIDE 37
slide-38
SLIDE 38

class LikeButton extends React.Component { 
 render() { 
 return this.state.liked ? 
 <Button label="Like" onClick={...} /> 
 <Button label="Unlike" onClick={...} /> 
 }
 }

Initial render and updates share an API

slide-39
SLIDE 39

Good infra doesn't come from building in isolation

slide-40
SLIDE 40

Work directly with product teams to understand their needs

slide-41
SLIDE 41
slide-42
SLIDE 42

Minimize public interfaces Update call sites alongside infra changes Use tooling to automate changes Deprecate, log, and monitor

Iterating on a core library is really, really hard

slide-43
SLIDE 43

React has gone places we never expected

slide-44
SLIDE 44
slide-45
SLIDE 45
slide-46
SLIDE 46

Handling application state changes in a predictable way Object mutation and events Goal: Medium:

State management

slide-47
SLIDE 47
slide-48
SLIDE 48
slide-49
SLIDE 49

Stores Views Dispatcher

slide-50
SLIDE 50

Flummox Alt Fluxxor McFly Lux Delorean Reflux Material Flux MartyJS Fluxible Flux This OmniscientJS Fluxy

slide-51
SLIDE 51

Flux and Redux are still imperative

Simplified mutations and events, but didn't replace them We couldn't iterate on implementation

slide-52
SLIDE 52

function Product(props) { return <li>{props.name} (AUD {props.price}) </li>;
 } 
 
 Relay.createContainer(Product, { 
 product: ` 
 fragment { 
 name, 
 price, 
 } 
 `, 
 }); 


Relay is a new approach to data management

slide-53
SLIDE 53

Declarative Immutable Automated data fetching No manual object mutations Static analysis

slide-54
SLIDE 54

Declarative code and static analysis play well together

Extract data requirements as a build step Fetch data without running JavaScript Not possible with imperative code

slide-55
SLIDE 55
slide-56
SLIDE 56

Strings XHP DOM APIs jQuery React Ad hoc Flux Relay

slide-57
SLIDE 57

Clearly define the problem space

slide-58
SLIDE 58

Understand products' needs

Start by working directly with a team You should be writing product code

slide-59
SLIDE 59

Plan to iterate

Build an escape hatch Support incremental adoption Iterate on the abstraction

slide-60
SLIDE 60

One way data flow Declarative interfaces Immutability Functional programming Static analysis

Steal ideas that work

slide-61
SLIDE 61

Thank you

@joshduck