
Why Are So Many Developers Hating on Object-Oriented Programming? - ingve
https://thenewstack.io/why-are-so-many-developers-hating-on-object-oriented-programming/
======
jehna1
Have you seen bad OOP code? It's an unreadable mess of ObjectManagerFactory
classes where everyone mutates everything.

Have you seen bad functional code? It's an unreadable mess of monads, flatmaps
and partial composition where you're not really sure how many arguments a
curried function is whitholding.

Have you seen bad procedural code? It's an unreadable mess of nested if-else
statements where you're not really sure what state the world is in.

There are no silver bullets, only different solutions to different problems

~~~
tolmasky
I feel that it is in fact possible to learn from history, and what humans tend
to be good at and bad at, and derive useful directions for the future. "Use
the right tool for the job" and "no silver bullets" are certainly
tautologically correct, but they seem to miss the point of these discussions:
we have a _choice_ in what paradigms we teach, what frameworks we write, and
what tools we use. _How_ do we choose the right tool? These platitudes often
have the (unintended?) consequence of effectively serving as veiled gate-
keeping: "silly novice, you thought learning X was sufficient? No no, you must
learn all the possible paradigms, and at some point you will become aware of
which one to precisely apply for any given problem. Me merely telling you the
solution would be cheating!"

Practically speaking, in my opinion, beginning teaching programming with an
OOP approach can be detrimental to students. When I see students work in
procedural (not even functional!) environments, they seem to piece together
"the puzzle" of the programming task, whereas in OOP environments they often
seem to devolve into strange taxonomical metaphysical questions "Is a Car a
Vehicle? Or does it implement Drivable? Is a Window a Widget itself, or does
it only own Widgets? If it's a Widget itself, then could a Window contain sub-
windows?" So at least for the very constrained question of introductory
languages and techniques, I think there is nothing _wrong_ with specifically
calling out certain approaches, vs. vaguely attesting to the truism that you
can write bad code in any language. This feels similar to when people discover
the concept of Turing Complete, and thus conclude all languages must thus be
equivalent and any programming language discussion is thus moot. No. If that
were the case, we should have never bothered going past assembly.

~~~
yoz-y
What courses or universities actually start with OOP? In my uni we started
with functional programming (Scheme) and then went to C, only then we learned
Java, C++, Prolog and so on.

In another uni when I supervised some exercise classes all students started
with Python but using only imperative paradigm.

~~~
tolmasky
In high school AP Computer Science uses Java (20 years ago when I was in high
school, they were just transitioning off of C++). You can see what the
earliest programmers are being taught here:
[https://apcentral.collegeboard.org/pdf/ap-computer-
science-a...](https://apcentral.collegeboard.org/pdf/ap-computer-science-a-
course-a-glance.pdf?course=ap-computer-science-a)

Edit: When I was in HS, the AP CS courses (now there is only on since the
second one was discontinued) used the "Marin Biology Case Study" (
[https://en.wikipedia.org/wiki/AP_Computer_Science_A#Marine_B...](https://en.wikipedia.org/wiki/AP_Computer_Science_A#Marine_Biology_case_study_\(2000-2007\))
). It has apparently been replaced with the "GridWorld" similar case study. I
think it highlights one of the issues of OOP: a fascination with modeling, or
perhaps over-modeling, the real world. Throughout the course you are expected
to develop deep knowledge of a myriad of Fish and Fish Tank-related classes,
which while perhaps an accurate preview into what working in an environment
like Java is like, is not something that in my opinion succeeds in either
exciting most students nor teaching them the "fundamentals" of algorithms and
such. I think it can very much feel like a very complex and convoluted
exercise in meeting the abstract goals of "categorizing" the world.
Ironically, the insistence on modeling the world makes it feel frivolous and
disconnected from any practical use -- which is incredibly sad since IMO CS
could be the _most_ practical math/science course you take. In my experience
when you show kids the cool things that they can get computers to do _for
them_ , it can be more inspiring -- such problems do not lend themselves well
to formalized class hierarchy drawing though.

~~~
topkai22
They are back to two, and the new one appears much further down the “not only
OOP” path. It’s more about the grand ideas of CS and less about programming.
[https://en.m.wikipedia.org/wiki/AP_Computer_Science_Principl...](https://en.m.wikipedia.org/wiki/AP_Computer_Science_Principles)

------
cpursley
> “OOP is prevalent because cheap OOP developers are readily available, while
> functional programmers are typically more smart, and more expensive…”

The reason I prefer functional programming over OOP is that I'm just _not
smart enough_ to understand all the OOP abstractions and how to build reliable
systems with it. Functional programming is just easier to grasp mentally, as
it takes away a lot of the foot-guns (mutable state, inheritance, etc).

~~~
p1esk
I grasped the concept of OOP pretty easily. Can't say the same about FP.

~~~
madhadron
People say this, and I'm not sure it's actually true. People grasp some basic
use of structs with methods on them pretty quickly and using that to do
polymorphism. Most programmers I know haven't grasped how to use a system of
message passing objects to make the semantics of the underlying language
programmable at runtime.

~~~
p1esk
To me OOP is about using "templates" to create "objects", which map nicely to
real world entities/concepts. So a class is like a function, but unlike a
function it can do more than define an input to output mapping. It groups
together multiple related functions and variables, and allows "objects" to
exist and be interacted with. These "templates" can be hierarchical and/or
have more than one "base template", combining all their "features". This type
of thinking feels natural to model real world objects and tasks.

The above is my "layman's" understanding of OOP (I've never taken programming
classes, but I have been using OOP extensively in the code I write to do my
machine learning research).

Can someone describe FP in a similar manner to someone like me? Because every
couple of years I stumble upon another "intro to FP", and it just does not
click for me. When exactly should I use it? How "monads" or "functors", or
whatever else is important in FP, map to the real world, and real tasks? Maybe
I just don't write the type of code that would benefit from it.

~~~
ryandrake
I feel the same way. As hobbies I like to work with my hands on things like
carpentry and metalworking. OOP maps pretty well to how I think about
accomplishing step by step tasks on physical objects:

Step 1: Use this tool (instance of a class) to perform that modification (call
a mutating method) to affect this workpiece (another class instance). Step 2:
Now use that tool...

So if I’m building a cabinet, my mind plans out something like:

    
    
      saw.cut(wood1);
      saw.cut(wood2);
      wood3 = glue_bottle.apply(wood1,wood2);
      sander.sand(wood3);
    

Etc.

I’ve always thought of a program as just a more elaborate series of step by
step commands. Computer do this to this thing, now do that to that thing
(which may, through a subroutine, mean doing other nested tasks). I can’t wrap
my mind around accomplishing a step by step process with functional
programming. Just haven’t made that mental leap yet, probably because I’m so
used to thinking the other way.

~~~
dragonwriter
For a simple case like this with no diamond-shaped dependencies, the direct
functional expression is inside-out rather than top-to-bottom:

    
    
      sand(
        sander, 
        glue(bottle, 
          cut(saw, wood1), 
          cut(saw, wood2)))

~~~
username90
Now write that code with tools having durability. In OOP that is trivial and
require no code changes elsewhere.

------
save_ferris
I’ve come to loathe inheritance in OOP, favoring composition instead.

The idea of creating abstract base classes makes sense in theory, but this
eventually leads to problems regarding inherited behavior (i.e. debugging
unexpected behavior of a “duck typed” interface up the inheritance chain)

~~~
fragsworth
I disagree. OOP and inheritance is fine, and so is just about every
feature/paradigm/language/anything in programming, when used thoughtfully by
an experienced developer. For instance, inheritance can often be used nicely
at a framework or engine level.

Most people are just inexperienced and bad at programming, and bad at managing
large projects, and if a lot of bad programmers and managers happen to be
using some paradigm or feature or language, it is often the paradigm that
takes the blame for their shoddy work because nobody is willing to admit that
_they_ are the ones at fault.

Functional programming feels nice to everyone right now, because lots of
experienced developers are enjoying themselves with it, and writing decent
code. But mark my words: that good feeling will end once it gets too popular
and adopted by new developers. And then people will blame Functional
Programming for all the awful work people do in it. If you think I'm wrong,
you are way underestimating how bad new software developers can be.

We don't throw away all our hammers just because some bad construction workers
use hammers on the wrong things.

~~~
squirrelicus
I wish I could talk to you 5 or 10 years down the road when you have
discovered and internalized the reality that a) there are no good programmers
b) the programmers you're complaining about will never go away c) you're one
of them

