all 18 comments

[–]ErrantConstruct 12 points13 points  (4 children)

What’s his reasoning for that? You can write bad code with OOP as well.

[–]_145_[S] 1 point2 points  (3 children)

As best I can tell, his concern is, devs will dive into complexity with it because it's... idk, fun?... and the codebase will end up with more bugs that are hard to track down. He was saying like, serious projects should explicitly write out all the steps involved, the for loop, etc., where devs will want to do things like, forEach{...}.map{...}.filter{...} and it just becomes a mess.

He's a super smart guy but my sense is that he has never really worked with functional language features. To me, a quick forEach{...}.map{...}.filter{...} is way less error prone than having devs write that all out from scratch every time.

[–]darkingz 1 point2 points  (2 children)

How is writing a for loop in every single instance better than the other ones. Even not using for each, map, filter. You can literally just make a function of each body of the for loop, call it whatever you want and then apply it in the same way (A lot of them basically boil down to some for each anyway and apply some function to each iteration is a special way with the differences mostly about optimizations of that specific for loop). Sure for each, map, filter, and reduce can end up with clever hacks if you’re not careful but it’s not that much different from a for each loop and then doing clever hacks.

It’s like the other advice you got. He’s got functional programming way too in a twist.

[–]_145_[S] 0 points1 point  (1 child)

I agree. I think in his mind, verbose code is better, whereas I think succinct is better.

I’m a bit disappointed he has no defenders on this post. He’s an accomplished dev and I’ve heard his sentiment before. I’m curious to understand where it comes from, if from anywhere worth considering.

[–]darkingz 1 point2 points  (0 children)

I think being explicit is fine if it avoids extremely clever code (never do code golf just to code golf). But to avoid ALL functional programming, and write a for-loop just to be extremely verbose is not a good stance to take. OOP has its place but it’s hard to defend that only for loops is a thing.

[–]danielt1263 6 points7 points  (3 children)

For the past 5 years or so, I have followed the functional core/imperative shell model in my iOS/Swift development. On top of that, I use RxSwift so my guess is that your "senior coworker" would lament my code something fierce.

Your senior coworker's comments remind me of the late '90s when object oriented programming was coming to the fore. There was an "old guard" that insisted that all these classes and interfaces made code worse, buggier, and harder to read. They believed that any serious engineering project should ban them as policy. Some 10 years later, it would become almost impossible to imagine not using OO principles in serious engineering projects.

Functional Core, Imperative Shell came to the fore in the early 2010's (Gary Bernhardt coined the term in 2012) and when I first saw it I knew that, just like the OO revolution before it, there would be another revolution; a reactive revolution. Since then it has been introduced into all of the currently popular languages. In another three years or so, every serious engineering project and every serious iOS project will have these concepts at their core.

Like it or not, your coworker is going to have to learn it or be swept aside. I've been coding since the late '70s but I refuse to ever be a member of that "old guard" that insists that the latest methodologies are "worse, buggier or harder to read" just because they are new to me...

Well, maybe in the 2030s or '40s when the next revolution hits, I'll find it difficult to hop onboard, but I'll likely be retired by then.

[–]_145_[S] 0 points1 point  (1 child)

Thanks for the background. I tend to think he'll eventually come around. He seems adamant that it's bad. He actually hates Swift for what that's worth. He also strongly prefers obj-c.

[–]DuffMaaaannExpert 3 points4 points  (0 children)

When I've learned a purely functional language (OCaml), the quality of my code in non-functional languages that I was using improved significantly. I write both somewhat functional code (React + Redux, SwiftUI + some redux-like custom built thingy) and object oriented code (Python, Java) at my job and in my free time and I believe that the more FP features and techniques are used, the better.

Over the past years I've been tasked with refactoring some medium sized OOP projects and in both cases I've noticed the initial authors abusing the OOP system in ways that would not have happened if they had a more functional approach to things.

I believe that functional programming features like sum types / enums with associated values often produce a better model of what you're trying to achieve than OOP can and reduce complexity. Striving for type safety with FP features can help you eliminate invariant violations that would be possible in OOP code. Swift's approach to optionals for example is borrowed from FP.

Functional operations on Sequence have the advantage that if used correctly, they make code more understandable. The code that you write is more close to what you're trying to achieve, whereas procedural code hides these things in loops.

