
How to stop functional programming - zeckalpha
https://brianmckenna.org/blog/howtostopfp
======
braythwayt
My methodology for avoiding this confusing “functional” programming:

1\. Write:

    
    
      function add (a, b) { return a + b; }
    

2\. Refactor to object:

    
    
      class AccumulatingIntegerWidget {
        constructor (...numbers) {
          this.accumulation = 0;
          this.accumulate(...numbers);
        }
        accumulate (...numbers) {
          for (const n of numbers) {
            this.accumulation = this.accumulation + n;
          }
        }
        getAccumulation () {
          return this.accumulation;
        }
      }
    

Presto! It’s stateful and object-oriented and handles future cases like adding
three numbers, even though WeArentGonnaNeedIt!

If this does not satisfy, I progress to making my classes observe each other
and update themselves automatically. “We’re doing two-way binding!” I exclaim
proudly, while leaving debugging as an exercise for my colleagues.

~~~
goalieca
This is one reason I hate our industry. No one engineers anything. They all
just abuse OOP so that code is packaged together in some arbitrary heirarchy
and then refactor it every single time a user story is added.

~~~
pekk
If we forced everyone to switch to Haskell, do you think this would really be
any different? People would still do the bare minimum to implement the latest
user stories, because that is literally what the boss is paying for.

~~~
johan_larson
We force everyone to switch to Haskell. OK. Even the fair-to-mediocre
programmers? Yes. Who tend to program by copypasta and change stuff until it
gets the right answer? Yes.

Run away. Run far, far away. You don't want to see what "design patterns" and
urban legends these people layer on top of Haskell to make it intellectually
manageable.

~~~
Joof
I remember being a sophmore in college and I understood the basics of haskell
(not really monads yet) and we worked in groups. My partner was very
intelligent, but didn't have a grasp on the language at all.

For the final project, we had a problem that I didn't understand well, but he
couldn't use the language effectively. We ended up having him work out the
problem incorrectly in a shared notepad and I would refactor his broken code
into something that worked. It was a mess. I'm pretty sure I've seen worst
things you can possibly build in haskell -- and they are bad.

------
the_af
I've had some success explaining, mainly through pair programming, code
reviews and an educational use of the console, the basics of FP-ish constructs
such as map, fold, filter, pattern matching, control of side-effects, etc.

It's amazing what you can do if, instead of assuming an arrogant attitude, you
take your time to teach other programmers and review their code to explain how
to avoid pitfalls, and accept that some people will remain unconvinced about
some aspects of FP that you cannot adequately justify (a good reason to seek a
better understanding of those justifications!). And it has the added benefit
that this situation will never reach your manager, so he/she doesn't have to
get involved :)

~~~
sundarurfriend
> such as map, fold, filter, pattern matching, control of side-effects, etc.

 _map_ and _filter_ have become natural parts of my thinking, _fold_ too is
getting there, and avoidance of side-effects even gives pleasant tingles to
the math-guy in me, but I've never understood what pattern matching brings to
the table. In my admitted limited understanding, they seem to be a syntactic
sugar for _if-elseif_ branching that ends up scattering the logic of a
function to multiple blocks of code, while bringing no obvious benefit
compared to them.

Since you mentioned your success explaining the justifications for these
things, I thought I'd take advantage of that here. :) Could you explain what
I'm missing with pattern matching?

~~~
kinghajj
Pattern matching is not just sugar for an if-elseif chain, since compilers
will check for exhaustiveness. This is especially important when used with sum
types (which are the primary motivator for this feature):

    
    
        data Thing
          = Foo String
          | Bar Int Double
          | Baz String String
    
        case thing of
          Foo s -> putStrLn s
          Bar i f -> -- ...
          Baz s1 s2 -> -- ...
    

If you later add another variant to Thing, the compiler will check that all
pattern matches against it account for the new case. (Wildcard matches
alleviate the need always to handle every case.) An if-elseif chain, however,
would still compile after adding the new variant, so you must track down the
usages manually.

~~~
Cthulhu_
Aha, thanks for that bit, I didn't realize that. I thought Swift, which has a
switch/case statement that does not have automatic fallthrough and which has
to be exhaustive, was special in that regard. (Although in Swift you can in
most cases just do a 'default' case too, not sure how that works with pattern
matching)

~~~
lmm
This is why functional programmers get so grouchy - it's great that Swift has
picked up this kind of functionality, but ML family languages have had it for
40 years now :/. Worse is when a feature gets dismissed as "incomprehensible"
for years until it gets picked up by some fashionable language and then
suddenly everyone's excited about it.

