47 comments

[ 4.6 ms ] story [ 72.0 ms ] thread
> Perhaps a sneaky HTTP request to localhost for desert.

Typo: dessert

I think that "OOP" is an incredibly overloaded term which makes it difficult to speak about intelligibly or usefully at this point.

Are we talking about using classes at all? Are we arguing about Monoliths vs [Micro]services?

I don't really think about "OOP" very often. I also don't think about microservices. What some people seem to be talking about when they say they use "OOP" seems strange and foreign to me, and I agree we shouldn't do it like that. But what _other_ people mean by "OOP" when they say they don't use it seems entirely reasonable and sane to me.

I think this is some combination of strawman, and subset of all cases. You can lament complications of OOP. You can also lament the complications of docker, kubernetes, HTTP APIs etc. These aren't mutually exclusive, and they don't span the breadth of programming techniques. I prefer avoiding all of these.

Anecdotally, I've replaced OOP with plain data structures and functions.

This is so much nonsense. Contracts and interfaces have little to do with OOP. If you don't like inheritance, then talk about OOP. It's fine. Many people, including myself, don't like inheritance. On the other hand, if it's interfaces and contracts that have you bothered, parse-dont-validate to your heart's content. If the domain allows it. Just don't drag unrelated concepts into this particular discussion.
I agree with you, that inheritance isn't all of OOP, but I think it is one of THE unique selling point of OOP. All the other things like abstraction, interfaces, encapsulation, polymorphy, etc. all exist(ed) before and without OOP.
> Other bright sparks jumped in on the action: what if this separation did not rely on the personal hygiene of the programmers - something that should always be called into question for public health reasons - and was instead enforced by the language? Components might hide their implementation by default and communicate only though a set of public functions, and the language might reject programs that tried to skip around these barricades. How quaint.

Sounds like C.

When was the last time you did OO against a .h file without even needing access to the .c file?

> And so, the process/network boundary naturally became that highest and thickest wall

I've had it both ways. Probably everyone here has. It's difficult to make changes with microservices. You gotta open new routes, and wait for people to start using those routes before you close the old ones. But it's impossible to make changes to a monolith: other teams aren't using your routes, they're using your services and database tables.

Someone is bound to quote Dijkstra here:

> To put it quite bluntly: as long as there were no machines, programming was no problem at all; when we had a few weak computers, programming became a mild problem, and now we have gigantic computers, programming has become an equally gigantic problem.

Nonsense. Network service layer separation solves a different problem than OOP. It doesn't replace it. Services and containers bring features and capabilities that OOP doesn't provide. It's orthogonal.
TL;DR: OOP is being replaced by microservices (and even more extreme ideas), which is much worse. Yeah, I have to agree with this author.

I will say that service-oriented architecture does have some advantages, and thus sometimes it's the right choice. Parallelism is pretty free and natural, you can run services on different machines, and that can also give you scalability if you need it. However, in my experience that architecture tends to be used in myriad situations where it clearly isn't needed and is a net negative. I have seen it happen.

I'm not really qualified to talk about either topic at length, but my impression is that the Microservice crowd is kind of a different group than the anti-OOP crowd.

As a total beginner to the functional programming world, something I've never seen mentioned at length is that OOP actually makes a ton of sense for CRUD and database operations.

I get not wanting crazy multi tier class inheritance, that seems like a disaster.

In my case, I wanted to do CRUD endpoints which were programmatically generated based on database schema. Turns out - it's super hard without an ORM or at least some kind of object layer. I got halfway through it before I realized what I was making was actually an ORM.

Please feel free to let me know why this is all an awful idea, or why I'm doing it wrong, I genuinely am just winging it.

I had a job interview where the guy asked me something along the lines of do I have experience with OOP or Microservices,or both. So I answered how I like both and feel that MS are Objects at the network layer, the dude cut me off and told me to stick to the question. Absolutely gut wrenching, I was being evaluated by who knows who, in a slot of 30 minutes, maybe his entire job was repeating the same set of questions 16 times per day and he was unironically writing down yes/no next to "Microservices?" "OOP"?
Microservices are a bad pattern. Function as a service is better, because that architecture tends to assume vertical integration within the function and you can leverage a shared business logic library across an organization. Having service-to-service communication is the thing that makes microservices suck, if you can give people autonomy while having a shared systems language and keeping computation on one system it works ok.
Many great design patterns have come from OOP and have found their home in functional languages or libraries.

Dependency injection has to be the most successful one, but there's at least another dozen good ideas that came from OO world and has been found to be solid.

What has rarely proven to be a good idea instead is inheritance at behavior level. It's fine for interfaces, but that's it. Same for stateful classes, beyond simple data containers like refs.

You can even have classes in functional programming word, it's irrelevant, it's an implementation detail, what matters is that your computations are pure, and side effects are implemented in an encoded form that can be combined in a pure way (an IO or Effect data type works, but so can a simple lazy function encoding).