My contention against OOP is that it is a pattern that encourages critical
mistakes that composition-based systems does not encourage.

My contention against FP is that it discourages small amounts of state (e.g.
that doesn't leave the scope of the current function) and instead encourages
many mental leaps to wrap your head around the transducer or whatever.

But if I had to pick one, FP tends to produce higher quality code.

~~~
fragsworth
I've been programming for 20+ years now, nearly fulltime, and worked with many
other programmers for the entire time. There are plenty of good programmers,
and they all have a lot of experience. I've learned to tell the difference. It
took a long time. Your blanket statement that developers are all bad is simply
wrong, there are vast differences between them. Maybe to put it in terms you
seem to prefer: some are "less bad" than others. And not everyone is bad in
the same way, either.

But you're right, the programmers I'm complaining about will never go away,
because there will always be new programmers, and old ones will retire or die.

My only point was that everyone's impression that FP tends to produce higher
quality code is largely based on a selection bias from the code you've read,
or based on your own attempt to learn the paradigm after already having had
some amount of experience.

I witnessed firsthand the rise and fall of many paradigms in programming. I've
witnessed it with NoSQL. And Agile. The same thing is likely to happen to
Functional Programming, if it becomes too popular too quickly. When you see
companies starting to post jobs with "Functional Programming experience
required", that's when you're reaching peak, and a bunch of new (bad)
developers will come in and ruin everyone's impression of the paradigm.

~~~
squirrelicus
The industry is very new. The rise and fall is natural (lolwat data mining?).
But the function is not uniform. MongoDB might be one of the worst tools on
the planet for relational data, but data that's only accessed by id and is
dominated by variable length data? There's no better db on the market. Agile?
Well, nobody's figured any of that stuff out yet, to say the least. We can't
even estimate basic tasks still, so planning is strictly fucked until we can.

Additionally, there are so many things to learn, especially for up and coming
developers that it's nearly impossible to select good tooling to learn in the
first place. So you'll have them randomly spread across the tooling which,
again, is indistinguishable from each other from the perspective of a new
developer.

I guess my point is that you're complecting two orthogonal concerns: the
process of figuring out this software thing (still in it's infancy), and the
process of bringing up juniors. Consequently, what juniors do before they gain
sufficient training shouldn't have much impact on the value of tooling. That
is, unless the tooling in question causes the juniors to make unnecessary
critical mistakes because the tooling encourages it. QED I suppose.

------
scardine
It is like JavaScript: I don't hate JS itself, I hate spaghetti-code people
write with it (but I do hate automatic type casting).

I don't hate C, I hate dangling pointers and buffer overruns.

I don't hate OOP, I hate over-engineered class hierarchies, state hiding and
leaky abstractions.

I don't hate FP, I hate when people write a new undocumented DSL for each
project just because "it is so easy in an expressive language like X".

------
gavanwoolery
I've been programming for a quarter of a century.

It has taken me a long time to realize that "dumb code" is the best.

Dumb code is easy to read.

Dumb code is concise and to the point, not attempting to address theoretical
problems (necessarily).

Dumb code does not overthink the problem.

Dumb code helps you sympathize with the machine.

Dumb code has no weird blackbox behavior.

etc...

~~~
chaoticmass
A corollary to that-- less code written the better.

~~~
proverbialbunny
Not always. eg, simpler code is sometimes turning a line into two or more
lines, just to make variables named in a way that describes what's going on.

------
yuhe00
I don't think OOP itself is bad. Bad abstractions are bad, no matter the
language, and that is the main problem. Abstractions and domain models are
created based on our understanding of a given problem as well as what is
possible within a certain programming language/paradigm. Most of the time, we
initially do not have a good understanding of the domain we are working in,
and because we are conditioned to keep code "organized", we tend to fall back
to established "patterns" (which OOP has an abundance of...), but these almost
always end up being the wrong abstraction. By the time we figure this out
though, it's already too late to change it.

A functional language such as Haskell tend to make us think a little bit more
about what abstractions we use, because they are such an integral part of the
language you can hardly do anything without them. We can "converse" with the
compiler to come to a better understanding of how our code should be
structured. You usually end up with a better domain model. However, this can
also be very limiting. Lack of control of execution and no control of memory
layout is a problem in my domain (video games). It's also slower to develop
for because you can't take "shortcuts", which can be helpful to get something
up and running without having to understand the problem domain.

I still use OOP daily (C++), but I never start out with abstractions when
writing new code. I tend to create C-style structs and pure functions.
Eventually, I will have a better understanding of how this new module should
be organized, and will make an API that is RAII-compliant and whatnot. I think
you can easily write clean code in OOP as long as the abstraction makes sense.

~~~
MauranKilom
Out of all the comments here this one resonated with me by far the most.

You're totally correct: The goal is to find the right abstractions. Bad
abstractions keep getting in your way either by leaking too much or by being
based on invariants that turn out to be not actually be all that invariant,
whereas good abstractions have no need to be touched again later.

For me, the additional layer of "how hard is it to change the abstraction if
it turns out to be wrong" is also quite important. In my environment
(algorithmic R&D) you never quite know which invariant your next idea will
break. And this is where OOP can really bite you - untangling code from a
class hierarchy or twisting interfaces to bend to your new ideas is anywhere
between infeasible and a complete mess. Composition over inheritance can help
save a lot of frustration here. But sometimes interface/abstract base class +
a single implementation also provides a very clean abstraction to separate the
core model/algorithm from the fiddly details. Just don't fall for deep
hierarchies or large interfaces would be my takeaway so far.

Maybe we just need to get better at giving up on abstractions when they fail?
I think that's very tough because they tend to still dictate how we think
about problems (plus the usual cost of rewriting code). Your approach of
delaying the abstraction choice sounds very interesting (somewhat akin to
Extreme Programming?), I will try to keep that in mind for the future. In
thinking about this I'm mostly afraid of code sort of remaining at this
"makeshift"/provisional level and never actually settling into something more
organized (due to lack of incentive/time to improve it). I think that can be
kept under control, but do you have any suggestions on that front?

~~~
yuhe00
> Your approach of delaying the abstraction choice sounds very interesting
> (somewhat akin to Extreme Programming?), I will try to keep that in mind for
> the future. In thinking about this I'm mostly afraid of code sort of
> remaining at this "makeshift"/provisional level and never actually settling
> into something more organized (due to lack of incentive/time to improve it).
> I think that can be kept under control, but do you have any suggestions on
> that front?

Actually, I find that more often than not, code written in this manner is
actually easier to maintain, because there are no layers and concepts to
untangle - just the raw functionality and data transformations. You don't need
to put yourself in the mindset of the person who wrote the code, who might not
have had the right concepts in their head at the time. Instead, you just parse
the code like a computer - This makes it easier to figure out what the code
actually does rather than being distracted by the intent of the author.

The main purpose of abstraction is to intentionally hide implementation
details so other people can use your code without requiring a full
understanding of all the details. However, when maintaining code, obfuscation
is the exact opposite of what you want - You want to fully understand what the
code is actually doing. Internally, I forgo most abstractions. For public
interfaces, I expose highly specific functions and datatypes rather than
"generic" interfaces, and only the bare minimum. Variants should favor
duplication over generalization when uncertain. It's up to the consumer of
those APIs (which is often myself!) to choose whether or not to implement
abstractions on top of those. In my experience, it's either super-obvious when
it's needed or unnecessary if unsure - So you can usually push back
abstraction up to that point.

------
mattbillenstein
Using python, I tend to write much more procedural code than anything else -
packages / modules / namespaces are much better for code organization and pure
functions that don't hold state are just easier to reason about. Classes are
used sparingly - really only when you actually should encapsulate some data or
state, but generally they're not needed at all.

I've seen oop used as code organization too many times, and it's always a
laughable mess.

~~~
pjmlp
Python functions are objects, instances of the function class, as this little
snippet shows.

    
    
        def afunc():
            pass
    
        print(afunc.__class__)
        print(dir(afunc))

~~~
Doxin
While technically a function is a class instance, it doesn't _act_ like one in
pretty much any common use-case.

------
gumby
I do agree that O-O design was fetishized starting in the 1990s and the
results have been terrible. But this is strange to me:

> In fact, his essay ends by touting functional programming as the superior
> alternative — a competing paradigm in which problems are modeled not with
> objects but with pure mathematical functions and an emphasis on avoiding
> changes in state.

O-O is a way of encapsulating abstraction. That's it. It could mean actors,
message passing generic functions composition and/or inheritance. There's no
reason you couldn't program in a purely functional O-O way.

I build hardware that uses a variety of different kinds of fasteners, and
circuits with different kinds of components. I _could_ build all my logic
circuits with only resistors and diodes (people used to do so, after all) but
the fact that that's no longer a good idea doesn't mean I should try not to
use resistors or diodes at all.

------
dagw
Having been around this block (procedural->OOP->FP->...) a couple of times
over the past 20 years, I've ended up at place where I always start with no
classes and mostly pure functions, but don't shy away from adding small
handful of classes when it becomes obvious that they solve a real problem.
Sometimes objects really are the cleanest solutions, but they should never be
your first solution.

------
dreamcompiler
> In non-OOP languages, like JavaScript, functions can exist separately from
> objects. It was such a relief to no longer have to invent weird concepts
> (SomethingManager) just to contain the functions.

This is one of the things CLOS (Common Lisp Object System) got right: It's
object-oriented but functions are not "owned" by classes; they're separate and
first-class and generic and can dispatch on multiple arguments. In CLOS,
classes are truly just user-defined types, and classes don't impede your
ability to write functional code.

~~~
fengb
Is he seriously using Javascript as an example of non-OOP language?

~~~
naikrovek
Having the idea of objects does not make a language "object oriented."

Compartmentalization and encapsulation are fundamental concepts of objects and
those concepts existed long before "OOP" did

~~~
pjmlp
That was called modular programming.

SELF, which JavaScript takes its model from, is definitely OOP.

------
Const-me
OOP is the only way invented so far to deal with complex mutable state. Many
practical problems have a lot of that.

OS kernels is one example. Right now, Windows task manager says there’re about
100k opened handles in my system. The state of an opened file handle is huge:
user mode buffers, kernel mode structures, encryption, compression, effective
permissions, file systems B-trees, flash memory state, and more. Without
hiding all that state behind an API, the amount of complexity required to
write a byte to a file would be overwhelming. On Linux it’s usually
object_do_something(struct tObject *), on Windows it’s
DoSomethingWithObject(HOBJECT), it’s 100% OOP, where objects are hiding their
state behind methods.

GUI is another example. Whether it’s a web page, a rich text document in an
editor, or a videogame, the state is very complicated. GUI frameworks don’t
compute functions, they respond to events: from user, from OS, and from other
parts of the program. All GUI frameworks are OOP, including web frontent ones,
e.g. reactjs.org says “Build encapsulated components that manage their own
state”, it’s a textbook definition of OOP.

------
mattnewton
I feel like there are two effects here: Most code you will encounter in the
workforce is poorly written or is now used in ways the author didn't intend.
Because of it's popularity, most code you will encounter there is also object
oriented.

The second effect is, pay and hire-ability is often linked to years of
experience in languages and tools for developers who don't have large projects
or exits on their resume. That means that you are incentivized to learn new up
and coming tools and paradigms, where your years of experience can quickly
become competitive vs more established technologies, where people have years
of experience on you.

Now, I happen to also prefer functional programming because it seems to more
closely match the way I think, and I find it easier to responsibly manage
state in that style. But I believe that these two potential causes have a
larger effect than my personal preferences. I don't know how to measure this
though.

~~~
commandlinefan
> most code you will encounter is object oriented.

Well - most code you encounter was written in a language that was designed for
object oriented programming, like Java or C# (and, really, Python and
Javascript). That doesn’t mean it’s actually object oriented or particularly
well designed. I’ve been working mostly with Java for the past 20 years and
every single Java-based system I’ve inherited has been the same big-ball-of-
mud as the others, with almost every function declared static and classes
declared because Java doesn’t work if you don’t type “class” somewhere. It’s
never reusable, never unit-testable, and never modularized.

------
pjmlp
Because it is fashionable to hate OOP and many don't understand that neither
OOP == Java, nor none of the multi-paradigm languages eschews OOP rather
embrace a mix of OOP and FP features.

Just like apparently, any FP language that has come before Haskell stop being
FP, for whatever definition of what FP is supposed to be.

~~~
madhadron
I don't think anyone is arguing that, say, Standard ML isn't a functional
language, and if anyone did, they would probably be laughed out of the room.

~~~
pjmlp
Well, even on this thread FP is being discussed as a set of Haskell features,
starting with the idea that all FP languages use immutable data only.

Which would make Standard ML not a FP language. :)

