
Functional programming in JavaScript is an antipattern - allenleein
https://hackernoon.com/functional-programming-in-javascript-is-an-antipattern-58526819f21e
======
coldtea
Funny, but HN oldsters probably remember when functional programming wasn't at
all tied to immutable data structures, and when Lisp and derivatives where
considered enough functional programming, without every discussion of the
topic requiring strictly requiring purity and immutability -- just first class
functions, map, fold, and the like.

~~~
vbezhenar
I was taught in university that functional programming means using functions
as first-class-values, so function can get other function as a parameter.
That's all. You can write functional code with assembler if you want.
Immutability is just another design choice with its pros and cons.

~~~
Dzugaru
I've always thought that functional programming is about structuring your
program in functions and their composition (as opposed to classes) - nothing
to do with immutability either.

As for JS, I've read "Javascript: The good parts" one day and realized that I
can do everything I want using just functions and closures - it's really
elegant imo. (even use this approach in Python sometimes)

------
zumu
I've been doing FP in JavaScript fulltime for a few years now. I find it much
easier than the OOP approach.

My advice to the author is: choose ImmutableJS, Ramda, OR lodash. Don't choose
all three.

I think that is his anti-pattern.

> I could be more productive if I didn’t have to wonder things like ...
> “Should I mutate this variable?”

If you're doing FP the answer is likely 'No.'

~~~
k__
Or?

Ramda doesn't even have the same functionality as Lodash.

~~~
zumu
Excuse the overstatement -- there are sane ways to use the libraries in the
same project. The point was the 3 libraries all prescribe a certain model of
structuring and operating on data. One cannot reasonably expect to use all 3
without some cognitive overhead.

~~~
k__
I see.

I was just reminded of last week, when I needed a utils lib. I read many good
things about Ramda, but then I wanted to debounce a function and it failed me,
haha.

------
lewisl9029
I wouldn't go as far as to call it an anti-pattern, but the lack of native
persistent data structures does make functional programming a decidedly
second-class citizen in the JS world.

We can either choose to use a library like ImmutableJS instead of regular JS
objects and suffer the impedance mismatch and exponential increase in
verbosity, or use regular JS objects and make full copies every time we want
to change any piece of data.

It's a very unfortunate blemish on an otherwise surprisingly pleasant
experience (functional programming in JS), especially when paired with a nice
utility library like Ramda [1].

I tried to look into if native persistent data structures was on the roadmap
for a later version of ECMAScript, but this random proposal on GitHub [2] was
the only thing I could find, and I'm not familiar enough with the
standardization process to be able to gauge how much traction that proposal is
getting.

If anyone else is aware of similar efforts, I'd love to hear about them.

Until something like this makes it into JS proper, I'll be putting my weight
behind ClojureScript.

