5 ms·
functional code tends to be harder to write, understand, and debug, I've heard just the opposite. It's likely harder to write if you've being doing procedural
by jamesbritt 13y ago
functional code tends to be harder to write, understand, and debug,
I've heard just the opposite. It's likely harder to write if you've being doing procedural code for a long time but the elimination of state, the referential integrity, makes things easier to reason about and easier to debug in the long run. The ability to compose larger methods from numerous small, state-free methods s a big win as well.
I've never found a compelling reason to use the FP paradigm in JavaScript.
My motivation to write more FP-oriented code is to reduce the number of WTF moments.
- crazygringo 13y agoDo you (or anyone) have any links to web-centric JavaScript programs written this way? My confusion comes from the fact that I feel like most of the web-based stuff I deal with has to do with state -- the state of the DOM, the state of the database, the state of a connection, etc. All the FP I read about always uses simple algorithmic examples (like factorials, Fibonnaci, etc.), and I've never been able to find a good example of a real-life webapp, say, that is written in a functional manner, that is a good example of how a program can be easier to write/maintain/debug/etc. Pointers?
- tif 13y agoSorry, I don't have any links to share off hand. But I do have some comments: Of course we all have to deal with state, otherwise our programs are essentially useless. As a casual FP practitioner, I try to make web-based design decisions that minimize the number of places where I handle state. The majority of the functions that I write just take values and return some referentially transparent transformation of their inputs. So for me it's really more about black-boxing and forgetting (once it's thoroughly tested) about 90% of my code, thus hopefully limiting the scope of my state related wtf moments to the other 10%. There was a time in my life where I thought that this sort of design was obvious and everybody was doing it. I've since learned, through lots of painful maintenance and debugging, that this is not at all the case :/
- dxbydt 13y ago> minimize the number of places where I handle state The idea isn't to minimize places where you handle state. If you want to manage state, use a State monad. Here are some examples in Scala - http://stackoverflow.com/questions/7734756/scalaz-state-monad-examples http://stackoverflow.com/questions/7734756/scalaz-state-mona...
- tif 13y ago> use a State monad Sure, I agree that that's the proper, academic, and purely functional way to handle state. Whether or not that introduces its own set of problems I'll leave as a thought exercise for the reader. The key phrase in my comment was "casual FP practitioner." I'd only hoped to show OP a way to painlessly introduce some principles from the FP world , ones with, IMO, real and immediately obvious benefits, without cramming "monads and combinators and category theory oh my!" down his or her throat. I tend to prefer simple, dumb, readable code to academic elegance, and I've found that treating data as immutable (whether it actually is or not under the covers) and preferring data transformation to state manipulation are two ways to get closer to that goal.
- cgag 13y agoThe vast majority of your code probably isn't manipulating state, or doesn't need to be. You can have well defined boundaries where you're dealing with state. Read from the database, pass those values through a bunch of pure functions, then eventually rewrite to the database. You only have side effects when you intially read from and eventually write to the DB. Same goes for manipulating the DOM, and almost anything else.
- jdmichal 13y agoHere's an example that I'll put in here. Let's say you have an array of strings, and you want to create a UL element with each string in an LI. You can do this with a for loop just fine and everyone's happy: var ul = document.createElement("ul"); for(var i = 0; i < strings.length; ++i) { var text = document.createTextNode(strings[i]); var li = document.createElement("li"); li.appendChild(text); ul.appendChild(li); } However, you can pretty handily turn this into a series of functional transformations: var ul = document.createElement("ul"); strings.map(function (string) { return document.createTextNode(string); }).map(function (text) { var li = document.createElement("li"); li.appendChild(text); return li; }).each(function (li) { ul.appendChild(li); }); The next step would be decomposing the functions into their own generic entities: function toTextNode(string) { return document.createTextNode(string); } function wrap(tag, child) { var wrapper = document.createElement(tag); wrapper.appendChild(child); return wrapper; } function append(parent, child) { parent.appendChild(child); } // Helper function to provide partial-application. // This is usually built into functional languages. function wrapIn(tag) { return function (child) { return wrap(tag, child); }; } function appendTo(parent) { return function (child) { return append(parent, child); } } var ul = document.createElement("ul"); strings.map(toTextNode).map(wrapIn("li")).each(appendTo(ul)); And now you have a bunch of general-purpose, easily-tested functions that you can apply in similar situations all over the place.
- mattmanser 13y agoI generally don't like double posting in a thread but... 7 lines to 30 lines, with a never-ending call stack of despair if anything ever does go wrong. That imo, is really shit code.
- BrandonM 13y agoBut the 5 helper functions are all very reusable, making the code specific to this particular usage shrink from 7 lines to 2. With a handful more usages like this, they can have a huge decrease in code size. And later on, seeing "map ... map ... each", it is immediately obvious that we are iterating over the entire array, producing new values, and then doing something with each of them. With the explicit for-loop, the unique logic is mixed in with boilerplate iteration code. Of course, by now, for (var i = 0; i < strings.length; i++) { /* something with i */ } is a common pattern for us, and our brains skip right over it. Fundamentally, though, terms like "map" and "each" are much closer to the way we approach the problem. Do you really tell yourself, "OK, I want to start with i set to 0 and increment i to match each array index, then for each of those, I'll use i to extract the ith array element, then..."? There is a lot of extra baggage going on (WTF does i have to do with creating a bullet list?), with a lot of room to make a mistake; we've just trained ourselves to overlook it. That's a huge benefit of functional programming IMO: replacing a bunch of repetitive, error-prone patterns with a higher-order function call. On a side note, it's really unfriendly to call a comprehensive, helpful example "shit code." If you can relate your opinion in a slightly more respectful way, people will be more apt to listen to you.
- jshen 13y agoThis book helped me answer the same question: https://leanpub.com/fp-oo https://leanpub.com/fp-oo This talk is pretty good as well, but I already had a decent grasp on FP before watching, so it might not be as good before having such an understanding, http://vimeo.com/34522837 http://vimeo.com/34522837