Live data from Hacker News

The Law of Leaky Abstractions (2002)

joelonsoftware.com

41–50 of 93 posts

Re: The Law of Leaky Abstractions (2002)

#41

I've long been having a hunch that we're currently in the "wild west of abstraction". I think we're missing an essential constraint on the way we do abstraction. My hunch is that this constraint should be that abstractions must be reversible. Here's an example: When you use a compiler, you can work at a higher layer of abstraction (the higher-level language). But, this means you're now locked into that layer of abstr…

Most ORMs give a way to integrate nicely with SQL if you need to reach down to that layer and still use the rest of the ORM features.

There is no silver bullet; everything is a trade off. Almost all of the time, the trade off is entirely worth it even if that gets you locked into that solution.

Re: The Law of Leaky Abstractions (2002)

#42

> Back to TCP. Earlier for the sake of simplicity I told a little fib, and some of you have steam coming out of your ears by now because this fib is driving you crazy. I said that TCP guarantees that your message will arrive. It doesn’t, actually. If your pet snake has chewed through the network cable leading to your computer, and no IP packets can get through, then TCP can’t do anything about it and your message doe…

> There are leaky abstractions I guess but not all are. A garbage collector that can cause memory errors would be leaky. I don’t know anything about garbage collectors but in my experience they don’t.

Garbage collectors are a rich source of abstraction leaks, depending on what you do with the runtime. If you color within the lines, no surprises, the garbage collector will work. Unless it has a bug, and hundreds of GC bugs, if not thousands, have shipped over the decades; but while a bug is an abstraction leak, it's not a very interesting one.

But go ahead and use the FFI and things aren't so rosy. Usually the GC can cooperate with allocated memory from the other side of the FFI, but this requires care and attention to detail, or you get memory bugs, and just like that, you're manually managing memory in a garbage collected language, and you can segfault on a use-after-free just like a Real Programmer. It's also quite plausible to write a program in a GC language which leaks memory, by accidentally retaining a reference to something which you thought you'd deleted the last reference to. Whether or not you consider this an abstraction leak depends on how you think of the GC abstraction: if you take the high-level approach that "a GC means you don't have to manage memory" (this is frequently touted as the benefit of garbage collection), sooner or later a space leak is going to bite you.

Then there are finalizers. If there's one thing which really punctures a hole in the GC abstraction, it's finalizers.

Re: The Law of Leaky Abstractions (2002)

#43

I've long been having a hunch that we're currently in the "wild west of abstraction". I think we're missing an essential constraint on the way we do abstraction. My hunch is that this constraint should be that abstractions must be reversible. Here's an example: When you use a compiler, you can work at a higher layer of abstraction (the higher-level language). But, this means you're now locked into that layer of abstr…

Lots of abstractions have an escape hatch down to the lower level, you can put assembly in your C code, most ORMs have some way to just run a query, etc. I think the question I have is, what benefit does this provide? Let's say we could wave a magic wand and you can operate at any layer of abstraction. Is this beneficial in some way? The article is about leaky abstractions and states > One reason the law of leaky abs…

It would help because you could tackle the problem at hand always at the right layer of abstraction.

If a certain aspect of the problem can be solved easily in a higher layer of abstraction, great! Let's solve it at that layer, because it's usually easier and allows for more expressiveness.

But whenever we need more control, we can seamlessly drop down to the lower layer and work there.

I think we need to find a fundamental principle that allows this. But I see barely anyone working on this - instead we keep trying to find higher and higher layers of abstractions (LLMs being the most recent addition) in the hopes they will get rid of the need of dealing with the lower layers. Which is a false hope, I feel.

Re: The Law of Leaky Abstractions (2002)

#44
post #11

If you like this, my other favorite essay by Joel is Making Wrong Code Look Wrong: https://www.joelonsoftware.com/2005/05/11/making-wrong-code-...

The problem is that it completely ignores the correct solution, which is "use types; we invented them for a reason". HTML fragments should never be stored in strings.

One problem is that there's a major lack of language support to make this easy.

IMO, every ID should be its own type. You shouldn't have a bunch of objects that have an ID of type string, you should have a User object with an ID of type UserID and a Post object with ID of type PostID, and then the compiler solves a lot of problems for you. Or make it so your functions that interact with the outside world accept a String, but they only return ValidatedStrings, and your internals only accept ValidatedStrings (and there's only one way to turn a String into a ValidatedString).

But in any kind of language with structural typing (e.g. TypeScript) this doesn't work, by definition. You can call a string a UserID and you can call it a PostID but if they're both Strings then you can assign them to each other.

And in Java, the concept of a typedef-like operation doesn't exist at all (I can't speak for .Net).

There's a whole class of bugs that go away if you allow for easy, nominal typedefs, but it's actually not easy to do in most statically typed languages.

Re: The Law of Leaky Abstractions (2002)

#45