~~~
madhadron
Then I guess we can start laughing at some people, yes?

~~~
pjmlp
It seems like so, but I rather prefer the quixotic way that some education is
still possible.

------
namelosw
> 'Right tool for the right job' 'No silver bullet' 'Bad programmer write bad
> code'

Those are all good tools to stop thinking/progressing and being comfortable
ever after. But no, everyone knows those and they're not the answer to the
question. 'No silver bullet' could only be true when accidental complexities
are very small compared to core complexities, but it's far from the truth for
nowadays industry.

OOP is bad because it's a foot gun. It forces people making strong assumptions
by default. It's only a tool modeling static and mid-sized scale problem.

When the assumption is very strong it means behaviors in a class are strongly
coupled, its relation to other classes are static and specific. And that's why
people feel OOP is more understandable and readable - because OOP toys are
very specific, thus readable.

And it's very vulnerable to change. To deal with that, people have to make
less assumption, but every technique doing that have serious trade-offs -
people have to choose. And those techniques are where all those obscure
'AbstractFactoryBuilder' came from. For the same problem, 10 people tend to
have 10 different trade-offs, using different obscure solution, and 8 get
burned in the next release.

For example, to modeling the concept Payment, in a mediocre functional
programming language, it might be an algebra data type:

    
    
      type Payment = FreeCoupon | Cash Amount | CreditCard Number CVV
    

