Hacker News new | ask | show | jobs
by zak_mc_kracken 4291 days ago
That's a pretty underwhelming case against objects, and equally underwhelming in favor of functional programming.
2 comments

Agreed. The problem is, what you're asking him to do is really hard.

Why was OOP considered a good idea? Before OOP, programs were just structs and functions that operated on them. But as programs got larger, that approach broke down. Someone on a team of programmers would create an instance of a struct, but would initialize it in a way that some function (written by a different programmer) would regard the struct as having an inconsistent state. Or some function, which was meant to only be a helper function for other functions that were the API, would be called directly by some ignorant and/or lazy programmer. The result was increasing chaos as programs got larger.

OOP was viewed as the fix to that kind of problem. It was somewhat successful as a fix, too.

So the problem with most of these pro-FP articles is that they show you small examples. But the pre-OOP style worked fine on the small examples, too. In fact, almost any style works on small examples.

And showing that I can write the same thing in fewer lines by using FP isn't the answer, either. It's like saying that your algorithm has a smaller scaling constant than mine does. That's fine, but first let's talk about whether your algorithm is O(n^2) and mine is O(n log n). That is, if your approach scales worse than mine for large problems, then showing me that your way is more efficient for small problems completely misses the point.

But to build a convincing case for that, you'd have to do something like having a team of competent OOP programmers write a large-ish program (say, 10 person-years of work), and have a team of competent FP programmers write the same thing, and report on the results. Oh, yeah, and have the teams maintain the programs for five years. That could be a convincing paper, because it would address the actual issues.

This is the argument I would use against FP. It's an open question -- to some degree.

Couple of notes. First, have you seen what real-world large-scale OO looks like? Dude, it ain't pretty. We're swimming in projects that are staffed at 10x or 20x the number of coders they probably really need, and a lot of time is spent in support activities.

Second, maybe the real question here isn't one of scale, it's how the model falls apart under strain. A good encapsulated system should offer you a bit more defensive programming protection than an FP one. But if you're using compsable executables, while testing at the O/S level? Meh.

I know why we went to OO. And let's not forget OOAD, a beautiful way of joining analysis and design about the problem with the solution itself. I'm of a mind that OOAD might live on even once the world moves to mostly FP.

I think maybe that OOP was a stopgap position; a place to try to build a firewall against the encroaching overstaffing associated with Mythical Man-Month management. Now that programming is a commodity, however, we're seeing diminishing returns. Don't know.

I am much less convinced of the "We need OO for large scale projects" argument now than I was two years ago. I expect this trend to continue. We might be able to solve the scaling problem with things like cyclomatic complexity limits on executables, or DSL standards. Not sure of the answer here, but I think we're going to find out.

Programming is a commodity? In a generation I hope so - now?