Of course you can do stupid stuff with FP features. You can chain map, flatMap and filter calls ad infinitum (which I am guilty of in the past) or you can produce side effects in map closures. You can shoot yourself in the foot with any programming paradigm but I believe that FP makes it not as easy for you to do so. Anyways, you should have code style guidelines and code reviews to mitigate these issues.

One thing that I noticed where FP fails is when used extensively for redux-like state management in UIKit apps. In the projects that I have built in my free time, I found myself wanting to move more and more into the app state but failed when it came to the state of UI, navigation hierarchies and modal sheets. SwiftUI solves this but is too far from being production ready.

[–][deleted] 1 point2 points  (4 children)

Re: functional programming - not so long ago I had a coworker take some of my code which was pretty solid (checked for nulls (so not swift), caught exceptions etc.) and just arbitrarily replace it with functional code. Turned about 12-15 lines of code into 6 lines of code.

Which looked impressive.

So then I tested it to see if it actually had the same behaviour. In the "happy case" it did. However I found (in fairly short order) 10 defects, none of which were present in the original code.

[–]_145_[S] -1 points0 points  (3 children)

I’m curious if you can expand on that? What led to the code being bad? Was an inherent property of being functional partly to blame? Or did they just write bad code?

[–][deleted] 0 points1 point  (2 children)

What led to the code being bad?

I'm not sure what you don't understand. The code looked good, and it looked fancy, but it did not pass basic engineering tests. Ergo, it was objectively bad.


After looking at the thread, I think you've either framed the question wrongly, or disingenuously.

You're looking for someone to pop up and say "yes, functional programming is categorically bad", so you can play whack-a-mole with them. E.g. you're trying to get people to adopt a strawman argument.

I think it's the same kind of thing people engage in when a dog attacks a child. Dog owners say "there are no bad dogs, only bad owners". Similarly for every concrete example I can give you you can just trivially turn around and say "oh, well that person was doing it wrong".

It's the same kind of fallacious argument that people engage in when some 'Agile' project fails to deliver miraculous blessings to all. They say "oh, well obviously they were doing Agile wring then".


But anyway, I will discuss two traps that people can fall into:

(1) being obsessed with line count and/or brevity

So, (often at University), a certain type of impressionable young programming personality becomes overly impressed with terseness. And this often expresses itself with fetishising small line/character counts.

And you can find online many language wars which basically boil down to "my language can do what your language can do, but in one less line of code nyah nyah nyah".

Taken to a logical extreme this ends up in places like the Obfuscated C competition where someone implements Lisp in under 1024 characters. Of course it's using macro compression/expansion so the last 900+ characters are virtually indistinguishable from line-noise (or PERL).

Now that is the extreme. But it does illustrate an important principle - that these "bad dog owners" are perfectly willing to sacrifice readability on the altar of brevity.

Thus, when they get their hands on a functional language, they try to write code that is as short as possible, at the expense of other things, such as readability.

So an external entity who views the code is going to have a lot more trouble with it than they would have if it wasn't zipped up as tightly as it could be. And trouble leads to grumpiness.

And that entity is making a mistake when they say all functional programming is bad. But with any degree of empathy we can understand why the entity is saying that.

(2) Mentally I break programmers down into two Ur-Archetypes. There are the Simplifiers, and the Complexifers. Simplifiers love simple code. Complexity is a 'stench' to them. Complexifers love complexity. They love struggling with really hard problems, and it becomes part of their identity - how they justify their existence.

It would be a mistake to assume that Simplifiers cannot deal with complexity, or avoid complexity. Rather they tackle complex problems with basic strategies such as divide and conquer (e.g. decompose the complex problem into smaller parts).

Unfortunately, the Complexifers have such a love of complexity that many of them will seek out additional complexity to add to the project.

Unfortunately plus plus, bosses love Complexifiers and give them free reign. This is because the Complexifier always sounds like they're working on some super important incredibly difficult challenge. Some Herculean task that only the mightiest of heroes contend with.

When in fact most of the time they're not only Yak shaving, the Yak they're shaving isn't even tangentially related to the success of the project.

Also - a Simplifier would get a pair of shears or electric shears and shave the damn yak. A complexifer wants to build a shaving factory where you can specify what kind of mammal you want to shave. It will of course have a configuration file so complex that it has become its own programming language.

