
Sick of Ruby, dynamic typing, side effects, and object-oriented programming - blakehaswell
https://blog.abevoelker.com/sick-of-ruby-dynamic-typing-side-effects-object-oriented-programming/
======
sklivvz1971
Programming is hard. A few years back, in the 90's when most of the code in my
field was still mostly structured, and bad at that, a lot of people were
saying that OOP would sort it out. I was skeptical, not because I'm resistant
to change, but because it was obvious to me that doing OOP right was (and is)
very hard. Not that structured programming was easy.

Fast forward to today: programming is still hard, and actually it probably got
a lot harder. OOP did not sort it out. Most of the code in my field is object-
oriented, and bad at that. A lot of people are saying that FP will sort it
out. I am skeptical, not because I'm resistant to change, but because it is
obvious to me that doing FP right is (and will be) very hard. Not that object
oriented programming is easy.

Am I alone in thinking that fast forward a few years, once there is enough
rotten FP code written, we will be reading people ditching FP because it's the
root of all evil?

The facts are that programming is hard. Working with legacy code is hard.
Learning a paradigm well enough so the code you write in it is not total crap
is very hard, and requires years of practical experience if you are proficient
at another paradigm, let alone if you simply skimmed a paradigm and moved away
because it was too hard...

It's great that people want to move on from single-platform, single-paradigm
monocultures, with one caveat: breadth without depth is shallowness.

I'd like to read people treating languages and platforms as tools and not as
cargo cults. You don't read carpenters writing they'll ditch hammers for
screwdrivers because the old cupboard they are fixing uses nails. You read
carpenters debating the pros and cons of using hammers versus screwdrivers.
And you read better carpenters that debate how cupboards are designed, because
it is ultimately more important than whether they are glued, nailed or
screwed.

~~~
kitsune_
What I 'love' about object-oriented programming is that every other year there
is a new pattern or paradigm that is shoved down our throats by opinion
leaders and self-proclaimed OO-gurus. These architectural patterns all make
sense on the surface but by the time people try to apply them in real life and
realize that they are mostly a load of horse shit, the instigators have
already moved on to the next "big thing". And this pattern is repeated ad
infinitum.