And to be fair I think that OoP and FP are the wrong paradigms for handling bad management of a large project. Open source methodologies are eating into that (I have just started at a major Fortune 500 with effectively a huge open source project inside it's employees) and even without that a good focus on risk management will help

In short, talking about your problems and taking early steps to resolve them will do more to fix a project than moving from OoP to fp.

> I know why we went to OO. And let's not forget OOAD, a beautiful way of joining analysis and design about the problem with the solution itself. I'm of a mind that OOAD might live on even once the world moves to mostly FP.

Never heard of it, but sounds interesting.

This is quite a good article on exactly that:

http://simontcousins.azurewebsites.net/does-the-language-you...

The same application written in C# and F# by the same programmers (the C# project took 5 years, the F# project 1). It in no way proves anything, but it's food for thought.

Personally I've had huge wins moving from OO to functional (Haskell and F#).

I've seen similar studies. I wonder, however. Functional programming is somewhat esoteric, so a random selection of programmers who practice FP are likely to be more dedicated to the craft of programming in general. I think the truly interesting question to ask would be, "Can we make software better by having the same programmers use functional programming?"
The second time you write the same thing is always a lot faster than the first time.
It's very hard to tell from that brief, offhand comment whether there's any substance behind it. I'd be delighted to hear more of your thoughts.
The sole argument in this article seems to be that OO systems introduce more complexity than is justified which results in larger code bases than an FP-based system would, which increases maintenance costs.

Then the article goes on to show some toy example solutions in FP style, without really touching on the challenges that don't show up until larger problems.

I can write a great Account balance summer program in Python OO too, and it'll be pretty, simple, and readable...

I'd really like someone on any side of this debate (and there are certainly more than two; for example, some people are advocates of "FP in the small, OO in the large") to write an article that does describe how their approach handles the challenges of designing and maintaining a large system.

I think such articles are rare because they're much harder to write than something like this. In complex systems it becomes very difficult to explain all of the tradeoffs and constraints that have led to the design you've ended up with, and it becomes harder to evaluate that design.

FWIW, at this point I agree with the author that modern FP has strong advantages over OO. One reason I feel this way is because extensive experience with large OO systems has shown me lots of ways in which OO causes problems. However, I admit that I don't have a similar level of experience with large FP systems. I'm sure that as FP gets more popular and more large FP systems get built, we'll find plenty of things to complain about on that side of the fence too.

So strong, pure FP coding will lead to a naturally decomposed system of small pieces -- once the re-factoring is done. There are no large pieces. That's the beauty of it. I believe that the premise of your question is in error.

The sucky part is that there is no guarantee that you will ever get there. A bad programmer or two and you've got a mess. Large FP systems crucially depend on high-quality coding. There is no place for everything to go, that's what the coders figure out!

Contrast that to an OO system, where things go where they naturally belong, but you really don't know what the algorithm is. Hell, you can spend days just wiring stuff up and putting stuff in place before the actual "real" code finds a home. But you always have a plan for where things go.

I don't think you can find a large, complex FP project because I think all the good complex FP projects are clusters of small executables.

What was the premise of my question that you thought was in error? I'm guessing the answer is in your last paragraph: there are no large, complex FP projects because such a large project inherently isn't good FP. We'll have to agree to disagree on that; in my opinion, some projects just don't cleanly decompose into a set of small, manageable subprojects.

So moving beyond that: if it's really true that large FP systems depend on high quality coding, I think FP is doomed.

One aspect of large systems is that you're no longer able to depend on consistently high-quality coding, because even if all the coders involved are highly skilled, there are new people being added to the project all the time and old people leaving. Knowledge and context gets lost, and new people write code that makes sense locally but doesn't fit the needs of the project as a whole. That's just reality. And even the experienced coders on the project lose the ability to consider the whole thing at once after a while. There is a limit to how much modularity and encapsulation can help with that, although they're very useful tools.

In a large scale project, it's really important to consider how features of the language and tooling and ecosystem help or hinder you in managing those kinds of problems. That's the sort of thing I think we could use more discussion about. And I feel completely opposite from you here - when it comes to dealing with imperfect coding and imperfect coders, I believe that modern FP languages have better solutions than modern OO languages. I think FP's popularity is only going to grow, exactly for that reason. But I also know there are places where current FP languages need work, or where the paradigm may be a poor fit, and I think it won't be clear where all of the weak points are until we've got more experience as a community with large FP projects than we have right now.

> I don't think you can find a large, complex FP project because I think all the good complex FP projects are clusters of small executables.

That's certainly one (optimistic) conclusion. Another could be that FP is not suitable to large, complex projects.

I'm not sure what you mean by "large" but Jane Street has apparently millions of lines of OCaml written. Of course, I'd argue that the fact that PHP is inherently unsuitable for anything complex doesn't keep Facebook from having a gigantic amount of it. The difference is that they had to write a type checker for it :)

I think the truth is more simple. Traditional OO is what is taught, traditional OO languages have tons of libraries, and there are tons of legacy code in traditional OO. You can easily find OO programmers. Nobody ever got fired for making OO systems, even when they end in barely-maintainable horrors full of mutable state.

That's great - if you can do it. The Unix design philosophy has held up well over the years.

But what you're doing is building small pieces that communicate with each other (via pipes, files, databases, or something similar). That looks almost like an OO design (pieces that communicate with each other over defined interfaces, hiding their internals from each other), except that the inter-object communication channel is both more inefficient and more impoverished in what it can express.

The rich typing of most OO languages and frameworks means that the "defined interfaces" are usually many and varied, and the system is less composable and reconfigurable as a result.

Unix pipes work so well in part precisely because the medium of exchange is so unstructured, with every "module" speaking the same language. You may need to massage the medium between two modules, but guess what, we have other modules like cut and sed and awk, that are not only able to transform the medium so that modules can be attached to one another, but themselves only had to be written once.

I think the Unix pipe pattern of architecture works very well in the large, and you see things very close to it elsewhere. C#'s Linq is fundamentally based on transforming iterator streams - little different, architecturally, than Unix pipes. The Rack middleware stack in Rails has a similar structure - every module has a single method, and recurses into the next step in the pipeline, and gets a chance to modify input on the way in and output on the way out. Both get their power by using fundamentally the same "type" on all the boundaries between modules, rather than module-specific types. It's the very antithesis of a language like Java, which even wants you to wrap your exceptions in a module-specific type.

I found your comment accidentally extremely funny. It's also illustrative of the problem here. I decided to reply not in order to goad you but to try to make some sense to the other OO folks reading along. Hopefully I can disagree and add some nuance without sounding like an asshole.

"That looks almost like an OO design"

Yes. Yes it does. You can only move data so many ways. I've got pipes, you've got messages. Life is good.

"except that the inter-object communication channel is both more inefficient and more impoverished in what it can express"

Really wanted to call bullshit on you here. If it's working, then somehow the efficiencies and paradigm of construction has overcome all these limitations, no? Lot of loaded words here. Are OO paradigms richer in terms of expressiveness? Gee, I don't know. You could say so. But in my mind it's an uniformed opinion. It's all pretty much the same.

Many times OO folks get really frustrated when they start learning FP. I know I did. The sample code did silly things like sort integers. Everything was simple, trivial, academic. Where's the real code? I would wonder. I'd read three books and we'd never get around to building a system.

Looking back, what I missed was that I was already looking at the real code. It was my mindest of wanting all of this expressivness, efficiency, and richness of expression that was preventing me from seeing a very important thing: we were solving the important problem!

Instead, I had a very fine-tuned idea of how things should look: this goes here, that goes there. This is obviously an interface, we should always use SOLID, and on and on and on and on. I had a feel for what good OO looks like. It's a beautiful, rich thing. Love it.

But this kind of thinking not only was not useful in solving FP problems, it consistently led me down the wrong path in structuring FP solutions, which was weird. I would look at things as all being the same -- when I should have been looking at the data and the functions.

Guy I know asked online the other day "What's the difference between microservices and components?" My reply "Everything is the same, but there's a difference in how you think about them. A component plugs in, usually through interfaces. A service moves things, usually through pipes."

If you're looking at a service as being another version of a set of objects passing messages, you're thinking about system construction wrong. Wish I could describe it better than that. It was something I struggled with for a long time.