Every time you want to process a payment, just handle the three possibilities
concretely, if there's duplication just extract it. If there are 100 functions
operates the Payment type, it's perfectly fine just like Alan Perlis
described. The type is perfectly natural - just what it should be. There is a
very high chance people yielding the same result independently.

In so-called OOP, this probably be:

    
    
      class Payment
        getFoo()
        getBar()
        doBaz()
      class FreeCoupon extends Payment
      class Cash extends Payment
      class CreditCard extends Payment
    

In order to accept Payment type, you have to bend three sub-classes into the
Payment interface. And there probably 100 methods for Payment, and the
refactoring result would be totally opinionated, everyone has their own idea
but none of them solve it without introducing new problems.

------
yoz-y
So much bashing on mutability. Yeah, I get it most of the time it’s bad. But
there are a whole lot of problem classes which are either unsolvable or
painfully slow without mutable data.

------
wwarner
Rich Hickey: "By default, an object-oriented program is a graph of mutable
objects. That's a very, very difficult thing to think about, debug and keep
running." Basically OO is exactly the worst to deal with increasing
complexity.

~~~
iLemming
Every programmer should at least get some familiarity with Clojure. It
maintains extremely good balance between simplicity, pragmatism and safety.

------
rukuu001
Done right - a focus on composition, message passing, little to no inheritance
- I find OOP a joy to work with.

It’s almost never done that way...