~~~
jnbiche
Pattern matching is awesome, and ML definitely gets the credit here for
putting it into practice, but matching is arguably not even part of the
functional paradigm. Lots of non-functional languages could _greatly_ benefit
from pattern matching and sum types.

And indeed, when you look at a language like Nim and Swift, that's exactly
what happened. Rust, too, although Rust is arguably a functional language.

~~~
AnimalMuppet
Rust is arguably a functional language? I'd _love_ to hear the argument that
says that it is...

~~~
jnbiche
> I'd love to hear the argument that says that it is...

[http://science.raphael.poss.name/rust-for-functional-
program...](http://science.raphael.poss.name/rust-for-functional-
programmers.html)

I personally think Rust isn't functional, but rather multi-paradigm with a
strong functional influence. But if you were to add TCO and a few other
features, I think Rust _would_ be a full-blown functional language, so it may
get there yet.

In any case, it's useless arguing over (should have known better than say
anything), so this will be my last word on the issue.

~~~
AnimalMuppet
I wasn't actually looking to argue; I was looking to understand.

And I guess it's going to come down to "whose definition of FP are we using?"
If FP means "I can write in a functional style", there are many more
functional languages than if FP means "I can _only_ write in a functional
style". That debate - about whose definition of FP is correct - is one that I
can't bother to care very much about.

------
agentgt
I have never seen a manager complain about the use of functional programming.

What I have seen is amazingly intelligent programmers with FP backgrounds (who
I pushed to hire) try to write in languages that are sort of FP (ie Java and
Javascript). They end up writing code that is not canonical (which I don't
mind) and using academic/haskell variable names (ie single letter variable
names which I do mind heavily) and then fail to write any documentation
(anecdotal observations).

I'm not saying this always the case but I have seen it quite a few times.

~~~
boothead
Isn't that a bit like hiring a sniper and then sending them into battle armed
with a nerf gun? ;-)

~~~
jawilson2
Probably more like sending them in with an AK-47. Each is great at what it
does, but you will fail if you assign a person trained with a different weapon
to the wrong task, and ask them to use an AK47 like a sniper rifle, or vice
versa.

------
rnavarro
Well, if the functional code people are complaining is on the same level as
the one the author used on the post, then I agree that a quick pair session is
enough to "solve the conflict".

But IMO there is problem when (assuming Scala here) you include a library like
Scalaz on the codebase, and then start using more abstract functional
concepts. While I think these concepts are amazing, I usually don't use then
on my day job as I know that my team don't have the knowledge nor the timing
to quickly grasp such concepts without impacting the project's pace.

~~~
incepted
We need more reasonable people like you :-)

------
incepted
Sounds like the author is sharing a personal story here. I'm guessing he wrote
some FP code and one his coworkers complained about it.

OP, two pieces of advice:

\- Ask yourself why your coworker went to your boss instead of talking to you
directly

\- Work on your communication skills with your coworkers. I'm guessing you
have an attitude that's rubbing them the wrong way (I've seen a lot of this
coming from people who are trying to impose advanced techniques upon a team
that's not ready for those).

It's startling how so many bright programmers possess so little social
awareness.

~~~
cname
It's amazing how you can tell so much about a person just by reading one short
article. To me, your advice comes across as condescending. Maybe you need to
work on your communication skills too?

Regardless, what's the practical solution to managing complexity in a team
"that's not ready"? At some point, most projects get complex enough that
you're going to have to do _something_ that someone is going to find
confusing. It could be functional, OO, whatever.

If you've got complexity to manage and can't use reasonable tools to manage
it, you may have bigger problems. Pandering to the hypothetical lowest common
denominator developer isn't going to help much, because they're probably not
going to "get it" anyway and will likely make a mess in any case.

~~~
lmm
Brian McKenna is a public figure who people could easily have encountered in
other ways.

In my experience many functional programmers, myself included, _do_ generalize
where they don't need to (e.g. writing a function to accept any F[_]: Foldable
when it's only ever called with List). At which point asking them to justify
the abstraction is entirely justified. Conversely in cases where fancy
functional techniques really are improving maintainability it's usually pretty
easy to demonstrate this by comparing two implementations side by side.

~~~
gb
An advantage of using the most general signature possible is it restricts the
things you can actually do with the values involved, which can make it easier
to provide correct implementations.

------
SCdF
I've found usually if you cleanly explain what you're doing and go through
some examples people are willing to learn. Not sure if I've been lucky in that
regard, but I've never had the problem this guy clearly has before, with
integrating functional ideas into code.

I've also found that quite often I actually am at fault because it is
reasonable to want to break up dense code into smaller understandable blocks,
and while you _can_ write an entire function (or application) as one statement
in an FP style, your job isn't to show how cool you are, it's to write code
that your peers can maintain.

