79 comments

[ 5.0 ms ] story [ 174 ms ] thread

    "The object-oriented model makes it easy to build up programs by accretion."
On a similar note that object-oriented model makes it easy to write code when you don't understand the problem yet. "I know I'll need a Patient and a Doctor and a Diagnosis ..." Soon you have all these pretty objects and interfaces and Patient and Doctor inherit from Person and ...

I've seen people with literally dozens of objects who still had no idea what they were building or why and couldn’t answer basic questions about the problem domain.

Alan Kay's idea of OOP-- encapsulate complexity behind a simple interface, and separate the two while preferring stability in the latter-- was utterly sound and right. He wasn't saying, "go off and write opaque, complicated objects". He was talking about what to do when complexity becomes inevitable.

The SQL database (a brilliant, wonderful thing despite the hatred it gets) is an example. When you write a query, you don't tell it which indexes to hit and how to micromanage details. You send a declarative query to this "black box" that, most of the time, does the right thing.

I think Objects are a good thing, but they should be rare. Very rare. As with macros, only use them when the simpler tools (referentially transparent functions, immutable data) won't do. Files are a case where the object metaphor makes sense-- there's a bunch of tightly-wound connected state, and I/O is inherently stateful.

The problem with "OOP" is that it's "programming as micromanaging, inept businessmen understand it". Instead of math, it's Factories and Visitors and other nonsensical "big picture" bullshit that doesn't map in any coherent, reliable way to the underlying substrate (mathematics, logic) of computation. I'm sorry, but programming is a game where if one doesn't understand the details, one doesn't understand the fucking big picture (which is made up of extremely important details).

Files are a case where the object metaphor makes sense-- there's a bunch of tightly-wound connected state, and I/O is inherently stateful.

And user interface widget libraries, which are all about I/O. Even Racket's widget toolkit leverages the superb racket/class encapsulation mechanism.

We get by without OOP in the widget library (creatively called Widget) we use for a Haskell-flavoured language at work.
For UI code, you should check out functional reactive programming (FRP). It essentially provides first class time-varying values instead of implicitly modelling time with mutable state.

This makes UI code more declarative and allows you to create things like neat combinators. As an example, it's very easy to write a function like `when' with FRP, which could be used like this (code roughly from a game of life app I wrote):

    when (not <$> paused) (step <$ time)
Here `time' is just a stream of events every x milliseconds. So what this code does is create a stream of step events which represent stepping the life simulation forward at each time step, as long as the game isn't paused. `paused' is a value based on a button, but it could easily have multiple inputs.

So you get signals and event streams like `paused' and `time' from UI widgets (or the system), and then combine them into new streams that you can plug directly into UI widgets. This then lets the widgets themselves be much simpler structures with not internal state. In essence, this replaces arbitrary mutable state with an explicit dependence on time which leaves less room for making mistakes while also making it easier to write high-level functions like `when'.

There's a ton of other cool things you can do--this is just an example meant to illustrate the sort of abstractions you can use; it is by no means exhaustive!

I've found that FRP leads to much nicer UI code than callback-based OOP.

FRP seems deeply awesome. Thanks for explaining it.
>the superb racket/class encapsulation mechanism.

Superb? The racket class system strikes me as awful/embarrassing. The language at least looks functional in nature, but to do OO they implemented this ridiculous single dispatch mechanism (manually calling "send" no less!). Why on earth didn't Racket end up with a CLOS like system? They could have made anything they wanted, and yet they ended up with a system that will require people to write the Visitor pattern. Shocking.

Although it looks impoverished, it's really just a foundation for developing your own abstractions, and syntactic sugar goes a long way (I've bound the Alt-> key to → and use it for 'send').

CLOS-like systems can be built on structs with the racket/generic module and Typed Racket makes multimethods trivial.

The SQL database (a brilliant, wonderful thing despite the hatred it gets) is an example. When you write a query, you don't tell it which indexes to hit and how to micromanage details. You send a declarative query to this "black box" that, most of the time, does the right thing.

