9 ms·
Functional programming in JavaScript is an antipattern
- crb002 9y agoJavaScript is an antpattern.
- klochner 9y agoThe 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 9y agothat's a misrepresentation. post claims FP in javascript is an antipattern, so use FP language that transpiles to javascript instead.
- klochner 9y agoFrom the post: Basically, write Javascript without functional programming techniques. That doesn’t seem like a good solution. So . . . what am I misrepresenting?
- lerax 9y agoJS is an antipattern for itself.
- flor1s 9y agoSeems 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 9y agoInteresting article, but I think F# (and other impure FP languages) show pretty clearly that you can have "mostly functional" programming without causing chaos.
- marcus_holmes 9y agoI 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 9y agounfortunately 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?
- marcus_holmes 9y agoI get the impression that the OP wasn't talking about a team environment either? I could be wrong...
- seangrogg 9y agoI'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 9y agoi 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.
- zurn 9y agoThere 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"
- dwaltrip 9y agoIt's an anti-pattern to call some "overly broad category of things" an anti-pattern.
- escherize 9y agoComing 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.
- bestest 9y agoIn 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."
- deleted 9y ago[deleted]
- yomly 9y agoI 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 9y agoInteresting 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_abramov_redux_is_not_an_architecture_or/d51g4k4?context=3 https://www.reddit.com/r/javascript/comments/4rcqpx/dan_abra... ). 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 9y agoYep 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
- kentor 9y agoI 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 9y agoThis 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.
- skrebbel 9y agoThis 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.
- lewisl9029 9y agoI 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-structures https://github.com/sebmarkbage/ecmascript-immutable-data-str...
- memracom 9y agoWhat 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.
- pvg 9y agoIt has changed from a high-level language to an assembly language just like C and Java. That hasn't happened to either C or Java.
- cousin_it 9y ago> 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. Latest research? Clojure is a Lisp family language, JS is an Algol family language. Both Lisp and Algol are from the sixties. Algol family is just more popular, so when people encounter Lisp family for the first time, they think it's "new".
- andriesm 9y agoThe 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.
- eropple 9y ago> coding when EVERYTHING is immutable by default is a royal pain in the arse Not sure I'd agree with that. Scala is a pain to write at times, but it's not because of the immutable data structures--indeed, the APIs are structured such that it's pretty painless. And while under the hood Kotlin's "immutable lists" aren't actually immutable (they're just ArrayLists, the interface is more akin to C#'s IReadOnlyList<T>), the API they present on top of it makes this pretty straightforward. In both cases, you can do mutable things, but it's extra work. I tend to think it's more of a Clojure-specific thing, and I think your #2 is more to the point: people don't use Clojure because it looks funny and is foreign to read for people who don't already know Lisps, that's all. (I've used Clojure, but I don't claim to "know" Clojure. YMMV.)
- js8 9y agoI have a different theory about this. Most people are practical and don't like too much abstractions. So any language that lets you make abstractions, no matter how beautiful it is internally, and no matter how useful they can be in coding, such as Lisp, Forth, Scheme, Haskell, Clojure.. (you name it) will not be popular, sadly. Weird thing is that functions are, for the most part, also a tool to make abstractions, but for some reason, the perception of them is different. I came to this conclusion after discussions with people I know who don't like these languages, and I now think it comes down to this.
- dozzie 9y ago> (1) coding when EVERYTHING is immutable by default is a royal pain in the arse. Is it really? Because I haven't noticed writing my Erlang.
- TeMPOraL 9y ago
- cies 9y ago>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
- bonesss 9y agoTo add to the list: F# has a JS transpiler via fable http://fable.io/ http://fable.io/ (Elm and its architecture has even been recreated to a degree - https://github.com/AnthonyLloyd/Elm https://github.com/AnthonyLloyd/Elm)
- davidgl 9y agoI believe Elmish is the current best Elm architecture for fable: https://fable-elmish.github.io https://fable-elmish.github.io
- weavie 9y agoElm 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.
- zumu 9y agoI'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.'
- nidu 9y agoAgree with this one. Reading article i though "Why don't you just drop ImmutableJS in favor of pure js collections with lodash/fp?". I felt the same when were using ImmutableJS. Two collection libraries across the app is very inconvenient. One could build entire infrastructure with ImmutableJS and restrict native collections to only system boundaries, but in js you usually befriend a lot of libs which makes it complex.
- k__ 9y agoOr? Ramda doesn't even have the same functionality as Lodash.
- dagw 9y agoThere is however enough overlap that using both ends up being a mess.
- zumu 9y agoExcuse 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__ 9y agoI 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.
- coldtea 9y agoFunny, 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 9y agoI 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.
- Asooka 9y agoNot sure why you're downvoted. That's literally the way I learned it first, too. Functional <=> "can use functions as values".
- mbrock 9y agoFunctional programming is also a family resemblance thing: you can't necessarily give a strict definition, any more than you can define "blues music". I'd say functional programming is a tradition that draws from sources like denotational semantics, lambda calculus, Church, Landin, etc etc. There are some different subspecies of functional programming: the Lisp family that draws from AI engineering, MIT, Emacs, actor research via Scheme, etc; the ML family that draws from typed lambda calculus, inductive definitions, and logical proof systems; and more, like concatenative languages. JavaScript was always inspired by functional programming, as evident by Eich's claim to have tried to sneak in a variant of Scheme dressed up as Java. I always use lots of anonymous functions, higher order functions, and nonmutating transformations in my JS, without using any special immutability libraries, and I'm pretty happy with it.
- Dzugaru 9y agoI'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)
- timruffles 9y agoNot 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).
- grandalf 9y agoI 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?
- callumlocke 9y agoI 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 9y agoMaybe it's arrogant to call out valid criticism as attacking the work of others, rather than just the paradigm.
- kungito 9y agoWhy ClojureScript and not PureScript?
- egwynn 9y agoPreviously 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
- xamuel 9y agoOne 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 9y agoDon't use a weakly typed language use instead my dynamically typed language!
- personomas 9y agoDon'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.
- shamas 9y agoJust 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 9y agoThis 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.