_(Like that last paragraph. It probably should have been more than once
sentence. We live and learn.)_

------
sdegutis
This satire is more sad than funny, because it's true. A manager's job isn't
to understand good code, it's to understand business and to know how to
effectively get rid of road-blocks for programmers on the team. But how can
they make decisions about how to make progress easier/smoother for every
programmer, if they don't understand programming?

It's kind of like when my kids are arguing without being able to solve it on
their own, and I hear it from my office, and have to go over there to
potentially solve the problem for them. What if they're arguing over a dispute
over Pokeyman cards? I don't know anything about Pokeyman, and I can't learn
well enough to give helpful advice or make firm rules on the spot.

It seems like the best solution in both cases is to trust the person who's
most "senior", either the senior developer or the oldest kid or whoever, to
make a judgment call to know what to do here. Probably the other programmer
should be brought up to speed on _how that code works_ so when they encounter
it next time, it's not confusing.

Is that always practical or even possible? Probably not in a large corporate
setting. But in smaller companies, I'm confident it probably always is. Of
course, so long as the code isn't _intentionally_ clever. As long as it's at
least _trying_ to be clear what it does, that should be good enough. But
intentionally clever code should almost always be rewritten, because it's
usually so clever that even the author can't understand what it does in 6
months' time.

~~~
zaphar
There is an even better approach than trusting the most senior that will have
a longer term payoff. The dispute is usually caused by a lack of people skills
in one or both of the parties. If you can instead take this as an opportunity
not to resolve a pokemon dispute but instead to teach dispute resolution
skills to both then you don't need to know enough pokemon to resolve it. And
the next time a dispute comes up around something you don't have enough
information to be authoritative about the involved parties might be able to
resolve it themselves.

------
catwell
Adding two numbers together without being pure? Isn't that how we always do
it?

    
    
        MOV edx, 1
        MOV adx, 2
        ADD eax, edx

~~~
wiredfool
Does that actually work?

------
kaio
Welp. The code would add the user himself as his own coworker in both
versions.

I'm a Java programmer by day, but i have definitely learned a lot by writing
some "functional" (i.e. in a "functional" language) code as well. But this is
just concepts. You can also take those concepts and write clean (and not too
bloated) OO code. I really don't get what all this exaggerated "functional
programming" vs. "bad object-oriented enterprise code" ranting is good for

------
kelvin0
I sense a little bit of a condescending attitude in such posts, and that does
not help 'non-fp' progs to want to join the super world of fp elite
programming. Personnally I've started learning Haskell and I love it. But
having a denigrating attitude towards OOP-ish programming is simply polarizing
and does not help the 'cause' ...

------
falcolas
I realize this is mostly frustrated satire - but it is an actual issue when
working with coders of different skill levels.

The solution is to simply drop the use of flatmap (or any other function which
eliminates loops). In my experience, that level of abstraction is the kind of
thing which confuse new developers who have not (yet) been exposed to the
terminology introduced by functional programming. It comes across as "clever"
and "obfuscated". And it really is quite clever - you turn a 4 line for loop
with accumulators into a single line of code. But it's also legitimately
obfuscated as well, until you grok how flatmap works.

Ultimately, a for loop can be understood by almost any programmer you will
encounter. There's more code, it does the exact same thing as a flatmap, but
(as the OP points out) the function is still pure.

~~~
pklausler
It is counterproductive to cripple the programmers on your team who can handle
abstraction to avoid confusing the ones who can't. Why turn 10x coders into 9x
coders or worse just to retain your 1x coders? Or work with the ones having
trouble with a pattern until they get it?

~~~
steven777400
That's the management decision in the article. And I make the same decision.
We're not an organization that attracts nor hires rockstars (or, as you say,
10x coders). We have a couple really sharp folks but are predominately staffed
by "1x" coders. Therefore, it is important and the responsible thing to do to
write all code so that it can be understood and maintained by a 1x coder.

Even if it is being written and currently maintained by one of our sharper
folks, people move on or change roles, and projects shift to other staff for
long term maintenance. Who's going to be maintaining this project in 2-4
years? This project needs to be written with them in mind.

~~~
Jtsummers
I have to ask, where do you draw the line? I had a team lead that disliked me
writing things like (in C#, been a bit so forgive errors):

    
    
      List<AClass> original; // perhaps as a parameter to the function
      List<AClass> filtered = original.Where(x => x.Field > 10);
    

Arguing that I should instead have just used for loops (showed him foreach and
he agreed that that was better, at least) like:

    
    
      List<AClass> filtered = new List<AClass>();
      foreach(x in original)
        if(x.Field > 10) filtered.Add(x);
    

Ok, so it's _only_ two lines longer (three if you split the if and its effect,
5 if you also add in braces, 7 if you put opening braces on their own lines).
The `Where` version is not that complicated, and only requires understanding
one (potentially) new concept for programmers, namely anonymous functions.

