Slide 1

Slide 1 text

Modular Design

Slide 2

Slide 2 text

ponyfoo.com @nzgb

Slide 3

Slide 3 text

ponyfoo.com/books

Slide 4

Slide 4 text

A Brief History of JavaScript Modularity

Slide 5

Slide 5 text

Slide 6

Slide 6 text

~function(){ // … }()

Slide 7

Slide 7 text

var i = (function(){ return { hello: 'world' } })()

Slide 8

Slide 8 text

<script> <script> <script>

Slide 9

Slide 9 text

RequireJS AngularJS Dependency injection

Slide 10

Slide 10 text

RequireJS define(['./sum'], function (sum) { return function double(a) { return sum(a, a) } })

Slide 11

Slide 11 text

AngularJS angular.factory('double', ['sum', function (sum) { return function double(a) { return sum(a, a) } }] )

Slide 12

Slide 12 text

Over-engineered. Verbose. But good enough

Slide 13

Slide 13 text

NodeJS CommonJS

Slide 14

Slide 14 text

const sum = require('./sum') module.exports = function double(a) { return sum(a, a) } CommonJS

Slide 15

Slide 15 text

Browserify

Slide 16

Slide 16 text

Babel Webpack Rollup

Slide 17

Slide 17 text

ES Modules import sum from './sum' export default function double(a) { return sum(a, a) }

Slide 18

Slide 18 text

GCC Babel Rollup Prepack

Slide 19

Slide 19 text

Prepack [1, 2, 3].forEach(n => { console.log(n) }) console.log(1) console.log(2) console.log(3)

Slide 20

Slide 20 text

Slide 21

Slide 21 text

But why?

Slide 22

Slide 22 text

No clashing (raison d'être for CSS-in-JS)

Slide 23

Slide 23 text

Containing Complexity

Slide 24

Slide 24 text

No content

Slide 25

Slide 25 text

It's all about containing complexity. Think of your modules as lego blocks. You don't necessarily care about the details of how each block is made. All you need to know is how to use the lego blocks to build your lego castle. — @sindresorhus

Slide 26

Slide 26 text

Interfaces

Slide 27

Slide 27 text

Breaking Down Complexity

Slide 28

Slide 28 text

Aspect, or Flow?

Slide 29

Slide 29 text

Portability

Slide 30

Slide 30 text

Composability

Slide 31

Slide 31 text

Composability

Slide 32

Slide 32 text

Modular Design Essentials

Slide 33

Slide 33 text

Single Responsibility Principle

Slide 34

Slide 34 text

API First

Slide 35

Slide 35 text

Revealing Pattern

Slide 36

Slide 36 text

Consistency (across modules)

Slide 37

Slide 37 text

Ambiguity

Slide 38

Slide 38 text

Be conservative in what you do, be liberal in what you accept from others. — Postel's Law (from TCP)

Slide 39

Slide 39 text

No content

Slide 40

Slide 40 text

Simplicity

Slide 41

Slide 41 text

Interface Testing

Slide 42

Slide 42 text

Interface Documentation

Slide 43

Slide 43 text

Abstraction

Slide 44

Slide 44 text

The Holy Grail!

Slide 45

Slide 45 text

Oh no.

Slide 46

Slide 46 text

Premature Abstraction

Slide 47

Slide 47 text

The Right Abstraction

Slide 48

Slide 48 text

Refactoring Complex Code

Slide 49

Slide 49 text

Less Clever* Code. (way less.) *

Slide 50

Slide 50 text

Use More* Variables! (way more.) *

Slide 51

Slide 51 text

() => a && (b ? c : d) || e if (a) { return b ? c : d } return e

Slide 52

Slide 52 text

Guard Clauses

Slide 53

Slide 53 text

if (apiKey) { if (apiSecret) { // happy path } else { throw new Error('missing secret') } } else { throw new Error('missing key') }

Slide 54

Slide 54 text

if (!apiKey) { throw new Error('missing key') } if (!apiSecret) { throw new Error('missing secret') } // happy path

Slide 55

Slide 55 text

Extract Function

Slide 56

Slide 56 text

let optionalLabel = null if (labelText) { optionalLabel = ( { labelText } ) }

Slide 57

Slide 57 text

const optionalLabel = renderLabel({ labelText }) function renderLabel({ labelText }) { if (!labelText) { return null } return { labelText } }

Slide 58

Slide 58 text

When all else fails … Slice Function

Slide 59

Slide 59 text

Thanks! @nzgb