That sounds very much to me like 'A SQL database is an abstraction', and very little like 'A SQL database is somehow related to OO'. In facts it's really unnatural to map objects to relations, which is why you need yet another ORM abstraction on top of it, just to satisfy the OO silver bullet.

Programming isn't math. Let me restate that again: programming is NOT math.

OOP works and is a paradigm because people can relate to objects and narrative best. It has much more to do with narrative and story. The word "language" is by design. Good OOP techniques can create great products.

Whatever the code is, unless you're writing machine language, eventually, you compile to or run bits of existing machine code. The important part is encapsulating the complexity. OOP or not, that's should be the goal of any module. Not all the details are important all of the time. In fact, it's generally much more important to hide details so one can deal with large systems in an abstract way. In many cases, details are unavailable and black box systems have to be dealt with. The point is logical abstractions, not details, are the goal here.

Just because you can write it in machine language doesn't mean you should.

   "Alan Kay's idea of OOP-- encapsulate complexity behind a simple interface, and separate the two while preferring stability in the latter-- was utterly sound and right. He wasn't saying, "go off and write opaque, complicated objects". He was talking about what to do when complexity becomes inevitable."
I agree completely, I was only pointing out another problem with OOP (or, if you will, OOP done poorly) is that it leads to the trap I mention.
I know a company that used to ask in all seriousness "How would you model a car in an OO way?" during interviews, with the expected answer along the lines of Car, Engine, four instances of Wheel and so on. My friend totally stumped the interviewer asking him about the purpose of the modeling. You know, this revolutionary idea that a DMV might model a car slightly differently than a car mechanic.

Late nineties, good times, OO was the silver bullet back then :)

Yeah, I was asked to model a graphics program in an interview and got into a argument about why circles should not be a subclass of ellipse. I explained that, yes, mathematically it's a degenerate case, but in a graphics package circles have different algorithms and different user interfaces. They actually have more in common with squares than ellipses.

After about 10 minutes of no progress, I suddenly realized I would be working with and for idiots so I excused myself from the rest of the process.

Yeah, Liskov Substitution Principle. I believe that (mutable) circle and (mutable) ellipse is the chief example of the bad kind of inheritance wrt to this rule.
I'm reminded of Pirsig's comments on the multiple ways you could break down a motorcycle, for example.

The tyranny of the dominant decomposition is no joke, especially when single inheritance and single dispatch are so popular.

I wrote about this last summer: http://michaelochurch.wordpress.com/2012/08/15/what-is-spagh...

Inheritance (typically assumed to be part of OO, but not a requirement) is a big part of it. It gets nasty pretty quickly. Inheritance is the 21st-century goto, although it shares features with the even wonkier "comefrom" of INTERCAL.

Spaghetti code isn't just "bad code" but a specific kind of bad code where understanding a piece in isolation requires pinging about an ungodly number of places. There are a lot of causes of that, but usually it's poor software management and bad development practices.

"Inheritance breaks encapsulation," the elders said, and as with all extremes, they each have their problems. Language is a lossy codec for math/logic/thoughts, computer languages no less so.
The "elders" never said that. They invented inheritance because there was a need for it.

Inheritance is a great way to maintain encapsulation in the face of a messy world. Unchecked composition quickly gets you to a world where everything has to be public anyway.

It's just a figure of speech.
This is a case of coherence vs coupling, which is lost by OO developers. Everything is so tightly coupled that more spaghetti code is written up to not break the coupling, making the code more incoherent overall.
This is why almost all good investors pass on startups with weak or no technical cofounders.
What? Most of the business world runs on spaghetti code sold by successful software companies. Success has almost nothing to do with technical skill.
(comment deleted)
* What this often means, in practice, is that it provides a structured way to write spaghetti code. *

I've had to refactor code that my co-workers have written several times because they end up throwing code in a class where it works but doesn't "belong".