~~~
gutnor
The problem is that the pattern that are being discussed ( or a pattern in
general, that's far from limited to OO ) are applied by a team of dedicated
developer, combing the code meticulously, generally with near-limitless
budget.

You read the story about how Linked In, Facebook, LMAX and you dream of
applying that.

That won't work. Those companies decided to go with their current
infrastructure after their previous one failed miserably and threatened their
billion making core business.

Real life for most developer is a lot duller. Very often you will have barely
enough to do what need to be done. Consistency, code gardening is difficult to
justify a budget for until the house is on fire. No matter how good the
pattern you use, the code will be shit if you don't have time to maintain it
properly.

------
hugofirth
The title "I'm sick of object-oriented programming" is misleading. The author
is sick of their work with Ruby and the fact that it is OO is one amongst
several complaints.

I use a mixture of OOP and FP day to day (mostly with the Java/Scala/Clojure
family) and have to say that both have their place. In large projects I
appreciate OO design patterns for clarity and flexibility (though maybe that
is just because it is what I'm used to), and FP's mandate on immutability for
the same.

Finally I have grown to whole heartedly share the author's dislike of dynamic
typing. I find Scala, not its more "pure" FP cousins Clojure and Haskell, to
provide the most productive balance of the above.

Anyone else like me: tried both and ended up walking the middle road?

~~~
psibi
I used to code a lot of Python earlier. After some time I started learning
Haskell, Scala and Clojure. Finally I ended up sticking up with Haskell
becomes of it's strong type system and ability to reason the code by just
seeing the types. And now when sometimes I write code in a dynamic language, I
must say that I write it more neatly.

------
wwosik
Ok, I get it. Mature Ruby codebase sucks. Integer division changes are
surprising. But what does it have to do with object-orientedness?

> break functionality into lots of small objects > use immutabile objects as
> much as possible (e.g. using thin veneers over primitives or adamantium)

are the guidelines that I'm using in C#.

> separate business logic into collections of functions that act on said
> objects (service objects) minimize mutation and side effects to as few
> places as possible

How does separating out functions minimize mutation?

> thoroughly document expected type arguments for object instantiation and
> method invocation with unit tests (mimickry of a static type system)

Yet another argument for static typing...

~~~
fetbaffe
The point is that OOP was introduced so people could continue coding with
globals (i.e. states), where the globals now lives inside different namespaced
containers instead the global container.

The effect is still the same though, your code is just the same old Rube
Goldberg machine.

------
bad_user
The problems exposed by languages like Ruby are not necessarily problems with
dynamic types. For example you can do reasoning about purity, side-effects and
whatnot in languages of the LISP family as well. Clojure for example is much,
much saner than Ruby in all the points listed by TFA - static typing is for
example by definition anti-modularity and anti-adaptability and note that I
prefer static typing over dynamic typing and Scala over Clojure. On the issue
of static versus dynamic one has to view this as a different school of thought
and to apply one versus the other depending on the needs of the project.

Uncontrolled side-effects are the real issue behind most of the accidental
complexity that we are seeing. We all badly need to adopt more abstractions
and techniques from functional programming.

Also, changing languages or idioms doesn't necessarily help with the exposed
problems. We also need a change of mentality in how we are doing software
development. Lets face it, when we need to do something right now, urgent,
that should have been done yesterday - no matter the language, no matter the
abstractions or idioms involved, we are bound to do stupid shit - because
there's accidental complexity and then there's inherent complexity and nothing
saves you from inherent complexity other than thinking really well about the
problem at hand and splitting it into simpler, more manageable parts.

This is also why TDD is a failure and complete bullshit in how it is
advertised. Tests don't save you from doing stupid shit. Tests don't tell you
whether your architecture is any good, they only tell you if your architecture
is testable. Tests don't prove the absence of bugs, they only prove their
presence. Tests only tell if you reached a desired target, not what that
target should be. And perhaps most importantly since this is touching the core
of their purpose, when uncontrolled side-effects are happening in your system,
tests are a poor safety net - anybody that had to deal with concurrency issues
can attest to that.

Agile methodologies are also trying to paint a turd. Yes, we should deploy or
publish as soon as we've got something to publish. We should pivot a lot. We
should communicate more with the end-users or within the team. And so on and
so forth. But it's an indisputable fact that some problems are hard enough
that they can't be solved by puking code and tests in a matter of hours or
days, or by adding more people to the team.

~~~
Ygg2
> This is also why TDD is a failure and complete bullshit in how it is
> advertised. Tests don't save you from doing stupid shit.

Why do people think tests are for that? Tests are basically same as free
climbers safety lines. They won't protect you from everything and sure they
are tedious to place, but once they save your tush, you'll be glad they were
there, and you weren't splattered across the floor.

I've seen lack of tests in practice and it's not pretty. Nope. Not pretty at
all. Basically lots of entangled undocumented, untested systems that you can't
refactor because your refactor just broke some code somewhere.

To demonstrate some of the bugs, if you accidentally type your username wrong,
the whole server crashes and resets. It was not pretty.

~~~
CmonDev
"you can't refactor because your refactor just broke some code somewhere" \-
picking a language that is not matched with first-class automated refactoring
(ReSharper, IDEA) was their first mistake (rather than lack of unit testing).

~~~
dozzie
Renaming stuff and pushing variables around is not refactoring. It's just some
editing work.

~~~
coldtea
You'd be surprised what transformation modern IDEs can do that IS refactoring,
not just renaming and pushing variables around.

Plus, you're wrong: a lot of refactoring is also about renaming stuff and
pushing variables around. You don't always have to rewrite everything in new
hierarchies and patterns in order to do a refactor.

~~~
dozzie
Renaming, pushing variables, changing their types, stuff like that. It's still
editing work. Can any IDE split the class into two according to methods'
responsibilities? Can it abstract a set of functions to a single generic
function? Can it get rid of unnecessary boilerplate code scattered around in
various classes? Can it change data structures used to store data?

Because refactoring is about making the code _simpler_ and _more flexible_.
Rearranging that IDEs do is only a method (and not the only one) to achieve
that.

------
tluyben2
I inherited a 6 y/o rails codebase and I worked on it for 6 months straight. I
am usually against rewriting things, but this is like going into one of those
abandoned houses and pulling off layer and layer of crap to find more
termites, cockroaches etc. Every time I had it 'working', I found all kinds of
weirdness, usually do to with forked GEMs to the old dev his personal github,
which where not only old/ancient but had stuff bolted onto them so they could
not be upgraded in any way.

So rewriting now... In F# (and C# where handy). I like Ruby but for projects
like this I have seen it fall over too often; most Rails dedicated companies I
know deliver great projects but they don't have to do long term support. I
would like to see how that would work out as I see companies in the wild
struggling to find devs _willing_ to support their codebases. This is not a
gripe with Ruby/Rails per se, but (in my experience!) Python programmers who
do large Django (or other frameworks, but I encounter mostly Django) projects
are more disciplined so less goes haywire, there are too many people who can
do JS, so you'll always find people willing to work on your crap. Ruby is in a
niche but popular spot; hard to find coders, some coders are not so good and
yet enormous projects are created in it.

------
pling
I get this periodically. I have to walk away and go and do something else for
a bit before I go nuts. This is usually after debugging some patternitis rats
nest that is completely over-engineered.

However occasionally amongst the muck, a beautiful and elegant thing pops out
and makes it all OK. This event is getting rarer for me as our product evolves
though.

------
DanielBMarkham
The older I get, and the more I watch and help programmers (including
programming myself), the more I believe this is an OO/mutability problem.

We created OO, at least the C++ version, in part as a way to create boxes of
code -- a reusable module system. But what happened was that we created a huge
stinking pile of mutability and hidden dependencies. If I'm looking at a
method in an object that takes one parameter, I literally have no freaking
idea what the current state of the object is, what the current state of the
parameter is or might be (and let's assume the parameter is itself an object
or graph of objects). In fact, it's impossible for me to reason about what the
hell I'm looking at. That's why we are forced to use the debugger so much.

Pure FP takes that all away. I have data going in, I do a transform, I have
data going out. If my data is clean and my transforms are broken down enough
to be understandable? It just works.

We keep trying to bolt on solutions like TDD to a fundamentally flawed model
of development. Damn, I hate to say that, because I _love_ OOA/D/P. I'm not
giving it up, but my current programming practices consist of using OCAML/F#
and pure functions to begin with, then "Scaling up" to objects as systems get
more mature. If I've got a big closure, I'm probably looking at an object. So
far I've found that scaling up is not necessary. I get more mileage from
composing my functions into command-line executables, a la unix, than I do
sticking everything together. But that could change.

It's right to be discouraged. There's something deeply wrong here. A big
change is coming to software development.

------
otikik
I am simply not convinced that static typing resolves as many bugs as its
proponents claim. The bugs I have are very rarely related with the type of a
variable. They are incomplete/incorrect implementations of business rules. The
type system doesn't solve that.

The other point of the article is that dynamic typing makes code rot. I am not
convinced that static languages do any better. Code rot is not a problem of
the typing system, it's a problem with the programmer writing the code, or the
environment he's in. Let's see what happens when he inherits a 5-year-old
Haskell codebase.

That said, I think the OP will do good in learning other languages. That
always helps.

~~~
lmm
> The bugs I have are very rarely related with the type of a variable. They
> are incomplete/incorrect implementations of business rules. The type system
> doesn't solve that.

It doesn't until you encode the business rules in the type system. But in a
well-designed language that's actually fairly easy.

> The other point of the article is that dynamic typing makes code rot. I am
> not convinced that static languages do any better. Code rot is not a problem
> of the typing system, it's a problem with the programmer writing the code,
> or the environment he's in. Let's see what happens when he inherits a
> 5-year-old Haskell codebase.

Having done both, it's far easier to port an old statically-typed codebase to
newer versions of its dependencies than to do the same for an old dynamically-
typed codebase. Compare a Wicket upgrade (seamlessly smooth, and the compiler
will catch anything you've missed) with a Rails/Django upgrade (batten down
the hatches, hope you've got high test coverage, and even then you'll likely
have something break).

------
pmontra
The problems I experienced with TDD in Rails applications (it's about the only
way I'm using Ruby) didn't derive from object orientation or dynamic typing.
They came from time and money constraints, especially in those one hour or one
day rushes to get a new small functionality into the code base and deliver it
into production. If a company has an internal development staff the technical
debt can be repaid later on. If a company works with consultants paid by the
hour, there might be never enough money to do it. An application with
reasonable test coverage can quickly turn into an application with 100% broken
tests and weeks of work to fix them all. But this isn't about Ruby or OO, it's
about customers and the amount of money they want to spend no matter how good
you are at explaining them what's happening to their software.

I have a Rails 3.2/Ruby 1.9.3 application that will be hard to port to Rails
4/Ruby 2.1 because of that. The point of the original post could be that
writing that application in Haskell would require less work on tests so we
could have less technical debt by now. Maybe. But when integration tests break
(originally run with Selenium) because the UI changed so much and there are
many new functionalities to test, I don't think the language can help. It's
back to having enough budget.

------
teamhappy
I think it's fair to say that 'everything is an object' was always a bad idea.
I'm a little surprised that it took Ruby devs that long to realise that (Java
devs still seem fine though).

My favourite example is the 'Utility' module that almost every project ends up
with at some point. Why would that ever be an object? In C++ you'd open up a
namespace and trow a bunch of free standing functions at it. Doesn't have to
be more complicated than that. Classes are supposed to be one method of
abstraction (among many others) that programming languages offer to us to
structure our code.

The real problem with OOP aren't objects though. It's inheritance. Complex
inheritance graphs are probably the best way to couple supposedly independent
parts of your code as tightly as possible. And they're notoriously hard to
wrap your head around. I guess a good example are component based scene graphs
(again, in C++). Whenever you're implementing some sort of graph, chances are
you start by writing a class called 'Node'. That's fantastic as long as you
stop the chain there. Each individual object in your scene should be a
subclass of Node that has any number of independent components (mesh
component, audio component, AI component, what have you) attached to it.
Favoring composition over inheritance is always a good idea as far as I'm
concerned and I'm happy to see languages like Rust adopting it.

I don't want to get into the whole TDD thing right now. All I'm gonna say is
that assuming your code didn't break anything because all tests passed is a
risky business and testing JavaScript UIs might not be as useful as you think.
Having said that, Cinder ([http://libcinder.org](http://libcinder.org)) had a
bug in it's matrix multiplication code not so long ago that could have easily
been detected with unit tests.

------
barking
He's inherited several rails codebases and has to maintain them.

Sounds like the 'other peoples code' problem to me.

Just like all non trivial abstractions are leaky (Joel) I guess all non-
trivial applications are 'hairy'

~~~
fetbaffe
No, I have seen tons of times when one developer on a single code base build a
rats nest for themselves by just doing OOP.

Sure the objects or classes where probably not perfectly designed or the
choices of the correct objects/classes to begin with, but that is the problem
with OOP, you don't know if the main building blocks you are using are the
correct ones.

~~~
cLeEOGPw
So you are saying it's impossible to build a rat's nest with FP? It's problem
with programmer, not with tool.

~~~
fetbaffe
Uh? Where did I write that? Why are you making up what I wrote?

I guess your assumptions are in line with the OOP programming style... ;-)

You can make a rat's nest of any coding paradigm, however I would argue it is
easier to do it with OOP.

------
Shorel
I was sick of Object Oriented programming the first moment I had to deal with
an API built with OO that replaced a previous API without it.

It was the WordPerfect 6 something language, replacing the WP5.1 macro
language.

I had built a perfectly reasonable autocorrection engine, it handled typos,
misplaced commas and periods, adding accents, and a few things more.

The Object Oriented macro language in WP6 removed any possibility to make my
macros work, in exchange for adding silly graphic buttons.

Now I like C++ and D, but they are not 'pure OO'. Therefore I hate Java.

------
phazmatis
Most of the points he makes are a byproduct of expecting too much from other
people. I.E. gem authors, or misunderstanding why something exists I.E. the
ruby standard library, which is a motley crew of modules meant to let people
write hacky scripts a la perl. This is why I'm getting away from
magic/cleverness as much as possible. Clever solutions usually rely on the
dark corners of a language/ecosystem, which might break in the future.

------
vfclists
When Edsger Dijkstra pronounced _Program testing can be used to show the
presence of bugs, but never to show their absence!_ had your Pa met your Ma?

------
erokar
I suspect Rails the framework is as much to blame here as Ruby, OOP or dynamic
typing.

The siren song of static typing is loud today. Robert Smallshire has given
convincing -- and even evidence based -- arguments that it increases
development time while catching only a very small percentage of bugs:

[http://vimeo.com/74354480](http://vimeo.com/74354480)

~~~
Rapzid
Possibly but.. Having had to dig into the Chef client code base way too
often.. Large ruby code bases can be a special kind of hell.

------
eloisant
Just use Scala, and you'll get to love object oriented combined with
immutability and functional programming.

------
bdcravens
I almost had to stop reading when I hit the quote from @HackerNewsOnion. Does
the author realize that's a parody account?

~~~
elwell
Of course OP knows. Read it again with that in mind and it makes [more] sense.

------
enupten
I guess we all agree that one way to get around the burden of reasoning around
mutable state is restricting the language.

I find that an equally reasonable way is to be able to add new language
constructs to make this reasoning far more (humanly) tractable. You can do
this with functions, and objects and so on, many a times, but without proper
macros, you may lose far too much in terms of performance (in a dynamic
language).

------
notastartup
I've never written tests for my projects. I hate writing tests because almost
certainly, as I'm creating a new software, things change. I'm focused on the
changing part all the time I hate being bogged down by having to write a
script that tells me everything is fine.

On a large scale project, I understand the need.

~~~
collyw
I agree with this. You (I) waste as much time trying to work out if the test
is wrong, or the code is wrong. Fiddle until the bar goes green. Doesn't help
you focus on the main problem. Show it to the users, and the requirements
instantly change anyway.....

In some cases automated tests are helpful, but not everywhere.

------
90hourweek
The original headline is this:

"Sick of Ruby, dynamic typing, side effects, and basically object-orientied
programming"

He's sick of OOP in Ruby, not of OOP in general. Ruby's dynamic typing means
you have one type, "the dynamic type". The compiler leaves you entirely on
your own as static analysis is impossible. It means many more tests,
assertions, and runtime error conditions. Most OOP techniques have evolved out
of, and rely on strong static typing, Ruby isn't that kind of language.

OOP in Ruby is the inevitable result of many Ruby projects growing in scope
and size. When you reach that point, a better way is to move part of the
project out of Ruby and into a language that can handle that scope and size.

P.S.: Any communication with the outside world is a side effect (ex. network,
file, database I/O), so sick of it or not, you better get used to it. Haskell
masking side effects as monads through a language loophole isn't making things
significantly better.

~~~
frowaway001
> P.S.: Any communication with the outside world is a side effect (ex.
> network, file, database I/O), so sick of it or not, you better get used to
> it. Haskell masking side effects as monads through a language loophole isn't
> making things significantly better.

Eh what? Even as a Haskell non-user, this just doesn't make any sense.

a) Haskell doesn't "mask" side effects b) The fact that monads are involved is
completely irrelevant c) It's not a language loophole

~~~
knz42
a) side effects are "masked" in Haskell in that a function that is generic
over any type of monad _may or may not_ incur side effects at run-time,
depending on which actual monad it is used with.

b) see above - because monads as a type class exist, a function may be written
with a type signature that does not indicate in any way that it will be
eventually used over IO.

