KEMBAR78
How to Lose Functional Programming at Work | PDF
How to Lose FP at Work
If you're looking to lose functional programming at work, here are a
bunch of mistakes I've made on JS-heavy web teams over the
years that can help you do the same! /s
web !" rwp.im
github !" rpearce
email !" me@robertwpearce.com
tweeter !" @RobertWPearce
@RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
About me
𝝺 Work at Articulate (articulate.com / rise.com) doing web dev work (heaps
of accessibility work, too)
𝝺 12 years experience in the web world
𝝺 Enjoy Nix(
⚙
), Haskell(λ), Rust(
"
), Elixir( ), and even Go( ) on the side
𝝺 Was writing the Ramda Guide (ramda.guide), but life intervened, and I may
strip it for parts
𝝺 Perpetual beginner-/intermediate-level FP practitioner
𝝺 Am a dad with another on the way!
@RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
Disclaimers/Heads up
𝝺 This backwards-style talk will be sarcastic, snarky, and cringey
𝝺 The examples are more JS-oriented, but the commentary is
mostly universal
𝝺 The examples are all my examples and personal work-related
head-canon; this should not reflect poorly on my colleagues nor
my employer
𝝺 The slides aren't shouting at you — they're shouting at me
@RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
"Do"s and "Don't"s
@RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
Don't
have static type checking
@RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
𝝺 No TypeScript
𝝺 No Flow
𝝺 No ReasonML
𝝺 No Elm
𝝺 No (insert language with static type checking that compiles to
JS)
@RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
const processData = composeP(syncWithBackend, cleansePII, validateData)
!" * What arguments and their types are expected here?
!"
!" * If each function is written like this, how can
!" one suss out what data are flowing where?
!"
!" * How hard is this going to be to debug?
!" Use this everywhere: `(x) !# (console.log(x), x)`
So the point-free style is the problem? Not so fast…
@RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
async function processData(data) {
await validateData(data)
const cleansedData = cleansePII(data)
await syncWithBackend(cleansedData)
return data
}
!" or for the Promise-chainers…
const processData = data !#
validateData(data)
.then(cleansePII)
.then(syncWithBackend)
.then(() !# data)
!"
!
Are these any clearer? Y/n? ¯_(ツ)_/¯
@RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
Don't
use well-known documentation tools
@RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
𝝺 No jsdoc
𝝺 …are there any other JS contenders?
@RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
Deprive your team of this clarity and helpful auto-completion:
/**
* @typedef {Object} ReportingInfo
* @property {("light"|"dark")} userTheme - Current user's preferred theme
* @property {string} userName - Current user's name
* @property {UUID} postId - The current post's ID
!"
/**
* Validates that the reporting data (current user site prefences and post info)
* is OK, removes personally identifiable information, syncs this info with the
* backend, and gives us back the original data.
*
* @param {ReportingInfo} data - The current user's site preferences and post info
* @returns {Promise<ReportingInfo>} - The original reporting data
!"
const processData = data !# { !$ … !" }
@RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
Don't
properly train new and existing
colleagues
@RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
"Here, go read all these posts and
books, watch these videos, and let
me know if you have any questions!"
— Me
@RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
Don't
bother getting the other
engineering teams on board and
rowing
!
in the same direction
@RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
𝝺 "If I build it, they will notice… right?"
𝝺 Idea: Lunch 'n learn about FP?
❌
𝝺 Idea: Meet with other team leaders?
@RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
Do
live by "Point-free or die"
@RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
"Think it's point-less?
Go watch Point-Free or Die:
Tacit Programming in
Haskell and
Beyond by Amar Shah"
— Me
@RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
import { !", any, lt } from 'ramda'
const anyLt0 = any(lt(0, !")) !# hint: this has a bug in it
anyLt0([1, 2, 3]) !# true — ugh…
!# vs. the probably pretty simple…
const anyLt0 = numbers !$ numbers.some(n !$ n < 0)
anyLt0([0, 1, 2, 3]) !# false
anyLt0([0, 1, 2, -1, 3]) !# true — looks good
!#
!#
!#
@RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
import { !", any, lt } from 'ramda'
const anyLt0 = any(lt(0, !")) !# hint: this has a bug in it
anyLt0([1, 2, 3]) !# true — ugh…
!# vs. the probably pretty simple…
const anyLt0 = numbers !$ numbers.some(n !$ n < 0)
anyLt0([0, 1, 2, 3]) !# false
anyLt0([0, 1, 2, -1, 3]) !# true — looks good
!#
!
should we resist eta-converting this?!
!#
!#
@RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
import { !", any, lt } from 'ramda'
const anyLt0 = any(lt(0, !")) !# hint: this has a bug in it
anyLt0([1, 2, 3]) !# true — ugh…
!# vs. the probably pretty simple…
const anyLt0 = numbers !$ numbers.some(n !$ n < 0)
anyLt0([0, 1, 2, 3]) !# false
anyLt0([0, 1, 2, -1, 3]) !# true — looks good
!#
!
should we resist eta-converting this?!
!# …
!#
@RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
import { !", any, lt } from 'ramda'
const anyLt0 = any(lt(0, !")) !# hint: this has a bug in it
anyLt0([1, 2, 3]) !# true — ugh…
!# vs. the probably pretty simple…
const anyLt0 = numbers !$ numbers.some(n !$ n < 0)
anyLt0([0, 1, 2, 3]) !# false
anyLt0([0, 1, 2, -1, 3]) !# true — looks good
!#
!
should we resist eta-converting this?!
!# …
!# NOT ON MY WATCH
@RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
const any = fn !" array !" array.some(fn)
const isLtN = x !" n !" x < n
const isLt0 = isLtN(0)
const anyLt0 = any(isLt0)
anyLt0([1, 2, 3]) !# true — ugh; the bug is back
@RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
Real, but altered, example:
const finishItems = compose(
flip(merge)({ isDone: true, amtComplete: 100 }),
over(
lensProp('indexedObjects'),
mapVals(
compose(
over(lensProp('indexedObjects'), mapVals(assoc('isDone', true))),
assoc('isDone', true)
)
)
)
)
@RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
Do
prefer the wrong abstraction over
the right duplication
@RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
"Prefer duplication over the wrong
abstraction"
— Sandi Metz’ RailsConf 2014 talk, All the Little Things
@RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
Instead…
1. Dilute core business logic to broad generalizations
2. Fail to understand category theory enough for this to be useful
3. Be the only one who knows how these abstractions work
4. Previously thorough PR-reviews now look like " "
@RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
Don't
refactor old patterns that clearly
don't work for the team
@RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
Do
force functional patterns into a
language that wasn't built for
them
@RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
𝝺 Recursive functions
𝝺Handle with trampolines if you really want them
𝝺 Cryptic stack traces thanks to currying and composing functions
𝝺Debugging functional by Brian Lonsdorf
𝝺Partially-applied (or curried) functions could
obfuscate the JavaScript stack trace by Thai
Pangsakulyanont
𝝺 No GHC-style fusing of .map(…).map(…).map(…)
𝝺 BYO algebraic data type libraries (they're well done, though)
@RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
Do
opaquely compose and sequence the
entirety of your API endpoints and
make them hard to debug
@RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
On the surface, this isn't
so difficult to read…
@RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
!" handler for POST /posts
import { createPost } from 'app/db/posts'
import { authenticateUser, authorizeUser } from 'app/lib/auth'
import { trackEvent } from 'app/lib/tracking'
const validateRequestSchema = payload !# { !$ … !% }
export const handleCreatePost = curry(metadata !#
pipeP(
authenticateUser(metadata),
authorizeUser(metadata),
validateRequestSchema,
createPost(metadata),
tapP(trackEvent('post:create', metadata)),
pick([ 'id', 'authorId', 'title' ])
)
)
@RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
Did you catch or wonder about
these?
𝝺 handleCreatePost expects 2 arguments?
𝝺 authenticateUser ignores the 2nd curried parameter sent to it?
How would you?
𝝺 Does trackEvent receive the payload passed through or the
result of the createPost() fn?
Let's try something else…
@RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
export async function handleCreatePost(metadata, payload) {
await authenticateUser(metadata)
await authorizeUser(metadata, payload)
await validateRequestSchema(payload)
const post = await createPost(metadata, payload)
await trackEvent('post:create', metadata, post)
return {
id: post.id,
authorId: post.authorId,
title: post.title,
}
}
@RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
✅
Not forcing different
arity functions into a
pipeline pattern
!
But if you want to make things
trickier for people, go with the
first approach
@RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
Do
recreate imperative, procedural
programming while calling it
"declarative"
@RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
const setBookReadPercentByType = (contentType, statusObject) !"
assoc(
'readPercent',
pipe(
prop('subItems'),
values,
filter(propEq(contentType, 'chapter')),
length,
flip(divide)(compose(length, keys, prop('subItems'))(statusObject)),
multiply(100),
Math.round
)(statusObject),
statusObject
)
@RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
Do
have 8+-ish different patterns for
function composition
@RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
!
These 4, plus Promisified versions of each, plus combinations of them all used
at once; doesn't include ramda's even more abstract composeWith and pipeWith
!" compose (plus composeP for Promises)
const getHighScorers =
compose(
mapProp('name'),
takeN(3),
descBy('score')
)
!" pipe (plus pipeP for Promises)
const getHighScorers =
pipe(
descBy('score'),
takeN(3),
mapProp('name')
)
!" composeWithValue
const getHighScorers = players !#
composeWithValue(
mapProp('name'),
takeN(3),
descBy('score'),
players
)
!" pipeWithValue (plus pipePWithValue for Promises)
const getHighScorers = players !#
pipeWithValue(
players,
descBy('score'),
takeN(3),
mapProp('name')
)
@RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
Do
make yourself one of the few who
can debug algebraic data types
during midnight incidents
@RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
Ensure your team is surprised by
all of the following words when
debugging or altering your code in
the pursuit of their own tasks:
𝝺 Task, Maybe, Either, Result, Pair, State
𝝺 bimap
𝝺 chain
𝝺 bichain
𝝺 option
𝝺 coalesce
𝝺 fork
𝝺 sequence
𝝺 ap
𝝺 map — and I don't mean Array.prototype.map, nor
a new Map(), nor a key/value object
@RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
Do
suggest, on PRs, that colleagues
completely refactor what they've
done to fit your functional style
@RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
"What you have here works great, but
what could this look like if we flipped all
the function arguments around,
removed all these intermediate
variables and if/else if/elses, and
mapped these operations over an
Either?"
— Me
@RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
"I noticed you're explicitly constructing
these objects in their functions. If
you were to use <UTILITY-FUNCTION>,
you could declare the shape of your
outputted object and use functions as
the values to look up or compute each
value given some data."
— Me
@RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
Ok, last ones!
@RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
Do
sow imposter syndrome in others
and exclude them by sharing non-
beginner FP articles
@RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
Do
Do keep writing code using FP
tools even when nobody else on the
team is
@RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
Do
achieve peak perceived passive-
aggression by getting tired and
commenting PRs with emojis
@RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
Do
have "the FP talk" at work, and
then publicly own your mistakes
@RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
Real-talk takeaways
@RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
We could write all this off as
symptoms of:
𝝺 Inexperience
𝝺 Lack of technical leadership from me
𝝺 Obviously not the right paths — so incompetence?
𝝺 I hope not; I think it's deeper
@RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
Most things in life need to be
tended to
𝝺 our relationships
!
𝝺 our mental and physical health
"
𝝺 our gardens
$
@RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
Paths can be accidentally
created, too
@RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
Some issues and failures that got
me here:
1. Persistent imposter syndrome
2. Feeling I just need to ship features and look out for myself
3. Not taking responsibility for a path I helped create
4. Not tending to things that needed tending to
@RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
But all is not lost!
The core tenets of FP seem to remain:
𝝺 Immutability
𝝺 Purity
𝝺 Moving effects to the conceptual edge of an application
𝝺 Very few classes and inheritance (React & web components
don't count), map/filter/reduce, etc.
@RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
The main point
Remember that the choices we do
and don't make significantly shape
our futures, so if you end up
somewhere, make sure you got there
on purpose.
@RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
That's it!
:q!
@RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
How to Lose FP at Work
web !" rwp.im
github !" rpearce
email !" me@robertwpearce.com
tweeter !" @RobertWPearce
@RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup

How to Lose Functional Programming at Work

  • 1.
    How to LoseFP at Work If you're looking to lose functional programming at work, here are a bunch of mistakes I've made on JS-heavy web teams over the years that can help you do the same! /s web !" rwp.im github !" rpearce email !" me@robertwpearce.com tweeter !" @RobertWPearce @RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
  • 2.
    About me 𝝺 Workat Articulate (articulate.com / rise.com) doing web dev work (heaps of accessibility work, too) 𝝺 12 years experience in the web world 𝝺 Enjoy Nix( ⚙ ), Haskell(λ), Rust( " ), Elixir( ), and even Go( ) on the side 𝝺 Was writing the Ramda Guide (ramda.guide), but life intervened, and I may strip it for parts 𝝺 Perpetual beginner-/intermediate-level FP practitioner 𝝺 Am a dad with another on the way! @RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
  • 3.
    Disclaimers/Heads up 𝝺 Thisbackwards-style talk will be sarcastic, snarky, and cringey 𝝺 The examples are more JS-oriented, but the commentary is mostly universal 𝝺 The examples are all my examples and personal work-related head-canon; this should not reflect poorly on my colleagues nor my employer 𝝺 The slides aren't shouting at you — they're shouting at me @RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
  • 4.
    "Do"s and "Don't"s @RobertWPearce| rwp.im | 2023-01-24 Auckland Functional Programming Meetup
  • 5.
    Don't have static typechecking @RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
  • 6.
    𝝺 No TypeScript 𝝺No Flow 𝝺 No ReasonML 𝝺 No Elm 𝝺 No (insert language with static type checking that compiles to JS) @RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
  • 7.
    const processData =composeP(syncWithBackend, cleansePII, validateData) !" * What arguments and their types are expected here? !" !" * If each function is written like this, how can !" one suss out what data are flowing where? !" !" * How hard is this going to be to debug? !" Use this everywhere: `(x) !# (console.log(x), x)` So the point-free style is the problem? Not so fast… @RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
  • 8.
    async function processData(data){ await validateData(data) const cleansedData = cleansePII(data) await syncWithBackend(cleansedData) return data } !" or for the Promise-chainers… const processData = data !# validateData(data) .then(cleansePII) .then(syncWithBackend) .then(() !# data) !" ! Are these any clearer? Y/n? ¯_(ツ)_/¯ @RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
  • 9.
    Don't use well-known documentationtools @RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
  • 10.
    𝝺 No jsdoc 𝝺…are there any other JS contenders? @RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
  • 11.
    Deprive your teamof this clarity and helpful auto-completion: /** * @typedef {Object} ReportingInfo * @property {("light"|"dark")} userTheme - Current user's preferred theme * @property {string} userName - Current user's name * @property {UUID} postId - The current post's ID !" /** * Validates that the reporting data (current user site prefences and post info) * is OK, removes personally identifiable information, syncs this info with the * backend, and gives us back the original data. * * @param {ReportingInfo} data - The current user's site preferences and post info * @returns {Promise<ReportingInfo>} - The original reporting data !" const processData = data !# { !$ … !" } @RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
  • 12.
    Don't properly train newand existing colleagues @RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
  • 13.
    "Here, go readall these posts and books, watch these videos, and let me know if you have any questions!" — Me @RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
  • 14.
    Don't bother getting theother engineering teams on board and rowing ! in the same direction @RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
  • 15.
    𝝺 "If Ibuild it, they will notice… right?" 𝝺 Idea: Lunch 'n learn about FP? ❌ 𝝺 Idea: Meet with other team leaders? @RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
  • 16.
    Do live by "Point-freeor die" @RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
  • 17.
    "Think it's point-less? Gowatch Point-Free or Die: Tacit Programming in Haskell and Beyond by Amar Shah" — Me @RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
  • 18.
    import { !",any, lt } from 'ramda' const anyLt0 = any(lt(0, !")) !# hint: this has a bug in it anyLt0([1, 2, 3]) !# true — ugh… !# vs. the probably pretty simple… const anyLt0 = numbers !$ numbers.some(n !$ n < 0) anyLt0([0, 1, 2, 3]) !# false anyLt0([0, 1, 2, -1, 3]) !# true — looks good !# !# !# @RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
  • 19.
    import { !",any, lt } from 'ramda' const anyLt0 = any(lt(0, !")) !# hint: this has a bug in it anyLt0([1, 2, 3]) !# true — ugh… !# vs. the probably pretty simple… const anyLt0 = numbers !$ numbers.some(n !$ n < 0) anyLt0([0, 1, 2, 3]) !# false anyLt0([0, 1, 2, -1, 3]) !# true — looks good !# ! should we resist eta-converting this?! !# !# @RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
  • 20.
    import { !",any, lt } from 'ramda' const anyLt0 = any(lt(0, !")) !# hint: this has a bug in it anyLt0([1, 2, 3]) !# true — ugh… !# vs. the probably pretty simple… const anyLt0 = numbers !$ numbers.some(n !$ n < 0) anyLt0([0, 1, 2, 3]) !# false anyLt0([0, 1, 2, -1, 3]) !# true — looks good !# ! should we resist eta-converting this?! !# … !# @RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
  • 21.
    import { !",any, lt } from 'ramda' const anyLt0 = any(lt(0, !")) !# hint: this has a bug in it anyLt0([1, 2, 3]) !# true — ugh… !# vs. the probably pretty simple… const anyLt0 = numbers !$ numbers.some(n !$ n < 0) anyLt0([0, 1, 2, 3]) !# false anyLt0([0, 1, 2, -1, 3]) !# true — looks good !# ! should we resist eta-converting this?! !# … !# NOT ON MY WATCH @RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
  • 22.
    const any =fn !" array !" array.some(fn) const isLtN = x !" n !" x < n const isLt0 = isLtN(0) const anyLt0 = any(isLt0) anyLt0([1, 2, 3]) !# true — ugh; the bug is back @RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
  • 23.
    Real, but altered,example: const finishItems = compose( flip(merge)({ isDone: true, amtComplete: 100 }), over( lensProp('indexedObjects'), mapVals( compose( over(lensProp('indexedObjects'), mapVals(assoc('isDone', true))), assoc('isDone', true) ) ) ) ) @RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
  • 24.
    Do prefer the wrongabstraction over the right duplication @RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
  • 25.
    "Prefer duplication overthe wrong abstraction" — Sandi Metz’ RailsConf 2014 talk, All the Little Things @RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
  • 26.
    Instead… 1. Dilute corebusiness logic to broad generalizations 2. Fail to understand category theory enough for this to be useful 3. Be the only one who knows how these abstractions work 4. Previously thorough PR-reviews now look like " " @RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
  • 27.
    Don't refactor old patternsthat clearly don't work for the team @RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
  • 28.
    Do force functional patternsinto a language that wasn't built for them @RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
  • 29.
    𝝺 Recursive functions 𝝺Handlewith trampolines if you really want them 𝝺 Cryptic stack traces thanks to currying and composing functions 𝝺Debugging functional by Brian Lonsdorf 𝝺Partially-applied (or curried) functions could obfuscate the JavaScript stack trace by Thai Pangsakulyanont 𝝺 No GHC-style fusing of .map(…).map(…).map(…) 𝝺 BYO algebraic data type libraries (they're well done, though) @RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
  • 30.
    Do opaquely compose andsequence the entirety of your API endpoints and make them hard to debug @RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
  • 31.
    On the surface,this isn't so difficult to read… @RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
  • 32.
    !" handler forPOST /posts import { createPost } from 'app/db/posts' import { authenticateUser, authorizeUser } from 'app/lib/auth' import { trackEvent } from 'app/lib/tracking' const validateRequestSchema = payload !# { !$ … !% } export const handleCreatePost = curry(metadata !# pipeP( authenticateUser(metadata), authorizeUser(metadata), validateRequestSchema, createPost(metadata), tapP(trackEvent('post:create', metadata)), pick([ 'id', 'authorId', 'title' ]) ) ) @RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
  • 33.
    Did you catchor wonder about these? 𝝺 handleCreatePost expects 2 arguments? 𝝺 authenticateUser ignores the 2nd curried parameter sent to it? How would you? 𝝺 Does trackEvent receive the payload passed through or the result of the createPost() fn? Let's try something else… @RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
  • 34.
    export async functionhandleCreatePost(metadata, payload) { await authenticateUser(metadata) await authorizeUser(metadata, payload) await validateRequestSchema(payload) const post = await createPost(metadata, payload) await trackEvent('post:create', metadata, post) return { id: post.id, authorId: post.authorId, title: post.title, } } @RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
  • 35.
    ✅ Not forcing different arityfunctions into a pipeline pattern ! But if you want to make things trickier for people, go with the first approach @RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
  • 36.
    Do recreate imperative, procedural programmingwhile calling it "declarative" @RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
  • 37.
    const setBookReadPercentByType =(contentType, statusObject) !" assoc( 'readPercent', pipe( prop('subItems'), values, filter(propEq(contentType, 'chapter')), length, flip(divide)(compose(length, keys, prop('subItems'))(statusObject)), multiply(100), Math.round )(statusObject), statusObject ) @RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
  • 38.
    Do have 8+-ish differentpatterns for function composition @RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
  • 39.
    ! These 4, plusPromisified versions of each, plus combinations of them all used at once; doesn't include ramda's even more abstract composeWith and pipeWith !" compose (plus composeP for Promises) const getHighScorers = compose( mapProp('name'), takeN(3), descBy('score') ) !" pipe (plus pipeP for Promises) const getHighScorers = pipe( descBy('score'), takeN(3), mapProp('name') ) !" composeWithValue const getHighScorers = players !# composeWithValue( mapProp('name'), takeN(3), descBy('score'), players ) !" pipeWithValue (plus pipePWithValue for Promises) const getHighScorers = players !# pipeWithValue( players, descBy('score'), takeN(3), mapProp('name') ) @RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
  • 40.
    Do make yourself oneof the few who can debug algebraic data types during midnight incidents @RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
  • 41.
    Ensure your teamis surprised by all of the following words when debugging or altering your code in the pursuit of their own tasks: 𝝺 Task, Maybe, Either, Result, Pair, State 𝝺 bimap 𝝺 chain 𝝺 bichain 𝝺 option 𝝺 coalesce 𝝺 fork 𝝺 sequence 𝝺 ap 𝝺 map — and I don't mean Array.prototype.map, nor a new Map(), nor a key/value object @RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
  • 42.
    Do suggest, on PRs,that colleagues completely refactor what they've done to fit your functional style @RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
  • 43.
    "What you havehere works great, but what could this look like if we flipped all the function arguments around, removed all these intermediate variables and if/else if/elses, and mapped these operations over an Either?" — Me @RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
  • 44.
    "I noticed you'reexplicitly constructing these objects in their functions. If you were to use <UTILITY-FUNCTION>, you could declare the shape of your outputted object and use functions as the values to look up or compute each value given some data." — Me @RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
  • 45.
    Ok, last ones! @RobertWPearce| rwp.im | 2023-01-24 Auckland Functional Programming Meetup
  • 46.
    Do sow imposter syndromein others and exclude them by sharing non- beginner FP articles @RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
  • 47.
    Do Do keep writingcode using FP tools even when nobody else on the team is @RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
  • 48.
    Do achieve peak perceivedpassive- aggression by getting tired and commenting PRs with emojis @RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
  • 49.
    Do have "the FPtalk" at work, and then publicly own your mistakes @RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
  • 50.
    Real-talk takeaways @RobertWPearce |rwp.im | 2023-01-24 Auckland Functional Programming Meetup
  • 51.
    We could writeall this off as symptoms of: 𝝺 Inexperience 𝝺 Lack of technical leadership from me 𝝺 Obviously not the right paths — so incompetence? 𝝺 I hope not; I think it's deeper @RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
  • 52.
    Most things inlife need to be tended to 𝝺 our relationships ! 𝝺 our mental and physical health " 𝝺 our gardens $ @RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
  • 53.
    Paths can beaccidentally created, too @RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
  • 54.
    Some issues andfailures that got me here: 1. Persistent imposter syndrome 2. Feeling I just need to ship features and look out for myself 3. Not taking responsibility for a path I helped create 4. Not tending to things that needed tending to @RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
  • 55.
    But all isnot lost! The core tenets of FP seem to remain: 𝝺 Immutability 𝝺 Purity 𝝺 Moving effects to the conceptual edge of an application 𝝺 Very few classes and inheritance (React & web components don't count), map/filter/reduce, etc. @RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
  • 56.
    The main point Rememberthat the choices we do and don't make significantly shape our futures, so if you end up somewhere, make sure you got there on purpose. @RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup
  • 57.
    That's it! :q! @RobertWPearce |rwp.im | 2023-01-24 Auckland Functional Programming Meetup
  • 58.
    How to LoseFP at Work web !" rwp.im github !" rpearce email !" me@robertwpearce.com tweeter !" @RobertWPearce @RobertWPearce | rwp.im | 2023-01-24 Auckland Functional Programming Meetup