For example, the REST API I'm building has thin controllers, thick domains, and thin data access layer with various supporting models. I had a co-worker write a Domain object that acted like a model (a single object that should be instantiated, properties set, and a calculation function run).

I had to refactor all his code out into a reusable model and then build helper functions in the domain for the controller to consume.

Whenever I see that I need to do the same type of operation in multiple places, it tells me that code should probably be consolidated into a structured class to make sure that any bugs in the code can be fixed in one place instead of a dozen.

So in a way the code was structured in a class but was still a mess. OOP isn't just about classes and inheritance but about structure, architecture, and how classes interact with each other.

When you 'had him write it' maybe you should have specified it more clearly.
I've never understood these sorts of statements. You can write spaghetti code in a functional language too. Instead of objects floating around, you have functions. Instead of objects interacting with each other in various ways, you have functions interacting with each other in various ways. You can "build programs by accretion" in any language. Ultimately it all comes down to complexity. Simple code is simple, complex code is complex. You're not going to magically get around this by switching to a functional language. Right?
Well, if you're really programming in a function way, then you're not using side effects (or at least, the side effects are constrained). That means things are local, and you can safely compose functions without causing the behavior of other parts of the program to change.
(comment deleted)
Spoken like a true academic.
Or, you know, a software engineer. Good software engineers, after all, value things like low coupling; composability is like a stronger version of low coupling. (That is, composable things are not tightly coupled but decoupled things are not necessarily composable.)
Good software engineers certainly value low couplings. Unless it is a coupling with some code written in an obscure language with extreme (and masochistic) approach and with no common sense.
I'm not at all sure what your point is. There's nothing controversial about the benefits of referential transparency and immutable state, for modularity, composition and simplicity. What is obscure to you? It won't be to everyone.
The biggest thing in this regard a language like Haskell has going for it is purity, and therefore the concept of "no global state" taken to an extreme. Add to that referential transparency (which is a highly related concept anyway) and you get pretty strong "equational reasoning" where it is quite easy to trace, accurately, what's happening in a chain of calls - it's all transformation of data structures passing through.

If by "functional language" you mean JavaScript, then that's a completely different matter... :-)

Whatever you do, don't let some baby with a hammer to take some abstract and high concepts to the extreme, ruin your project and learn from it. Not in your project.

In the production code, stay with the mainstream. And limit your extreme approaches to research grade code, with limited lifetime.

We use Haskell in mission critical production code at my company and we are very happy with it. So do many banks in their pricing models and many other areas of application.

This may mean that we can't just go hire your average programmer, but we have also had a bizarrely low rate of bugs in production despite a high level of inherent complexity in what we do.

Based on what I've seen, codebases, that use non-mainstream languages and technologies have a tendency to fracture into parts written in a mix of languages and disappear in the rubble.

So let's wait a few years, and see, shall we?

(It's not that I don't like, or don't use shiny 'new' toys. It's just that in the long run it really really helps to use these toys only in the 'research grade' code. Depending on anything even a tiny bit out of industry mainstream in your key production code is a huge liability few years down the line.)

This is Amazon affiliate spam... check the `tag=...` in the book link.
I haven't read the book and dunno about PG's definition of spaghetti code, but "we can make all these types of modifications without even looking at the rest of the code" sounds like the opposite of what all people I know call sc. I thought that a necessary property of spaghetti code is that almost everything is connected in a way so you can't make a change by only changing something in one place because everything is connected in weird ways because of the lack of structure, so you need to keep the whole program in your head while working on it.

Isn't the whole point of well structured programs to be able to work on them while holding as little of the program in your head as possible, so you can work on part of it and be able to "make all these types of modifications without even looking at the rest of the code"? If you have a program that can "evolve" successfully without the need for anyone to "hold it in its head", then a large team can work on it and you can usually replace a 10x programmer with a swarm of 1x ones, basically a pointy haired boss's wet dream...