There is a kernel of insight here that is pretty valuable. Interfaces are a form of security and is a result of a loss of trust. It's interesting to think about how far trust can be extended before it breaks down.
The idea of "we are replacing <thing> with microservices, which is much worse" is true for almost any <thing>, OOP or not.
> At around the same time, some bright spark realised that programmers - a population of people not known for good hygiene [ ... ]

OK, I'm out.

Oh gosh I clicked "Enter the tarpit". I hope I didn't blacklist my IP or something.

Silly link, though. I highly suggest going back and clicking on the link.

From one rambler to another: I’m not sure who or what this aimed at, as it goes all over the place.

Cloud: Separating resources from what gets deployed is a classic separation of concerns.

I don’t miss the days where I had to negotiate with the IT team on hardware, what gets run, and so on.

Personally, I believe the next evolution is a rebalkanization into private clouds. Mid-to-large companies have zero reason to tie their entire computing and expose information to hosting third parties.

OpenAPI: The industry went through a number of false starts on formal remoting calls (corba, dcom, soap). Those days sucked.

The RESTful APIs caught on, and of course at some point, the need for a formal contract was recognized.

But note how decoupled it is from the underlying stack: It forces the engineers to think about the contract as a separate concern.

The problem here is how fragile the web protocol and security actually is, but the past alternatives offer no solution here.

It's unclear to me what the author thinks OOP is, and what he thinks we are replacing it with. The main point of OOP to me is hiding internal state. So OOP is great for user-interface, because there's all kinds of state there (not just the model, but the internal state of the UI element, like the scroll position of a list or the selection range of a text edit). Microservices, in fact, could be considered "network objects" and a microservice framework as network OOP. The problem there is that normal making a function call is straight-forward. The call produce a failure result, but the call actually happens. On the network, the call might not happen, and you might not be aware that the call cannot and will not happen for some seconds. This is not likely to simplify your code...

