L&L April 2022
Steve Olsen
GOALS:
What's all the ado?
Code that processes data
that are common to solving a problem
Single purpose ideally
(rule of thumb: 10 statements, early exit)
No external state or data dependencies
(i.e. no closures, i/o)
REPEATABLE / idempotent
Highly refactorable
Highly testable
Highly reusable
Single purpose ideally
(rule of thumb: 10 statements, early exit)
HAS external state or data dependencies
(i.e. closures, i/o)
CHANGE TO STATE
NON-REPEATABLE / non-idempotent
HARDer to refactor
HARDer to test
HARDer to reuse
export const add = (a, b) => a + bimport fs from "fs"
export const saveToFile = async (filename, text) => {
return fs.writeFile(filename, text)
}
export const readFile = async (filename) => {
return fs.readFile(filename)
}
export const callApi = async (id) => {
return fetch(`http://123.com/${id}`).then(r => r.json())
}
let id = 0
export const getId() {
return id++
}
Date.now() === '?????'main()
"composition"
OOP: “Composition over inheritance”
contain instances, instead of
inheriting from a parent
FP: "Onion Layers"
wrappers that intercept an
inner function's execution
Each "onion layer" is a function
const g = f(x)
const G = <F><X/></F>// Constructor ///////////
const handleButton = (index) => () => {
console.log("Clicked button #" + index)
}
...
{[1,2,3].map((number, idx) =>
<button onClick={handleButton(idx)}>{number}</button>)}
// Decorator ///////////
const timeFunc = (cb) => () => {
const now = Date.now()
cb()
console.log("TIME LAPSED (ms):", Date.now() - now)
}
const looper = (times) {
for (let i = 0; i < times; i++) {
console.log("i=" + i)
}
}
const timedLoop = timeFunc(() => looper(99999))
timedLoop() // TIME LAPSED (ms): 4
timedLoop() // TIME LAPSED (ms): 6
timedLoop() // TIME LAPSED (ms): 3// Theory
const add = (a, b) => a + b
const addBy5 = add(5)
addBy5(5) === 10A function that returns a function
until all its arguments are provided.
JavaScript does not provide this natively,
but there are wrappers to provide it!
Eg. [ [ pres ] state({initial}) ]
Eg. [ [ apiGetUser ] debounce({seconds}) ]const initialState = {count: 0};
function reducer(state, action) {
switch (action.type) {
case 'cnt/increment':
return {count: state.count + 1};
case 'cnt/decrement':
return {count: state.count - 1};
// default:
// throw new Error();
}
}
function Counter() {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<>
Count: {state.count}
<button onClick={() => dispatch({type: 'cnt/decrement'})}>-</button>
<button onClick={() => dispatch({type: 'cnt/increment'})}>+</button>
</>
);
}aka. low ratio of wtf-per-minute
OPTIMIZED (5%)
MAINTAINABLE (90%+)
WORKING (5%)
refactor, test
heavy test
All essential code must go somewhere —
in another well-named file (follow naming conventions)
split up per responsibility
benefits:
less scrolling/hopping around file ("fits in your head")
${dirty} ${activeEditorMedium}${separator}${rootName}
"Connascence": level of coupling
Dimensions: strength, degree, locality
Not all coupling is "bad"
Tradeoffs made by the developer
important to understand them!
they're highly functional
data presentation
event handling
state manipulation
Data validation [assert]
Data manipulation [map/reduce]
Data API calls [I/O]
Analytics / metics / logging [monitoring I/O]
data presentation
event handling
state manipulation
Data validation [assert]
Data manipulation [map/reduce]
Data API calls [I/O]
Analytics / metics / logging [monitoring I/O]
data presentation
event handling
state manipulation
Data validation [assert]
Data manipulation [map/reduce]
Data API calls [I/O]
Analytics / metics / logging [monitoring I/O]
Pres
Contain
Func/
BusLog
a1) Presentation components:
app state manipulation
wire up business logic to presentation component
a2) Container components:
data manipulation [map/reduce]
analytics / metics / logging [monitoring I/O]
b) Business Logic functions:
Goal: reduce copy/paste, DRY!
Create new component APIs that encapsulate common patterns and conventions
Often a parent/child relationship
Common ones are shared:
maximize reuse
minimize redundancy
Think about this like “a bucket of specific Figma assets” ala drag-and-drop reuse
Eg. Carousel, Select box, Navigation
https://www.patterns.dev/posts/presentational-container-pattern/
https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0
https://gist.github.com/chantastic/fc9e3853464dffdb1e3c
front_end/src/views-mui/header/header-omni/header-omni-mobile.component.js link
front_end/src/components-mui/header-desktop/header-desktop-nav.container.js link
component duplication, event handling, io
utility components, new files, decouple BL
snapcommerce-spa/src/routers/auth-required.tsx link
Questions?