From Imperative to Functional: TypeScript Fetch Promise
shows how more functional code is superior to imperative code to
perform a simple fetch request to get a JSON value that models a tree data
structure to be represented later by
Both versions are correct and do the same, but the “functional” version still has some imperative style because JS/TS is not a functional language but the difference is clear again.
The difference between both snippets is the following:
The refactored code (a.k.a. “more functional”) is not functional, but it gets close. This is to avoid introducing functional abstractions like pipes, monads, etc., on top of JS/TS which is not a functional language but a mixed one as the underlying project is pretty short.
By noticing the:
👎🏻 return statement
👎🏻 ternary operator
👎🏻 error handling block
And lack of:
👉🏻 pipe operator
👉🏻 pattern matching
Then we have reasons why the “functional” snippet doesn’t get even better.
The imperative version has the following visible problems, and I encourage you to reason the code snippets to figure them out:
- Imperatively needs to add
asyncto the function signature which leads to the “async-await hell” and more boilerplate.
- Usage of mutable variable
treefor returning the function value in order to avoid a multiple-
- Usage of
catchfor error handling which has many disadvantages and can be replaced with sum types or monads like Rust does, so there’s no reason why we should keep using
catchblocks in robust software development.
- Usage of OOP which might enhance lower-level imperative code but is complete nonsense for high-level software (most projects) and yes, more boilerplate.
- As I say below, it still has and needs mixed components (functional/declarative, OO, etc.) so if we could go fully functional (with better languages) why keep writing cheap code like that?
- Has more formatting constraints, I always put the
elsebranch on a new line (which gives more LoC) as it is factually the best way to format it.
- It’s obviously quite prone to error and hard to read.
- Even the Mozilla docs for
Promiseonly show toy examples, and real life error handling gets worse with imperative code. Code on the internet like docs or tutorials almost always skip the status
okerror handling and go directly to fail when parsing the
JSONdata. Who cares when code is imperative anyway?
Also, notice how throwing from a
catch block is an antipattern as it
If TS had
try-expressions (like Kotlin) the imperative version would get
much better regarding correctness and style, but expressions are
declarative so functional in the end 😋.
The more you make a program better, the more functional it gets, that’s because FP is the only/original programming paradigm there exists as per scientific concerns, and all other paradigms are just cheap workarounds.
Notice we can go “pure functional” but not “pure imperative” or “pure OO” so the workarounds are clearly the alternative non-functional paradigms.
Another good one I know a lot from experience is that the more I refactor code to improve it the more domain-specific it gets, and FP is clearly the natural way to go for DSLs.
I used to be a huge fan of Java as an OO approach (still have my good reasons) but I got to understand those “clever” ways of programming are just intellectual distractions.
So, my favorite phrase I use to teach others or tell my story is that the simplest designs are the best and FP is all about simplicity.