OOP can be just about structuring code, like the Java OOP fundamentalism, where even a function must be a Runnable object (unless it's changed since Oracle took over). If there's anything that is not an object, it's a function!

Some things are not well-suited to OOP, like linear processing of information in a server. I suspect this is where the FP excitement came from. In transforming information and passing it around, no state is needed or wanted, and immutability is helpful. FP in a UI or a game is not so fun (witness all the hooks in React, which in anything complicated is difficult to follow), since both of those require considerable internal state.

Algorithms are a sort of middle ground. Some algorithms require keeping track of a bunch of things, others more or less just transform the inputs. OOP (internal to the algorithm) can make the former much clearer, while it is unhelpful for that latter.

> The main point of OOP to me is hiding internal state. So OOP is great for user-interface

One principal I pursue aggressively in UI design is NOT hiding state!

A client had written a script to calibrate an embedded system across several operating parameters. The program consisted of a TUI to capture setup parameters, then ran 5-layers of nested FOR loop for several hours. This original program lacked even a basic progress bar. You never knew what it was doing or when it would be done - it hid a lot of internal state!

You might say, "the TUI program was hiding relevant state; your program should only hide the irrelevant state." But as I iterated on the program I realized that literally all of the program state was relevant! So I meticulously crafted a GUI to display every operational detail on screen at all times. This included the state of each FOR loop, a plot of the intermediate results, the state of each TCP connection, the state of the unit under test, and the user-selected test parameters, the full path of the calibration files the test relied upon.

While the program had some "magic" (it would auto-recall the default parameters associated with the model under test, and would auto detect equipment types with a network scan) I future-proofed it by ensuring that ALL of the parameters were both visible (not hidden!) and human-overridable AND resettable (A reset-to-default option would appear when the user changed defaults, in case the selection was unintended.) The GUI is also wire silent (no network packets transmitted) until directed by the user to scan for/connect to equipment, and it gives a visual indicator while waiting for network responses.

The GUI also tracked test progress as a first-class file-saveable object, so not only was there a progress bar, but tests could be resumed if equipment connectivity was lost mid-test. And a 95% confidence interval estimate, shown as "between 9 and 13 minutes remaining" to help production techs plan their day.

Even when state is read-only, I still don't hide it. Once a test has commenced, the selectable test parameters cannot be changed, but displaying them on screen confirms to users that their 5-hour test was not started with the wrong parameters.

My big takeaway from this effort is that ANY hidden/inaccessible state is a liability. A user should be able to observe at all times what their program is up to.

What they mean is probably the original intended Alan Kay definition of message passing which interconnected systems do.
smalltalk is all UI and exposed all state, wish we had a fast modern language that did the same thing
> The main point of OOP to me is hiding internal state.

> Some things are not well-suited to OOP, like linear processing of information in a server. I suspect this is where the FP excitement came from

'Hiding' isn't good enough.

OO sells the dream of 'black-box' objects, where you only need to be concerned with the inputs and outputs, and only the object cares about its internals.

But what do programmers stick inside objects? The world! Files are outside the black-box, but inside a FileWriter object. Likewise with external webservers and databases.

That's where the FP hype comes from - or at least Haskell. I can encapsulate functions perfectly (and actually stop caring about the internals!)

If I try to stuff an Airplane inside flight-recorder, I get a compile error.

Microservices are a great solution to the problems you run into at high scale.

But they come at great cost. If you don't actually HAVE the problems they solve, do everything in your power to avoid them. If you can just throw money at larger servers, you should not use microservices.

> Every call across components acrues failure modes, requires a slow march through (de)serialisation libraries, a long trek through the kernel’s scheduler. A TLB cache invalidation here, a socket poll there. Perhaps a sneaky HTTP request to localhost for desert.

And this has tangible costs, too. I saved more than $10k a month in hosting costs for a small startup by combining a few microservices (hosted on separate VMs) into a single service. The savings in development time by eliminating all of the serialization layers is also appreciable, too.

I think it would be very nice if the author provided citations for their assertions about how OOP was adopted. I was alive and gigging as a coder in the 80s when people had interminable arguments about Structured Programming, unstructured programming, OOP and every now and again LISP or FORTH. None of what the author mentions rings true. Standard interfaces came DECADES before anyone started talking about OOP. Rationalizing standard interfaces was mentioned in mythical man month. Structured Development was all the rage in the early 80s when I started selling 6502 op codes. Half the people I talked to in the 80s insisted C++ WAS OOP while the other half found that quote from Alan Kay who said C++ wasn't what he was thinking of when he invented the term "Object Oriented Programming."

I think the author is correctly picking up on how messy changes in best common practice can be. Also, different communities / verticals convert to the true religion on different schedules. The custom enterprise app guys are WAAAAY different than games programmers. I'm not sure you'll ever get those communities to speak the same language.

OOP is dead. Long live OOP.

No, "we" are not replacing OOP with something worse. "We" are replacing layers of stupid shit that got layered on top of, and associated with OOP, with different renderings of the same stupid shit.

I have been programming since 1967. Early in my college days, when I was programming in FORTRAN and ALGOL-W, I came across structured programming. The core idea was that a language should provide direct support for frequently used patterns. Implementing what we now call while loops using IFs and GOTOs? How about adding a while loop to the language itself? And while we're at it, GOTO is never a good idea, don't use it even if your language provides it.

Then there were Abstract Datatypes, which provided my first encounter with the idea that the interface to an ADT was what you should program with, and that the implementation behind that interface was a separate (and maybe even inaccessible) thing. The canonical example of the day was a stack. You have PUSH and POP at the interface, and the implementation could be a linked list, or an array, or a circular array, or something else.

And then the next step in that evolution, a few years later, was OOP. The idea was not that big a step from ADTs and structured programming. Here are some common patterns (modularization, encapsulation, inheritance), and some programming language ideas to provide them directly. (As originally conceived, OOP also had a way of objects interacting, through messages. That is certainly not present in all OO languages.)

And that's all folks.

All the glop that was added later -- Factories, FactoryFactories, GoF patterns, services, microservices -- that's not OOP as originally proposed. A bunch of often questionable ideas were expressed using OO, but they were not part of OO.

The OOP hatred has always been bizarre to me, and I think mostly motivated by these false associations. The essential OOP ideas are uncontroversial. They are just programming language constructs designed to support programming practices that are pretty widely recognized as good ones, regardless of your language choices. Pick your language, use the OO parts or not, it isn't that big a deal. And if your language doesn't have OO bits, then good programming often involves reimplementing them in a systematic way.

These pro- and anti-OOP discussions, which can get pretty voluminous and heated, seem a lot like religious wars. Look, we can all agree that the Golden Rule is a pretty good idea, regardless of the layers of terrible ideas that get piled onto different religions incorporating that rule.

A voice of sanity. The submitted article has zero meaningful content.

This comment i posted in an earlier thread rehashing Inheritance vs. Composition for the gazillionth time is highly relevant here - https://news.ycombinator.com/item?id=45943135

OOD/OOP has not gone away, has not shifted etc. but is alive and well; just packaged under different looking gloss. The meta-principles behind it are fundamental to large scale systems development, namely; Separation-Of-Concerns, Modularization, Reuse and Information-Hiding.

I thought structured program was about language support for control flow, simplification and formalization of control flow and single return. Not ADTs.
I thought I expressed that: "I came across structured programming. The core idea was ... Then there were Abstract Datatypes, ..."
OOP today is really CBP (class based programming). Its really just imperative code hidden in methods that work on mutable state. Its gross. This is most common in Java, PHP and the likes.
There's a time and a place for all of these things. Like everything in life, many people pick the wrong time and wrong place.