I've long been having a hunch that we're currently in the "wild west of abstraction". I think we're missing an essential constraint on the way we do abstraction. My hunch is that this constraint should be that abstractions must be reversible. Here's an example: When you use a compiler, you can work at a higher layer of abstraction (the higher-level language). But, this means you're now locked into that layer of abstr…

Most ORMs give a way to integrate nicely with SQL if you need to reach down to that layer and still use the rest of the ORM features. There is no silver bullet; everything is a trade off. Almost all of the time, the trade off is entirely worth it even if that gets you locked into that solution.

> Most ORMs give a way to integrate nicely with SQL if you need to reach down to that layer and still use the rest of the ORM features.

Agreed, that's a good thing, in my experience.

> Almost all of the time, the trade off is entirely worth it even if that gets you locked into that solution.

I wish this would match my experience.

Re: The Law of Leaky Abstractions (2002)

#46

Earlier quoted context omitted.

Most ORMs give a way to integrate nicely with SQL if you need to reach down to that layer and still use the rest of the ORM features. There is no silver bullet; everything is a trade off. Almost all of the time, the trade off is entirely worth it even if that gets you locked into that solution.

> Most ORMs give a way to integrate nicely with SQL if you need to reach down to that layer and still use the rest of the ORM features. Agreed, that's a good thing, in my experience. > Almost all of the time, the trade off is entirely worth it even if that gets you locked into that solution. I wish this would match my experience.

What's funny is that ORMs giving you directly access to SQL is a leaky part of the abstraction but in this case that's good!

I think being locked into a some abstraction is so common place that you don't even consider it being a thing until you have a problem with it. Look at your examples: compilers, libraries, frameworks, etc. As an example, is anyone truly upset that coding in Python locks you into the Python ecosystem? Yet, I've used libraries/frameworks that didn't win the war of popularity and I'm still unfortunately committed. I think there's a bias at play in how we look at these things.

Re: The Law of Leaky Abstractions (2002)

#47
I feel like this article should be called "The Law of Bad Abstractions." I often see this cited as a blanket rejection of complexity in software. But complexity is unavoidable and even necessary. A skillful engineer will therefore design their abstractions carefully and correctly, balancing time spent thinking forward against time spent implementing a solution. I think Joel understands this, but it feels weird how he frames it as a "law", as though it's something he's discovered instead of a simple fact that arises from the nature of what abstractions are: things that stand in for (or mediate interaction with) some other thing without actually being that thing. What a surprise that the stand-in ends up not being the actual thing it's standing in for!

Re: The Law of Leaky Abstractions (2002)

#48

I've long been having a hunch that we're currently in the "wild west of abstraction". I think we're missing an essential constraint on the way we do abstraction. My hunch is that this constraint should be that abstractions must be reversible. Here's an example: When you use a compiler, you can work at a higher layer of abstraction (the higher-level language). But, this means you're now locked into that layer of abstr…

That's not really true of, at least C compilers. Because compilers have ABI's and fixed calling conventions, it's straightforward, documented, and not uncommon (depending on your application area/deployment target) to drop down to the ASM layer if you need to do that. It's definitely one of those things that makes C nice for bare metal programming.

Interesting, I'm curious though, once you do drop down to the ASM layer, how do you ensure that this code doesn't get overwritten by new compiler output? Or is this something you somehow include in the compile step?

Re: The Law of Leaky Abstractions (2002)

#49
post #34

I've long been having a hunch that we're currently in the "wild west of abstraction". I think we're missing an essential constraint on the way we do abstraction. My hunch is that this constraint should be that abstractions must be reversible. Here's an example: When you use a compiler, you can work at a higher layer of abstraction (the higher-level language). But, this means you're now locked into that layer of abstr…

Abstractions work by restricting the domain of what you can do, then building on those restrictions. For example, raw hardware can jump anywhere, but structured programming constrains you to jump only to certain locations in order to implement if, for, functions, etc. It is precisely those restrictions that bring the benefits of structured programming; if you still frequently dipped into jumping around directly struc…

> It is precisely those restrictions that bring the benefits [...]

Wouldn't it be possible to say "ok, I'll take those restrictions as long as they benefit me, but once I notice that they no longer do, I'll break them and drop down to the lower layer. But only for those parts that actually require it"?

> Abstractions necessarily involve being irreversible, or, to forestall a tedious discussion of the definition of "irreversible", necessarily involve making it an uphill journey to violate and go under the abstraction.

Why? Not being snarky, I'm genuinely trying to understand this better.

Re: The Law of Leaky Abstractions (2002)

#50

Earlier quoted context omitted.

That's not really true of, at least C compilers. Because compilers have ABI's and fixed calling conventions, it's straightforward, documented, and not uncommon (depending on your application area/deployment target) to drop down to the ASM layer if you need to do that. It's definitely one of those things that makes C nice for bare metal programming.

Interesting, I'm curious though, once you do drop down to the ASM layer, how do you ensure that this code doesn't get overwritten by new compiler output? Or is this something you somehow include in the compile step?

In my experience (admittedly limited) you include the assembly in the compile step. Your linker hopefully puts everything together so you can talk to yourself
Post reply on HN