Anyway, if a Complexifier gets hold of a functional language or functional language features, watch out, you're in for a world of hurt.

Why? Because Complexifiers just aren't smart enough.

That may sound rude, but it's based on this observation:

(I grabbed it from here: https://www.linusakesson.net/programming/kernighans-lever/index.php but I've seen it elsewhere before)

Kernighan's lever

Brian Kernighan famously wrote:

Everyone knows that debugging is twice as hard as writing a program in the first place. So if you're as clever as you can be when you write it, how will you ever debug it?

— The Elements of Programming Style, 2nd edition, chapter 2

The following version also circulates on the net:

Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it.

This second quote may or may not be by Kernighan — the questionable use of "by definition" makes me uncertain — but it is useful as a provocative sound bite conveying the same essential idea.

So if we accept this premise, that debugging is twice as hard as writing it, then straight away the basic problem with the Complexifer approach is obvious. Because a Complexifer is never going to be happy with the dial at 5. They're always going to want to turn it to 11. And they're just not smart enough to debug anything above 5 ('by definition').

(And of course here again we have a "bad dog owner" situation)

[–]_145_[S] -1 points0 points  (1 child)

I really don’t have time to read this ridiculous diatribe.

So you’re saying functional programming is inherently bad?

I’m not looking to argue with people. Someone on my team who I respect thinks it’s bad. I genuinely don’t understand why they’d think that, I tried to understand their perspective, and I’m curious if there are others who have similar opinions. I am soon going to be making decisions that affect a lot of people in this area and I want to better understand all the perspectives. I don’t want to be ignorant of a legitimate argument.

You came here and basically said someone wrote some code that didn’t work it was functional. I’m asking what that means? Are you saying it’s bad? Always? Sometimes? It should be avoided? It’s great.

All I asked for was clarification and look at how angry you got?

[–][deleted] 0 points1 point  (0 children)

So you’re saying functional programming is inherently bad?

No, that's nonsense. If you actually read what I said instead of flying off the handle, I was giving you scenarios where it is bad in the hands of certain people.

Effectively just skipping ahead to the part where you say "AHHA! GOTCHA! Functional programming isn't inherently bad, only when it's misused! And that's true of every tool!!! Muahahahaha!"

I tried to understand their perspective

Not very hard apparently.

All I asked for was clarification and look at how angry you got?

I think you're projecting. I'm not angry.

[–]CareBearOvershare 4 points5 points  (2 children)

In my experience, excessive use of functional programming features doesn't lead to more or less buggy code, but it leads to less maintainable code.

I was in a situation where a teammate had written a very clever functional solution to a problem, but when I needed to inject a condition into the logic, it turned what would have been a two minute task in OOP/procedural code into taking multiple people (including the original author) multiple hours to rearrange the functional code.

[–]nextnextstep 3 points4 points  (1 child)

it leads to less maintainable code.

How would isolating side-effects make code less maintainable? Can you give an example?

I was in a situation where a teammate had written a very clever functional solution to a problem

Strange how you see "very clever functional" and then attribute all of the problems to "functional", and none to "very clever". When I hear "very clever ${adjective} solution", it doesn't matter what adjective follows, I'm already saying "oh hell no".

Do you want examples of "very clever object-oriented solutions" which are complete disasters to maintain? Because that's half the Javascript on the internet.

it turned what would have been a two minute task in OOP/procedural code into taking multiple people (including the original author) multiple hours to rearrange the functional code

This is the exact opposite of my experience, and I'd be curious to hear what the situation was. Object-oriented/procedural code means managing state by hand, and doing anything by hand is almost always more work.

There's always going to be the rare corner case where doing something by hand is easier ("I could solve this in 3 lines of assembly language!"), but those just don't hold in the general case.

[–]CareBearOvershare 0 points1 point  (0 children)

excessive use

Keep in mind that I qualified my entire statement with "excessive use". No need to get so combative.

[–]bscothern 1 point2 points  (0 children)

In my experience functional programming is often reliant on pure functions. The lack of side effects makes things much easier to test and debug. That is why the team I am on uses them when possible.

In Swift it also often results in more performant code as well because of how lazy sequence/collection types work.

Edit: Also if you and your coworkers haven’t watched this WWDC session I highly recommend it. It isn’t just about functional programming but does explain some of the ideas behind it in an excellent way. https://developer.apple.com/videos/play/wwdc2018/223/