Wouldn't the briefer, but still clear, code be preferable for maintenance?

~~~
steven777400
Yes absolutely. I don't say "no functional constructs" nor does anyone else
here that I know of. However, composite LINQ statements, especially involving
aggregation can and do become confusing. Obviously it's a judgment call but in
many cases, breaking out a complex expression into incremental, imperative
steps can and does make it clearer.

The "rule" I apply is "code should be written primarily for people to read and
only incidentally for machines to execute" which, although very subjective,
provides a good foundation for everyone to start from.

------
annasaru
I think a lot of the abuse happens in Java, and java-derived languages. There
is a culture,and the more lines of code you have , and the more classes you
have , the better. The language environment and frameworks only re-inforce
that stuff. Scala is (I guess ) functional - particularly when contrasted to
Java.

In his example, I suspect he is conflating that one-liner chained function
call with functional programming? Sort of like how coders like to use ternary
one-liners especially when they first learnt them (and end up with unreadable
code). But his first snippet is obviously simpler, compared to the OOP-cruft
of the second and third snippets.

As more Java programmers migrate to coding in Python, they are bringing that
toxic culture in to Python too - where boilerplate and sugar were relatively
less.

Its like everyone is doing rocket science, which is despicable, given we are
mostly coding CRUDs.

Any language is susceptible to abuse, its also a human trait to de-simplify
something to gain a fake intellectual satisfaction.

------
relevate
This is where I think LINQ does a good job.

    
    
      var coworkers = departments.selectMany(department => department.employees);
    

Nearly equivalent to the Scala code, but uses more approachable keywords like
`select`, `selectMany`, and `where` instead of `map`, `flatMap`, and `filter`.

~~~
douche
It makes a lot of sense in .NET land, because it maps to SQL, which people
tend to have some kind of grasp on.

Although that LINQ expression syntax can go die in a fire. It's a great way to
end up with people using borked up joins in Linq-to-SQL and EF that don't work
the way they think they do, rather than the actual foreign-key relationships.

------
lacksconfidence
s f g x = f x (g x)

k x y = x

b f g x = f (g x)

c f g x = f x g

y f = f (y f)

cond p f g x = if p x then f x else g x

fac = y (b (cond ((==) 0) (k 1)) (b (s (*)) (c b pred)))

~~~
js8
You don't need if-then-else, you can emulate it by applying k and (s k) (which
can represent true and false).

------
methodover
Wait, am I missing something? Isn't the "non-functional" code here wrong?
There seems to be no filtering for only those departments that belong to the
user's business, unlike the functional example where it uses
"user.departments"

------
aidenn0
What language does the article use for examples? I don't recognize it.

~~~
logicfiction
Scala

------
Joof
Oh no problem.

fac n = result (for init next done) where init = (0,1) next (i,m) = (i+1, m *
(i+1)) done (i,_) = i==n result (_,m) = m

for i n d = until d n i

------
crimsonalucard
One way to solve this problem is to show them this article. I'm bookmarking
this in case the situation ever pops up.

------
seivan
I can understand that concepts like flatMap, merge, reduce and zip can be
intimidating at first. It would help to explain what they are and how they
work with smaller examples outside of project code base.

[https://jsbin.com/bemasodemi/edit?js,console](https://jsbin.com/bemasodemi/edit?js,console)

~~~
Cthulhu_
One argument I'd like to use at one point is to explain a for-loop and what it
does - intimidating? How about initializing a numerical variable, then
creating a loop that checks the value of said variable, increments (or
decrements), and in case of array operations, attempts to get an entry in that
array in each loop.

Versus for-each-entry-in-list-do-this.

~~~
seivan
Be pragmatic, there's a higher chance that a developer has used said concept
than the FRP mentioned above.

Funny you should mention that for loop as it's been removed from Swift 2.2 ;-)

------
throw19238
Apparently this submission is flagged and sinking. In addition to being
bureaucrats, the OO hordes are apparently without humor, too. Or perhaps one
goes with the other.

~~~
emodendroket
It's not really that funny.

~~~
vinceguidry
Worse, there doesn't seem to be a point. It sounds like a Haskeller's rant
over how OOPers don't understand basic concepts. And, to be fair, a lot of
them don't, can't count how many times people have mistaken static typing for
object-orientation.

But this isn't the way to point that out. Should we be surprised that a modern
multi-paradigmatic programming language can be used to code in a functional
style?

------
andrewmcwatters
I feel like there's potential for a "How to stop being a smartass" rebuttal
article here.