If you have a program that can "evolve" successfully without the need for anyone to "hold it in its head", then a large team can work on it and you can usually replace a 10x programmer with a swarm of 1x ones, basically a pointy haired boss's wet dream...

Why is that the PHB's wet dream? I mean, by observation I agree with you. That is the case, so I am not challengingyou on that. But what could be the underlying reason, seeing as 10x programmers are only 1.5-3.0x as expensive?

It seems like PHBs shoot themselves in the foot, repeatedly, without mercy.

PHB's tend to measure themselves by how many people they're in charge of; better 10 guys than 1 that's productive as 10. PHB's aren't entrepreneur types, they're middle managers who require underlying to justify their existence, the more the better.
That's been my feeling about it, too. Headcount and control rather than actual productivity. Also, I feel like middle managers have a terrible incentive profile. If an underling really shines, then it reflects well on the underling. If one underperforms or makes a mess, boss gets shat on for not keeping them in line. It's easy to rip on middle managers, but they have a shitty job and it's not their fault. It's just structured badly.

I think it's easier to understand why middle managers are the way they are once one understands their incentive structure. They participate in an employee's downside but not upside (she did it herself) so of course they're going to be the way they are.

I may be radical but I think open allocation is the only answer for software development. All the nonsensical process that grows up around closed allocation seems archaic and stifling. I think typical middle management is useless. What you really need are HR-independent mentors. Aside from mentoring, the other thing managers can do (firing) should be so rare in a well-run company that you only need one per few hundred people.

I recommend reading about the Gervais principle![1]

[1]http://www.ribbonfarm.com/2009/10/07/the-gervais-principle-o...

If you have the time, you might want to check out my blog. I've covered that topic in exacting detail.
just had a quick look and am as excited reading this as checking out more espisodes of 'the office'! (I only started watching the american version recently. Originally I dismissed it as just another copy-cat of the original UK, but I'm beginning to get into it).

I didn't read any of it yet, but just the thought of having more to read about it makes my life already better :)

EDIT: I just realised who I was "recommending" this too. Well, at least it was worth it for me :)

They would also have trouble identifying the 10x programmer to begin with, and with the pointy haired-ness have trouble retaining them.
It is trivial to identify a 10x programmer.

Take any project (or platform) that uses quirky and individualistic style, preferably written in an obscure language. Any programmer that has been working with such a project for a year or two, would be a 5x programmer. Any programmer that has actually started that project would be a 10x programmer. Why? Because an amount of effort that any developer, unfamiliar with an obscure approach has to spend is 50x.

So a 10x programmer is one who writes crappy code? I think you have your definition backwards.
One who writes quirky and individualistic code. Not crappy. It could be well organized. And even good. And even solve the problem, at the time when it was written.

But. If that code is approachable by any regular developer, when the original programmer would not be 10x. And management and peers wouldn't think about the original developer as 10x.

But if, the code is quirky and individualistic... a funny thing happens. Suddenly whoever works (or can rise up and work with that code for whatever reason) is 10x. And peers and management would see them as 10x.

I've seen that quite a number of times. Many times as 10x, as 1x and even a few as 0.1x.

Good code is dead simple to read and understand. That is what makes it good, because sooner or later, someone will need to read it and maintain it.

Getting to that point is difficult, and may require a 10x programmer. But the end result is simplicity.