[1] [http://ramdajs.com/docs/](http://ramdajs.com/docs/)

[2] [https://github.com/sebmarkbage/ecmascript-immutable-data-
str...](https://github.com/sebmarkbage/ecmascript-immutable-data-structures)

------
marcus_holmes
I like Javascript. As a language. It's fun, enjoyable, and I'm productive in
it. There I said it.

I don't mind exploring interesting avenues like immutability, jsx, typescript,
declarative or functional styles. I like that JS has enough flexibility to
make all of these possible.

I get the fatigue about the endless stream of new frameworks, libraries,
approaches, and "new hotness". But I became much more relaxed about it all
when I realised it's all completely optional. I can just stick with vanilla JS
if I want to, and cherry-pick interesting things as they whizz by. It's the
sushi train of programming environments :)

LISP in JS sounds great, I might give it a try. But this does raise a
conundrum... if LISP is the ultimate programming language because you can
write all the others in LISP, then the fact that this is a LISP written in JS
makes it...what?

~~~
keymone
unfortunately this approach does not scale past single developer or multiple
klocs of code unless you're really disciplined, but then wouldn't that
cognitive effort be better spent elsewhere?

~~~
seangrogg
I've seen multiple klocks of code written in Java and C that are taking
minutes to handle database operations, unable to process parallel network
requests, and choking on errors. Watching new features get added is exciting
in the same way it's ensorcelling to watch someone assemble a house of cards.

I'd love a tool that enabled me to spend my cognitive currency how I want to,
but so far all I've found are tools that have disguised their expenses in new
and interesting ways, like tranches of a collateralized debt obligation.

~~~
keymone
i don't think i disagree with you and (i think) neither does the author.
argument (as i understand it) is that rather than piling on features that
don't really fit and have complex interference you could use a better tool.

------
callumlocke
I hate the arrogance of announcing that thousands of developers' work is an
antipattern. This post contains valid discussion of some of the shortcomings
of FP-in-JS, and presents alternatives. That's fine. But everyone has their
own priorities and tradeoffs. The downsides of adopting Clojurescript in my
current situation would outweigh the benefits.

> Clojure compiles to Javascript... So any Javascript job could be a
> Clojurescript job

That's not how it works.

~~~
moron4hire
Maybe it's arrogant to call out valid criticism as attacking the work of
others, rather than just the paradigm.

------
cies
>Functional programming in JavaScript is an antipattern

The article then shows ClojureScript as _an_ alternative.

In the comment section Ken Aguilar mentions two other alternatives: PureScript
and Elm.

But there are more! Bloomberg's BuckleScript (which is OCaml; possible used on
onjunction with Facebook's Reason), GHCJS (Haskell), are two other FP langs
that compile to JS. These two have the added bonus of being strong langs for
performant server-side programming as well.

[http://www.purescript.org/](http://www.purescript.org/)

[http://elm-lang.org/](http://elm-lang.org/)

[https://github.com/BuckleScript/bucklescript](https://github.com/BuckleScript/bucklescript)

[https://facebook.github.io/reason/](https://facebook.github.io/reason/)

[https://github.com/ghcjs/ghcjs](https://github.com/ghcjs/ghcjs)

~~~
weavie
Elm is nice. Really really nice. It make it very intuitive and straightforward
to write well architectured front end code. The compiler tells you straight
away when something is wrong.

I have recently started playing with Bucklescript and am _really_ loving it.
There is bucklescript-tea which is a port of the Elm architecture to OCaml. So
not only do you get the goodness from Elm - intuitively well architectured
applications, but you can do it in a language that can be used everywhere -
not just on the server.

Another worth mentioning is Typescript. Having discovered the joy of types
through Elm and Bucklescript it was a real pain having to go back to maintain
a fairly large javascript code base. My initial thought was to rewrite the
whole thing in OCaml, but that would take months if not years. Instead I have
started moving it across to Typescript. No code needs rewriting, I can just
slowly one file at a time start adding typing information in. I have found a
lot of subtle bugs and bugs I knew existed but was tearing my hair out about
just easily presented themselves via compiler messages.

I will never go back to raw javascript again.

~~~
vog
Curious question: Why did you choose Typescript over Flow? Flow's type system
is better designed. Also, Flow's annotations are _really_ optional, as in:
Generating JS from Flow means throwing away the annotations. Nothing else, no
code generation at all.

~~~
weavie
I struggled to get Flow working on FreeBSD. Typescript worked straight away,
so I just went with it.

------
timruffles
Not well reasoned. Mostly of the complaints boil down to 'not knowing' whether
a given piece of data is mutable or not.

If you're doing FP with immutable data, there is no ambiguity: you never
mutate. Doesn't matter which language you're in, nor whether the data-
structure is mutable or not (e.g Redux mostly uses normal mutable JS objects,
with the spread operator to avoid mutation when returning a new state).

------
bestest
In my opinion the top rated comment is right on point there: "I’d say that
ImmutableJS is your anti-pattern here, not FP in JavaScript as a whole."

~~~
yomly
I agree - I use ImmutableJS in one of my projects and the pros vs cons are
substantial - it's hard to keep track of when something is Immutable or not
and it has been slowly infecting more and more of my codebase.

I would be interested in hearing strategies of mitigating this, my first step
has been to let Immutable creep through the project, but adopt a convention of
creating a layer through which guarantees JS output - anything that is logic
related in my redux layer is Immutable, anything which is in my presentational
react layer is JS.

The difficulty then, is at input points where I need to always remember to
deal with nested data structures too.

It feels like a type checker would be of great use here to add additional
guarantees about any data

~~~
acemarke
Interesting you should say that. I wrote a Reddit comment about a year ago
listing reasons why I generally advise against use of Immutable.js, and the
"infectious" API is exactly one of the reasons that I listed (
[https://www.reddit.com/r/javascript/comments/4rcqpx/dan_abra...](https://www.reddit.com/r/javascript/comments/4rcqpx/dan_abramov_redux_is_not_an_architecture_or/d51g4k4?context=3)
).

Also worth noting that if you are going to do Immutable -> POJO conversions,
you should avoid using `toJS()` as much as possible. The conversion process is
expensive, _and_ it always creates new object references. Either use
`getIn()`, or use memoized selectors to ensure the conversion only happens
when the data actually changed.

~~~
yomly
Yep memoized selectors was on my list of things to look at - great tip!

My philosophy is when providing the POJO from the immutable data structure is
to select the absolute minimum from the bigger object, which I suppose is in
line with your advice on using getIn

------
skrebbel
This post struck home with me. But I realized that the root cause for the
problem is the many _ways_ to do FP (and, notably, immutable) in JS. What
doesn't help here is that all ways have some major downsides. ImmutableJS has
a huge API that works pretty different from everything else. Ramda changes all
the time. Lodash, by virtue of _not_ changing all the time ever since
underscore was first released, has some pretty weird and unexpected function
names and behaviors.

If JS had more builtin functional primitives (i.e. well beyond
Array.prototype.map and friends) this problem would be much smaller.

Similarly, I think another way out of this antipattern is to settle with the
team on a single way to do FP. This disqualifies ImmutableJS by definition,
because 3rd party apis tend to want arrays and objects. But most other options
are open, I guess.

------
dwaltrip
It's an anti-pattern to call some "overly broad category of things" an anti-
pattern.

------
andriesm
The author asks WHY hasn't clojure caught on if it is great.

I think I have a better answer than his conclusion that it aint popular
because people shun things that aren't popular.

(1) coding when EVERYTHING is immutable by default is a royal pain in the
arse.

(2) Coding directly in Abstract Syntax Trees is not pretty, there is a reason
why most programming languages don't look like lisp.

~~~
kazinator
Coding in nearly the cleanest possible notation for abstract syntax trees is
simply breathtaking.

The reason a lot of programing languages don't look like Lisp is that most
programming languages don't have anything interesting _semantically_ going on.
Their authors' primary source of intellectual pride is the work that went into
the syntax.

Part of it is CS education. It is drilled into the heads of CS undergraduates
that programming language design involves tokenizing, and parsing with LALR(1)
or what have you. The idea that you're going to have those pieces there if you
design any language for any purpose is deeply ingrained, like the idea that no
matter what you will be coding, you're going to have modules with functions
that have local variables, and that there will be a edit-compile-debug cycle,
and so on.

------
flor1s
Seems like the author discovered the curse of the excluded middle:
[http://queue.acm.org/detail.cfm?id=2611829](http://queue.acm.org/detail.cfm?id=2611829)

~~~
brianberns
Interesting article, but I think F# (and other impure FP languages) show
pretty clearly that you can have "mostly functional" programming without
causing chaos.

------
egwynn
Previously
[https://news.ycombinator.com/item?id=14602448](https://news.ycombinator.com/item?id=14602448)

It was widely panned in the comments then, too.

EDIT: looks like it was posted even earlier and nobody payed attention:
[https://news.ycombinator.com/item?id=14590127](https://news.ycombinator.com/item?id=14590127)

------
memracom
What has happened to Javascript is the same thing that happened to other
fundamental high-level languages before them. It has changed from a high-level
language to an assembly language just like C and Java.

Of course you canb choose to live in the past and keep on hand-rolling your
Javascript just like others do with C and Java, but the world has changed. In
today's world we write our code in a high-level language and have an
optimizing compiler emit the assembly/machine code that our compute engine
executes. The details are a bit different for different compute engines.

For C, the high-level compiler might use the same backend as the C compiler to
emit machine code for x86 or ARM, but it will make integrating C libraries
easy to do. For Java, the high=level compiler may emit Java class files
directly but it will make integrating Java libraries easy to do. For
Javascript you have Scala.JS and Clojurescript emitting optimized Javascript
because the compute engine executes that directly.

As a developer it is worthwhile knowing all these low level details of
internals because you will need to debug issues with that level of knowledge.
But your main job should be to implement tested stable functionality for the
users of your application. No matter how much you like C or Java or
Javascript, it is always faster, more efficient and more reliable to write in
a truly high-level language that incorporates the best knowledge of the latest
research in Computer Science.

As a Javascript expert you may find that Clojure slows you down at first. That
is the investment period. Then you start picking up the tempo, enter the
payback period, and people start whispering about you being a rocket scientist
or 10x developer.

Of course you could just stick woth Javascript but others who know how to roll
with the punches will change with the times and win the 10X crown. Not because
they are better, but because a true 10x developer is just a person who uses
the best tools. They used to say that the suit makes the man. Nowadays it is
the tools that make the 10X developer.

~~~
rf15
> It has changed from a high-level language to an assembly language just like
> C and Java.

Neither C nor Java are assembly languages. What are you trying to express
here?

> No matter how much you like C or Java or Javascript, it is always faster,
> more efficient and more reliable to write in a truly high-level language
> that incorporates the best knowledge of the latest research in Computer
> Science.

> always faster, more efficient > truly high-level > best knowledge > latest
> research

I uh.... what?

------
kentor
I have a few large React apps that have been using mostly Immutable.JS from
the very beginning, so I rarely run into issues where I need to think whether
what I'm dealing with is an Immutable.JS object or plain JS objects. I can see
an issue if you are incrementally converting an app to Immutable.JS and
dealing with a mix of plain JS objects though.

I have heard criticisms of lisp macros as making it a write-once language. If
you're not working on a team then maybe it's fine, but other people aren't
gonna want to figure out how your macros work.

~~~
memracom
This is why a professional developer needs to document their code. If they
don't do that, then they are NOT a professional.

Plus they are selling themselves short. If you want to fully learn something
you must teach it. By documenting your code you are teaching the other
developers on the team and this will lead you to much deeper understanding
than the hackers who churn out code all day.

------
shamas
Just a note on immutability, I feel like this is pretty straightforward in ES6
(map, spread operator, and Object.assign) and will be more so with spread-
operator for objects in ES7. Am I missing something?

I mean, you still have to THINK about whether you need to keep something
immutable or not, but that's the difference between a junior developer and a
more seasoned engineer, right?

~~~
zurn
This is the C++ trap - you keep piling on more features to the language and
then you can answer some criticisms by saying "just use this subset". But this
is not how the usage of programming languages pans out. Programmers can't
agree even with themselves (=consistency) about what subset to use, or have
accidents with it. And libraries / practices in that PL's culture can't rely
on those conventions and subsets, so they can't really leverage the benefits.
It's basically inventing your own mini-language with borders drawn in the sand
and not enforced by any tooling.

------
escherize
Coming from Clojure to ClojureScript, I must say I have had some hard times
with the dynamic, mutable, APIs that a lot of js libraries have.

Even though interop is possible and not difficult, I am so much more
comfortable using cljs wrappers (there are a lot) or in my part of the world
(cljs - land). One reason is that the clojure way (tm) is to use immutable
data and pure functions. It bugs me to enact stateful changes.

One way out is to have a datastructure that stores the state of the entire
browser (what url am i on, what's in local storage?) and change the
datastructure while some unspeakable side effecting function observes and
updates either localstorage, or browser history, or etc.

In Clojure 90% of my code is datastructures, manipulating them, and sending
them back. Partly because servers tend to be way less stateful than UIs, and
partly because it feels like there is more to explore in Clojure without going
into java, compared to cljs/js.

------
zurn
There are so many JS/Node developers now, and I have worried that JS will ruin
dynamic languages for a lot of people, so it's encouraging to hear this
written about ClojureScript: "As an average Javascript/Node developer, it
hasn’t been difficult for me to learn the language or the ecosystem"

------
grandalf
I think the biggest weakness in the ecosystem is that it's cumbersome to map
between different approaches to immutability. I'd like to be able to use
clojurescript for some stuff, reason/bucklescript for other stuff, and
immutable.js for still other stuff without having to jump through hoops when
passing immutable data around.

Are there immutability constructs in flow or typescript that would allow
libraries to conform to a type interface for conversion?

------
personomas
Don't use immutability in JS. Though, use Ramda, since it's much better than
plain JS.

This, then, would solve almost all of the problems mentioned in the article,
yet remain functional friendly.

Ramda functions never mutate the object by always returning a new object, this
is very simple to reason about, and it's pretty close to immutable programming
without the overhead yet only one API.

------
xamuel
One of the most annoying JS FP antipatterns is when people use fancy 3rd-party
currying when a simple ES6 fat-arrow would suffice.

"_.curry(f,0)" instead of "x => f(0,x)"

------
vorotato
Don't use a weakly typed language use instead my dynamically typed language!

------
klochner
The flagged comment was accurate - post claims FP in javascript is an
antipattern, but then says FP is the most sane way to write javasript.

Ergo author is claiming javascript is an antipattern, tldr clojurescript.
/shrug

~~~
keymone
that's a misrepresentation. post claims FP in javascript is an antipattern, so
use FP language that transpiles to javascript instead.

~~~
klochner
From the post:

    
    
        Basically, write Javascript without functional programming techniques. That doesn’t seem like a good solution.
    

So . . . what am I misrepresenting?