c) the fact that the Haskell denotational semantics are entirely silent over
what happens at run-time with the IO monad is definitely a loophole. From a
birds view, a Haskell program is a giant expression that reduces to an object
of type IO, and what happens with that object is entirely outside of the
language semantics.

~~~
chrismonsanto
a-b) The objects of type IO are values, just as any other monad. It is true
that polymorphic functions can be instantiated with type IO, just as they can
be of any other type. How you think this supports the assertion that side-
effects are "masked" is beyond me.

c) The language boundary of Haskell typically ends at the production of an IO
value. You can easily give an operational semantics to many IO operations, and
in fact there are papers that do this for simple IO operations such as putStr.
It's not possible to give a full operational semantics for IO in _any_
language, not just Haskell. Of course you are going to model console I/O,
references, exceptions, concurrency features (all of which have been done).
But these aren't the only kinds of side effects. Does your model account for
the network, and all its complexities? Does your model account for power
failures? Does your model account for cosmic rays? Most models don't, but
nobody calls them loopholes, nobody implies it's a big cover-up. Every model
is going to have a boundary, and Haskell's seems good enough to me. It's no
more undefined than, say, ML.

------
aosmith
Sounds like you need to spend some time with go!

~~~
derengel
now he'll have two problems!

------
dragonbonheur
I'm surprised those shiny new languages still can't do what was considered
normal in good old BASIC. And all programmers nowadays go "Meh! BASIC.
Considered harmful! Will permanently damage your brain!!!"

Come on people, FreeBASIC has really great options for object-oriented
programming and could use your skills.

~~~
da02
Fun fact:

"Since the only computer language Richard [Feynman] was really familiar with
was Basic, he made up a parallel version of Basic in which he wrote the
program and then simulated it by hand to estimate how fast it would run on the
Connection Machine."

[http://longnow.org/essays/richard-feynman-connection-
machine...](http://longnow.org/essays/richard-feynman-connection-machine/)

~~~
dragonbonheur
That's a really cool blog post. Makes me wonder about a lot of stuff:

What were the projects and discoveries for which the connection machines were
clearly essential?

Are there connection machines that are still in operation?

What happened to the old ones?

Does Danny Hillis now keep a cluster of GPUs running somewhere instead of his
old hardware?

Would connection machines be more useful now than in the past?

Is it the right time to boot up thinking Machines 2.0 ?

~~~
jerven
Parrella boards and cray xmt both are probably the closest you get to
connection machines today.