------
jmb12686
In my anecdotal experience, attempting / allowing "true OO" programming turns
quickly into an unreadable, unmaintainable, unreliable ball of mud. After
leading a team of ~30 developers in a monorepo for the past 5 years, I have
been relatively successful in avoiding complete software entropy by enforcing
the following "code commandments":

\- Modular, layered codebase (for ex: interfaces -> service layer -> DAO
layer)

\- Business Logic resides in Service Layer

\- Service Layer made up of collection of Transaction Scripts
([https://martinfowler.com/eaaCatalog/transactionScript.html](https://martinfowler.com/eaaCatalog/transactionScript.html))

\- Simple, immutable domain model, with distinct set of immutable objects for
each layer. Unapologetically, this is an "Anemic Domain Model", but with
separation and no re-use between layers. This allows for immutable objects at
each layer.

\- Services are decoupled and composed around the data / logic, thereby
"owning" their own data. Services can communicate with each other to get data,
DAOs are never to be shared among other services. This is in a sense,
"microservices without the network".

\- Testing at every layer, while respecting the "test pyramid"
([https://martinfowler.com/articles/practical-test-
pyramid.htm...](https://martinfowler.com/articles/practical-test-
pyramid.html)). Bang for buck is important here.

\- Last, but certainly not least: _Composition Over Inheritance_.

------
jefflombardjr
> What happened in most of the world starting in the 70s was abstract data
> types which was really staying with an assignment centered way of thinking
> about programming and I believe that... in fact when I made this slide C++
> was just sort of a spec on the horizon. It's one of those things like MS-DOS
> that nobody ever took seriously because who would ever fall for a joke like
> that.

\- Alan K

I don't hate on object oriented programming, but when I come across videos
like this
[https://www.youtube.com/watch?v=oKg1hTOQXoY&feature=youtu.be...](https://www.youtube.com/watch?v=oKg1hTOQXoY&feature=youtu.be&t=3315)
it is good enough reason for me to question OOP and explore alternatives.

I will say though... in my limited sample size of coworkers, it is more fun to
work with people who attack OOP than those who defend it. But the best people
to work with are those who don't get emotional about programming ideologies.

------
ridiculous_fish
OOP's strengths are coupled-but-separately-evolving components. An app, the
platform it runs on, plugins it uses, etc. all needing to talk to each other.
This forces you to think hard about the interfaces between components, and how
those interfaces themselves can evolve. OOP is good at expressing this sort of
thing.

If you assume you have all of the code, then interfaces and their evolution
don't matter so much. You can just refactor at will. OOP can't bring its
strengths to bear.

The web has shifted things to the "all of the code" assumption. Servers are
routinely self-contained. The browser's APIs are anemic and so are supplanted
by third party JS frameworks like React. These frameworks are version-pinned
by each site and bundled together into a single file. And when upgrading, it's
just accepted that there will be pain and incompatibilities.

------
patsplat
Managing state is hard. OOP expects state. OOP can make things harder than
necessary.

Languages with both first class functions and class semantics are nice,
because they allow you to choose the right tool for the job.

Inheritance is way overrated as a tool though. Great for the bouncer ball
sprite exercise, otherwise a bother.

------
adt2bt
To me, the pain I've always had with OOP is the amount of things I need to
keep in mind at a time when making a change, and also tracking side effects.
That mental overhead takes me away from thinking about what my customer really
wants with this feature, and slows me down.

~~~
commandlinefan
> the amount of things I need to keep in mind

Minimizing the number of things you have to keep track of when you make a
change was specifically what OOP was designed for... what's the alternative?
Procedural/structured programming is _way_ worse. I think FP is better, but
it's so hard to do that I've never worked with anybody who hadn't given up on
it before I had a chance to really tell.

~~~
choiway
Out of curiosity, what did you find hard about it?

~~~
commandlinefan
Functional programming? I haven't honestly had a chance to use it long enough
to find it hard: every time I've worked in a group that was even willing to
give it a chance, everybody else gave up before I had a chance to make up my
mind whether it was harder/easier than OOP. I personally kind of like the
functional aspects of Java, Javascript and Python (although I still don't have
the first clue what a "Monad" is).

I've been working primarily in Java for the past 20 years, across four
different companies, and as far as I can tell, most everybody gives up even on
OOP, too: every system I've ever worked on that was written by somebody else
was 90% static functions & static data, with a few "dumb object" data types
just because that's what you get from JAXB.

~~~
madhadron
> I still don't have the first clue what a "Monad" is

This is the simplest way I have yet found to think about them:
[http://madhadron.com/posts/2013-12-05-email-
about_monads.htm...](http://madhadron.com/posts/2013-12-05-email-
about_monads.html)

------
mark_l_watson
When I lived in Solana Beach California, one of my two tech guru neighbors
used to (25 years ago) pontificate on how OOP was the ‘last programming
paradigm.’ He thought there would never be anything better. It was the only
thing, ever, that I thought he was wrong about. (My other tech neighbor was
Stash Lev. He sold the 68030 replacement boards, with good gloating point
performance, for the original Macintosh, a wonderful thing indeed! Apparently
Stash was never wrong about anything.)

I don’t hate OOP, I just dislike it. I currently use three programming
languages, Common Lisp, Haskell, and Python. I don’t generally use Python
classes or CLOS unless I am working with someone else’s code.

Purely functional code, when possible, and also immutable variables avoid many
problems.

------
desc
An OOP approach is fairly straightforward to understand when you've got state
and need to control how it's modified.

A functional approach is fairly straightforward to understand when you need to
describe how state (maybe yours, maybe someone else's) is modified.

A place for everything.

------
edgarvaldes
As a person heavily invested in OOP, is there any good reference (book
preferably) about Functional Programming?

I know there must be lots of resources, but finding a good one can be
difficult when you are new to a field.

~~~
ahuth
Programming Elixir is a good one -
[https://pragprog.com/book/elixir/programming-
elixir](https://pragprog.com/book/elixir/programming-elixir).

It's (obviously) about the Elixir programming language, but was a pretty good
introduction to functional programming for me, as well. As was working through
problems on [https://exercism.io/](https://exercism.io/) in Elixir and
Clojure.

~~~
zinclozenge
This was my introduction to functional programming. The nice things about
Elixir for learning functional programming is that it's not nearly as
complicated as haskell, feels more familiar, and dynamically typed.

I'd recommend this book as it teaches how to think about solving things by
writing recursive functions (Elixir/erlang has tail call optimization),
pattern matching, etc. No need to learn the OTP concepts (genserver,
supervisors, etc).

------
naikrovek
The further we abstract ourselves from understanding of the platforms our code
runs on, the worse off we are going to be.

Our job as developers is to write software that transforms data from one form
to another. Any code that does not go directly to solving the transformation
problem you have for the data you have is wasted time and wasted effort today,
and will cost you additional time in performance and maintenance so long as
that software is in service. The best code, the most big-free code, the most
stable code, is the code that doesn't exist because it didn't need to be
written in the first place. Browse an Enterprise Java application and tell me
that there is no code there that couldn't have been written much more
succinctly and run much faster in another language.

Software development is not an art. It is a science - everything about
programming and software execution can be measured and therefore measurable
improvements can be observed. Almost no one does this -- why? Because of the
"CPUs are cheap" and "RAM is cheap" excuses I have heard throughout my entire
career.

I have never even heard of a study of OOP that found OOP to be a superior
methodology in any meaningful way whatsoever, and I don't think I ever will. I
don't think that result could ever be observed without a very strong bias in
the study.

~~~
kjeetgill
Just to tackle your first two paragraphs: I hate to say this, but this
impression may just be a lack of experience on your part. It's not wrong
exactly, just a very narrow view of the range of work that gets done with
software.

To bastardize a better quote: All abstractions are leaky some are useful.

Even assembly is an abstraction. And if you're working on tuning to nanos
maybe that's the problematic abstraction. But I'd say enough worthwhile work
gets done on top that it is a successful abstraction.

I think that's fair to claim all the way up your stack. An OS is worth it,
even if you do have to fight it once in a while. Same with processes. Or the
JVM. Or even _gasp_ OOP classes.

They don't need to be sacred to be valuable.

~~~
naikrovek
Ok, so add as many abstractions as possible?

I didn't say they were bad, I said we add far too many.

------
ilaksh
I have tried out functional programming various times over the years. Over one
span of some months I used OCaml to create something interesting. Maybe an OWL
parser. That convinced me that something like ML was far superior for parsers.

And I have experimented a few other times, such as with LiveScript.

The last time I tried to stick with a functional design was maybe a year or
two ago. I ended up repeatedly passing around a lot of parameters so that many
functions had several parameters. For example, in order to make a decision, I
had to analyze something in several ways, collect that analysis, and make a
decision based on all of the variables in the end. So the parameters just
started building up until the last function had like a dozen of them.

Then I grouped some of them into structures, but the functions that operated
on those structures had a few names parameters which were named in the
decision function. So even though I had fewer inputs to the decision, the
function body was complex with numerous parameters.

This led me to use classes to encapsulate the state so that parameters did not
always need to be passed at the end since they could refer to internal state.

------
bsder
The issue is that we don't _need_ OOP anymore--people forget that OOP had its
heyday when memory and performance were much smaller.

Passing a big list around, doing something to it, and passing back the entire
list is no big deal today.

It's a much bigger deal if you have to do some weird decompression/insert
because your main memory isn't large enough to hold the whole thing
uncompressed. You need a "gatekeeper" to the single thing--and you may need
coordination between the "gatekeepers" so they don't decompress
simultaneously.

Or, you build a huge hierarchy of objects into a GUI because you don't have
the memory to store the rendering state of each one so you want to be able to
look it up from it's parent.

Oh, and you only have one thread.

In an era of gigantic memory and dozens of threads, the "advantages" of OOP
simply don't make sense.

~~~
ncmncm
This argument does not make sense.

The more data you have, the more structure you need to help organize it.

------
ajxs
I'm not sure what point the first comparison example in the original article
by Ilya Suzdalnitski is trying to make. If you're going to cherry-pick an
example that demonstrates complex and abstract OOP paradigms (
factory/repository patterns, serialisation, etc ) then the author should
demonstrate how to address the same requirements that these patterns address
in FP. It's also quite rich that they're using Javascript to illustrate their
point. Javascript does not require the same OOP 'cruft' that languages like C#
and Java _might_ require in _some_ situations. So crafting the most complex
OOP-esque spaghetti you can think of in a multi-paradigm language is a
disingenuous comparison at best.

------
choiway
The problem with OOP isn't the concept itself. IMHO, the problem seems to stem
the fact that people use a "Class" as both a means of organizing code and as a
state machine. When you confuse the two, problems just get exponentially
worse.

~~~
AnimalMuppet
That _is_ the concept of OOP - that you package together the data (state) and
the functions that can operate on that data.

~~~
madhadron
Users of multiple dispatch OOP languages (Common Lisp, Dylan, CLOS, C++ STL)
would disagree vehemently with this characterization.

~~~
AnimalMuppet
Well, I'm a C++ STL user, and _I_ agree with me...

Could you be more specific about 1) in what sense you call C++ STL multiple
dispatch, and 2) why you think it disagrees with what I said?

~~~
madhadron
If you bundle functions and data, you end up implementing M functions each on
N types, or M*N. If you can separate your functions and your data, you
implement M functions and N types, or M+N. This is an explicit design goal of
the STL and Stepanov's research that led to it.

Similarly, Stepanov was explicitly trying to be able to write a polymorphic
max function `T max(T a, T b)`. That is, the instance of the max function
actually used is chosen based on all the arguments, not solely on the first,
which is the definition of multiple dispatch.

C++ also has a single dispatch object system, and the STL even mixes them,
putting things like vector::push on the class with the single dispatch system
and the STL algorithms in the multiple dispatch system.

------
ncmncm
> Why Are So Many Developers Hating on Object-Oriented Programming?

Fetishism, pure and simple.

Every language provides some apparatus to help organize programs. Some have
more, some less. With less, you have to build your own, because everybody
needs help keeping things organized.

Bad code fails to use what is there, or misuses it and makes things worse.
There is lots of bad code, because too few love simplicity, so everything gets
in the way of everything else.

Blaming OO should remind us of the old adage, "A poor craftsman blames his
tools".

People hating OO seem to be Lispers bitter that Lisp does not occupy the place
OO languages do. There are not as many as might seem around here, just because
most of them are around here.

~~~
iLemming
What? Lispers don't hate OOP. Take Clojure for example: it is a FP lang, but
deals with OO stuff better than OOP langs. Also: good craftsman knows how to
choose a right tool for the job. And bloated OOP languages are often not the
right tool.

------
ErotemeObelus
Functional programming combines the power of abstract mathematics with the
ease of understanding of abstract mathematics.

Now if you'll excuse me once I complete my Ph.D. dissertation I might be able
to finish my text editor I'm programming in Haskell.

~~~
iLemming
Haskell is not the only FP lang. Clojure, Elm and Elixir do not require
understanding of abstract mathematics.

Beside that, basics of category theory is far easier to grok than OOP Design
patterns.

~~~
ErotemeObelus
> Beside that, basics of category theory is far easier to grok than OOP Design
> patterns.

I know high-school dropouts and graduates from DeVry University who understand
design patterns. Category theory--even basic category theory--isn't taught to
undergraduate math majors (except maybe at MIT to honors students).

I mean, I appreciate functional programmers who want to do it because it is
hardcore... but that's why they do it: because it's hardcore.

~~~
iLemming
> I appreciate functional programmers who want to do it because it is hardcore

That's a misconception. Functional programming makes so many things so much
simpler. I know, Haskell can be seen as an impractical exercise for the sake
of tickling your prefrontal cortex. But again: there are other functional
languages, e.g.: Clojure - it is simple and allows you to get things done in a
pragmatic, reasonable and relatively quick fashion.

~~~
ErotemeObelus
Recursion is the worst way to do iteration because it requires cleverness (=
harder to debug) and it's ridiculously easy to cause a stack overflow. A for-
loop is not going to cause an integer overflow on a 64bit architecture.

Closures are basically global variables and inherit all of the problems with
global variables.

Continuations are basically goto's or memcpy and inherit all of the problems
with goto's and memcpy.

Functional programming is ALL of the bad programming practices of the '80s.
But because it's more abstract and mathematical it gets a free pass. Nevermind
the fact that computer science is not mathematics. And the benefits of
mathematical abstraction DO NOT TRANSFER if they inherently violate the
commandments of bad ideas like global variables and goto's.

There are solutions to ALL OF the object oriented problems--including the
diamond problem, circle-ellipse problem, and overuse of type hierarchies.
There are no solutions to the functional programming problems because they
inherently incorporate bad ideas described in paragraphs 1, 2, & 3.

~~~
dragonwriter
> Recursion is the worst way to do iteration because it requires cleverness

No, it doesn't; in fact, recursion is usually much easier to reason about,
particularly in terms of termination.

> and it's ridiculously easy to cause a stack overflow.

It's ridiculously easy not to, just assure your recursive calls are in tail
position and you are using a language that supports tail call optimization
(which essentially every dedicated FP language and a number of others do.)

> Closures are basically global variables

No, they aren't even similar.

> Continuations are basically goto's

Not really. They are similar in that they are a more powerful (and, therefore,
dangerous if used incorrectly) flow control concept than simple function
calls, but they aren't equivalent to gotos.

> Functional programming is ALL of the bad programming practices of the '80s.

No, that's unstructured imperative programming (though some structured
languages preserved some of them.)

~~~
ErotemeObelus
Closures are as hard to reason about as global variables are. Anywhere the
function with the closed variable is called, that is the same thing as
invoking a global variable, because that function could be called anywhere in
the entire program. The difference is that the garbage collector deletes it
when no function is calling it any longer.

Continuations are equivalent to memcpy... which should almost never be used.
And tail-optimized recursive functions are still difficult to reason about.

And tail-call optimization (making stack calls constant) is... kind of self-
defeating... because the only advantage of recursion is that it has a stack
built into the function call/return operations. Anything a recursive algorithm
can do is equivalent just a for loop and a stack data structure. And if you're
tail-call optimizing it so that it has a stack parameter... then you're just
using a clever way to write a for-loop :D Except functional doesn't allow for
you to mutate a preexisting stack so you're also wasting space recreating a
new stack each function call.

Yeah. Abstract math almost rarely transfers directly to the computer world.
There's a reason why the pure functional & concurrent language Erlang was only
used in telecoms and languished in obscurity: because that was the only domain
it worked well in.

------
jammygit
I found this video by Brian Will was interesting when I was trying to learn
about OOP[1]. It begins with some arguments, and there is a series of videos
that follow where he attempts to illustrate the point. One of his newest
videos is about an alternative form of OOP that he thinks works better.

[1]
[https://www.youtube.com/watch?v=QM1iUe6IofM](https://www.youtube.com/watch?v=QM1iUe6IofM)

I assume that OOP is only meant for very large programs, and he unfortunately
only demonstrates his ideas in smaller programs.

edit: added video author's name

------
maxharris
Sorry that this is a bit meta, but I don't think links from thenewstack.io are
good to post because of their Yelp-like tactics. They have a history of
shaking companies down for cash. Years ago I worked at a company that was
paying them tens of thousands per year, and when we stopped that because we
saw absolutely no measurable return, they retaliated by writing an unfriendly
article.

They are scummy, and I hope you don't learn this the hard way!

------
lerno
My take on why OO - as usually taught and practiced - is problematic:
[https://link.medium.com/GEgk2vjLpZ](https://link.medium.com/GEgk2vjLpZ) In
short: it requires a lot of up front design and abstract thinking, plus the
idea to architecture a program around state distributed over a large number of
objects is fundamentally flawed.

------
jayd16
These discussions are a bit tiresome. The major reason is of course "because
its popular." There's plenty of merit to OOP and there are certainly pitfalls.
OOP dominates the popular languages so you see the pitfalls most frequently.
The grass is always greener, etc.

It's not like any of these discussions about time to deliver or complexity are
based on statistical analysis.

------
_bxg1
I've grown so weary of dogmatism. Absolute answers are pretty much never
universally correct.

OOP is good for some things. FP is good for some things. Usually a project has
both kinds of things. If you ask me, pick a language like Rust, JS, Scala, or
Python that's competent in both and use the pattern that's right for what
you're trying to express in any given piece of code.

------
alkonaut
Because it’s a constant mental struggle to keep everything in mind when doing
“classic OOP”. Inheritance, mutability, weak type systems with nulls. All that
adds to the mental overhead.

It _is_ possible to program in a classical OO language without so much
struggle but it requires a level of discipline that takes 10 years or more to
aquire.

~~~
madhadron
I like the old metaphor of languages that are "programmer amplifiers" (usually
applied to Lisp, Forth, Smalltalk...). But the amplifier increases the noise
and problems as well as the good parts.

------
einpoklum
For me, it's:

1\. Because OOP lends itself more towards bloat with lots of boilerplate to
obscure what happens.

2\. Often stuck with what somebody else thought were the best abstractions -
while they weren't, or they were for them but aren't for what I'm working on.

~~~
ncmncm
You seem to be describing Java. Very often people complaining about OO are
really complaining about Java.

Java code is necessarily bad code, or at best mediocre code.

~~~
einpoklum
Also a bunch of object-oriented C++. To be fair - I've never written C# or
SmallTalk, so I don't know what those are like.

------
sys_64738
People are less complaining about OOP itself and complaining about inheritance
and polymorphism. If you've spent any time trying to figure out which method
is called by a python object then you'd generally agree.

------
crb002
Dead end career "architects" going OO crazy with inheritance, factories,
unessicary interfaces, ... instead of helping write more performance code or
deleting code.

------
luord
Another day, another entry in that one _decades_ old flamewar.

Each paradigm has its place.

------
segmondy
If you wish to learn French, Rust, Chinese or Java you can pick up a rule book
in your native language and get a grasp of the language.

If you wish to study code, what most people don't realize is that it's a new
language. It doesn't matter if it's written in a language you're familiar
with. You need to understand the domain, you need to understand the structure
of the code, the naming of the variables. That's a whole other language. Most
developers have to infer this new language by reading code. Imagine learning a
new language by reading a book written in that language. That's why Domain
Driven Design is popular in the OOP camp, talks about Ubiquitous languages and
bounded context. That's why DSL is popular in the functional camp, why Lisp
fans are crazy about Macros. It doesn't matter what the language is, if you
want to make your code a joy to work with. You need adequate documentation of
the code structure before folks dive into the code.

Imagine a student with no experience trying to learn about the Linux kernel
strictly by reading the source code compared to a student who first reads a
book on the Linux kernel then dives into the code.

This is what APL was hoping to solve and was pushing by "notation as a tool of
thought", but then it brought it own set of problem. APL is like Chinese,
Chinese notation is a tool of thought. You can read one Kanji and gain so much
from it, but you have to learn the damn notation first.

The only language that comes close is Declarative logical languages like
Prolog, but yet they suffer from some of the other faults and only holds
logically in closed-world assumption. Written by humans, so improper naming
can misleading too.

What's the solution for all? NOTHING! Some Developers will always hate on
whatever you use if you make them work harder than they want to.

With that said, the article was spurned by Ilya Suzdalnitski, who only seems
to care about medium claps. He wrote an article [1] about how OOP is a
trillion dollar disaster, then in about 2 weeks about [2] functional
programming sucks and is a toy and his solution was OOP. This is someone who's
happy to straddle the fence so long as he gets views.

1 [https://medium.com/better-programming/object-oriented-
progra...](https://medium.com/better-programming/object-oriented-programming-
the-trillion-dollar-disaster-92a4b666c7c7)

2 [https://medium.com/better-programming/fp-
toy-7f52ea0a947e?so...](https://medium.com/better-programming/fp-
toy-7f52ea0a947e?source=post_recirc---------2------------------)

~~~
tramav
> then in about 2 weeks about [2] functional programming sucks and is a toy
> and his solution was OOP.

which is clearly satire:

"PS> As most of you have guessed, the post is a satire. To all of the new
developers out there — don’t take this seriously, FP is great!"

------
BubRoss
Classes work well as interfaces to data. Thinking of a class as a mini
database makes a lot of sense.

Putting in anything complex that isn't directly related to managing the data
contained is where things start to fall apart.

Data formats are great. Simple data formats don't have to have dependencies,
just an interface to take out the details of accessing it. This is how
software communicates. Don't forget that the most used interprocess
communication is the file system.

Classes are not modular just because they can be wrapped up between two
braces. Dependencies destroy modularity and this definitely includes
inheritance. Complex data transformations that communicate using data formats
they both understand are how programs are made modular. Classes are a very
useful way of dealing with data formats.

------
api
It's an excuse to over-engineer. OOP encourages developers to over-think
object hierarchies and build baroque code that is prematurely generalized.

There is nothing intrinsically wrong with OOP and it maps well to certain
problem domains. The problem is the tendency of sophomore programmers to over-
engineer everything.

~~~
mieseratte
> OOP encourages developers to over-think object hierarchies and build baroque
> code that is prematurely generalized.

How does it encourage exactly? In my experience sophomoric programmers are
just as capable of over-engineering in a functional environment. Seems more a
function of cargo-cult behavior than anything else.

~~~
dentemple
How does one "over-engineer" a functional environment? By breaking functions
down into even smaller pieces? By minimizing side-effects even further than
before? These are all good things to do no matter what.

My one and only issue that I have with the "design"-side of FP is that it can
be tough to organize multiple functions in an intuitive way. (The "soup of
functions" effect, essentially).

It makes coming on to a new codebase tedious to trace, but I'd still rather
than dealing with spaghetti OOP.

~~~
imtringued
You can over-engineer point free style to create an uncomprehensible code
base. Point free style with more than 1 unapplied parameter is basically a
nightmare.

[https://wiki.haskell.org/Pointfree#Tool_support](https://wiki.haskell.org/Pointfree#Tool_support)