I think you misunderstand grand-parent. Once again I will use a quicksort example - we all know quicksort, even if not iterative, then surely recursive version, right? Ok, so here goes quicksort implementation that is dead simple and easy to read:

    quicksort=: (($:@(<#[), (=#[), $:@(>#[)) ({~ ?@#)) ^: (1<#)
It's in J. Someone who wrote this has much higher chance of being 10x than someone who implemented the same algorithm in Python. That's all I think grandparent wanted to say and if so then I agree completely.
Someone who wrote this has much higher chance of being called 10x by peers and management. And someone who has to support that code has much higher chance of being called 0.1x by pears and management.
>One who writes quirky and individualistic code. Not crappy. It could be well organized. And even good. And even solve the problem, at the time when it was written. But. If that code is approachable by any regular developer, when the original programmer would not be 10x. And management and peers wouldn't think about the original developer as 10x.

Nope, still got it backwards.

The characteristic of a 10X programmer is how FAST he can write GOOD code that solves a particular problem. Neither individualistic, nor quirky. He doesn't even have to read Ayn Rand.

If it's not code that his 1x coworkers can understand, then he's not 10X, just show-offish and hackish.

To give some examples: Dennis Ritchie and Brian Kernighan. Linus Torvalds. Poul-Henning Kamp. Zed Shaw. Notch. John Carmack.

All of those are/were very much 10X programmers. But no obscure languages and nothing quirky and particularly individualistic about their code.

I think you have mixed the notion of the 10X programmer with the notion of the "cowboy coder" (with traces of crazy genius, e.g the autonomous, quirky, Lisp/Haskell/J/whatever yielding programmer who completes some huge project in his own peculiar way in a short amount of time).

The problem is, that the consensus about a particular developer in a particular project -- to call that developer "10x, 1x 0.1x" -- is a consensus of peers and management.

And peers almost always lack the information to make the objective call. If they'd had that information, they wouldn't have called that developer a 10x. And that's one of the reasons, why you never see normal people calling themselves 10x, by the way.

The ten 1x programmers tend to turn against the 10x programmer before he/she has time to manifest, to protect their own 10 jobs.
Very fucking true. Also dangerous is the 2.5x who thinks he's a 10x, convinces management of this, and then drives out everyone better.

(For my part, I'm only a 6-8x. I'm fairly new to software and I also spend too much fucking time on activism.)

Risk management.

Assuming the PHB can hire 10 junior devs or 1 senior dev at the same cost:

If you have 10 junior devs and 1 decides to quit, the PHB can swap him out fairly easily - he just has to wait for graduation day.

If you have 1 senior dev and he decides to quit, the PHB's hands are severely tied, especially if the company is located in a place where talent is lacking.

This is also the reason why mainstream languages will likely remain popular forever in the enterprise world - no one wants to take a chance on a language that only 5% of devs know.

> This is also the reason why mainstream languages will likely remain popular forever in the enterprise world - no one wants to take a chance on a language that only 5% of devs know.

Unless they have a legacy system. Or what percentage of developers know Cobol these days?

They're not taking a chance on a language only 5% of devs know, precisely because they know how painful it is to be chained to a legacy system. So they do every new project in the industry standard language, which is Java.

Problem is, the industry standard used to be COBOL. Sooner or later, if/when Java falls out of vogue and stops evolving, they will end up with two legacy systems instead of just one.

You've just proven the point. Commit to the popular language because finding maintainers in X years will be that much easier
I can't find the link right now, but I saw an ad from a technical school here in Sweden only a couple of weeks ago advertising their new 1 year Cobol developer program.
I'm not surprised. Over here in Malaysia, almost all banks still run a COBOL backend.
Yea I remember the ad listing a number of large Swedish banks and insurance companies that still use COBOL as an argument for why you should learn COBOL and why it would be easy to get a job afterwards.
This is a good point, but it serves to point out what others are not bringing up. The truth is, managers know programmers aren't cogs and can never be. How could they not? The issue is that their managers believe or really want to believe that programmers are cogs, so the lower manager can cut all experienced programmers and replace them with the cheapest labor they can find. What shows up in the short term is a cost savings, and therefor probably a promotion. Yes, since these new programmers don't know the system it's destined for failure, but who cares? By the time that happens the PHB will be in a new position and no longer responsible for this mess they made.

The true plague or our industry and everyone else's is short term thinking, and I don't see how it could be fixed at this point.

But what could be the underlying reason, seeing as 10x programmers are only 1.5-3.0x as expensive?

I'd venture that it's because something like less than x% of all programmers are elite; where x is some number between 5 and 10.

In this case, if you are PHB and have a budget of y for staff (where y <= average) and time variable of z (where z <= average) for a release date - it would appear that you are an incompetent PHB if you believe you can hire an elite programmer to solve your problem(s).

I think people are not as rational as they seem and it's basically a form of power hunger - PHBs feel more powerful when the distance between them and their employees is larger: one feels much more powerful having 10 people well below him than having 1 person a little below him, and 10x programmers that also have social skills in a company where IT matters will have a say in lots of things, even not IT related and even if not in a direct way, so they end up closer to the PHB on the power scale than each of the 10 1x ones, which is a bad feeling... Now if the 10x is totally lacking in social skills and introvert, that's ok for the PHB, but if lacking in social skills and more of an extrovert, it's bad again, because although he wouldn't have a say in things because he's "the smart asshole", he'll make everyone, including the PHB, feel and look stupid (and they probably will be 20 iq point below him and they'll know it and feel somewhat demoralized by him).

Basically the 10x guy is uncomfortable for all guys above him (not only in software but in any other field that has a 10x skill gradient) that lack self-control, self-knowledge and people skills (what's called "being wise"), and most PHBs are "very not wise".

Why is that the PHB's wet dream?

Because it makes the business more failure tolerant. Finding even one 10x guy is tough - many teams will have only 1 or 2 of them, and a swarm of 1x guys.

If the 10x guy is on vacation, quits, or has something more important to do, you can throw one of the 1x guys at it.

You don't need nefarious "I hate the 10x cause I'm a psychopathic PHB" motives to explain this one.

> I haven't read the book and dunno about PG's definition of spaghetti code, but "we can make all these types of modifications without even looking at the rest of the code" sounds like the opposite of what all people I know call sc.

That was exactly my thought as well, I had to reread the part twice to make sure. This is the definition of maintainable (or maybe even well-designed) code when all its parts are carefully isolated.

I think the point is that writing code on isolated parts without thinking about the overall purpose and architecture of the program leads to bloat, repeated functionality and diverging paradigms/conventions in the same codebase. I agree that's not the traditional definition of spaghetti code, but it's a problem in many large software projects.

Adding that together, well designed code is the foundation of really bad code. That could explain a lot.

The quotation is nearly twenty years old. For context that's before Java [practically speaking] and before C++ was standardized - and when programmers of Graham's age had a background using PEEK and POKE and GOTO in BASIC or exposure to assembly and the older programmers had often seen plugboards in use.

I won't guess at Graham's definition today. He can speak for himself, anyway. But it resonated with me in the context of Rich Hickey's ideas - particularly "Are We There Yet?" http://www.infoq.com/presentations/Are-We-There-Yet-Rich-Hic...

As I understand it, an issue with [some] object systems is that when objects are made by aggregation, rather than inheritance, they are of a different type than each of their components. And this requires the programmer to write some code [however minimal] for the new type in order to reimplement any desirable feature of the objects from which it is composed.

In other words, the behavior of an aggregate of objects is undefined. Hickey's comparison is to data. Which he claims aggregates into more data. When, I ask myself "what is data?" lisp-a-cadabra - it's code. Which is the [structuralist] way in which I read Graham's note.

You're absolutely right. This is what is meant by spaghetti code; everything is connected and you can't tell what is connected to what until you start pulling things out.

I've only worked on one or two code bases that were truly spaghetti code and I replaced them both completely in short order.

Where I come from, we derisively called this "Lasagna code." It's not tangled like spaghetti, but there are many, many layers.
See http://www.paulgraham.com/noop.html for an essay from Paul Graham about a dozen years ago that expanded on the dislike that he had then for OO code.

I do not fully agree with his opinion there, but he certainly has some valid points.

People who critisize OOP for its bad applications have mostly not understood it.
(comment deleted)