Live data from Hacker News

That's not an abstraction, that's a layer of indirection

fhur.me

201–210 of 240 posts

Re: That's not an abstraction, that's a layer of indirection

#201

Earlier quoted context omitted.

Yes, abstraction and generalization are properties you'd rather look for the second time around . Someone was already warning about this 25 years ago [1]: You have a boring problem and hiding behind it is a much more interesting problem. So you code the more interesting problem and the one you've got is a subset of it and it falls out trivial. But of course you wrote ten times as much code as you needed to solve the…

Have you ever looked at how useless Chuck Moore's stuff is? Like, the chip designs are of the type “384 independent Forth chips with tiny amounts of RAM and mediocre interconnects, and if you want to actually do anything with them, you'll need to use 128 of them to program your own DDR3 controller”. Or, he demonstrates how awesome Forth is by showing that you can do “the guts of a disk driver” in five lines, except t…

Useless?

Like the RTX2000 which landed on a comet kind of useless?

Or do you mean some other kind of useless. Maybe the controlling radio telescopes kind of useless. That must be it.

Re: That's not an abstraction, that's a layer of indirection

#202
post #161

Earlier quoted context omitted.

Yes, ORMs came to mind for me as an example of indirection without abstraction. If you accept OP’s litmus test of “how often do I have to peek under the hood” I think ORMs generally don’t score particularly well.

If enabling the ablity to think of the database as the rich native data structures provided by the host programming language, and not the tables (rows and columns) that the underlying database service wants to think of the data as is not an abstraction, what is?

ORM, as the name suggests, is an "adaptation" layer ("mapping" or "mapper").

It does not really abstract away relational data, it instead maps it to object/class hierarchy. And every single ORM I've used also provides an interface to map function/method/expression syntax to SQL queries to get back those rows (adapted into objects).

Now, in a very broad sense, mapping would also be an abstraction — just like an "indirection" would be — but considering the narrower definition from the OP (where indirection is not an abstraction), I think it's fair to say that ORM is also not an abstraction.

Re: That's not an abstraction, that's a layer of indirection

#203

The best way to achieve a good abstraction is to recall what the word meant before computer science: namely, something closer to generalization . In computing, we emphasize the communicational (i.e. interface) aspects of our code, and, in this respect, tend to focus on an "abstraction"'s role in hiding information. But a good abstraction does more than simply hide detail, it generalizes particulars into a new kind of…

Yes, abstraction and generalization are properties you'd rather look for the second time around . Someone was already warning about this 25 years ago [1]: You have a boring problem and hiding behind it is a much more interesting problem. So you code the more interesting problem and the one you've got is a subset of it and it falls out trivial. But of course you wrote ten times as much code as you needed to solve the…

Ten times? Foo. Maybe double.

But that's still twice the cost, for only a potential win. Better check first that it helps somebody write better/more correct/quicker code.

E.g. we wanted to change our text-screen video driver to allow a full-screen overlay (many years ago). The programmer assigned the task was changing the text-blit code to know about certain lines on the screen that were going to be the 'nested' window, which could be 'up' and masking a subset of the window below, or 'down' and the full screen should be displayed as normal.

He'd been hacking away, changing every case in the code to 'know about' the particular window that was planned. Pulling his hair out, getting nowhere.

I suggested a simple indirection buffer, where each line of a virtual display was pointed to indirectly. To put the subwindow 'up' or 'down' you just pointed those lines of the main screen to a buffer, and pointed the lines of the subwindow to the hardware store for video text.

All his changes folded into 'access display indirectly'. Trivial. Then the up/down code became a loop that changed a pointer and copied some text.

That was actually an abstraction, and actually much shorter/faster/simpler to understand and change.

Later we could change the window dimensions, have multiple windows etc with no change to the video driver.

Re: That's not an abstraction, that's a layer of indirection

#204

The best way to achieve a good abstraction is to recall what the word meant before computer science: namely, something closer to generalization . In computing, we emphasize the communicational (i.e. interface) aspects of our code, and, in this respect, tend to focus on an "abstraction"'s role in hiding information. But a good abstraction does more than simply hide detail, it generalizes particulars into a new kind of…

IMO, I dislike that kind of mixing several concepts into the same name that software engineering is full of. Abstraction means removing details from the thing you present. Generalization means making the same representation valid for several different things. Are abstractions that don't generalize valuable? Well, maybe there is something better to be found, but those are the bread-and-butter of software engineering;…

I would warn against conflating the concept of an interface with an abstraction just as much as I would against conflating generalizations and abstractions.

An interface often accompanies an abstraction, sometimes even represents one. But if we get down to definitions, an interface is merely something that you interact with: a function, a class, a network endpoint etc. If you write in machine code, you might not think that you are working with any kind of an interface, and certainly it's not a high level one, but you are interfacing with the machine's native instruction set. You could then argue that the instruction is an abstraction that hides what the machine is capable of. But now we're splitting hairs and about to ask silly philosophical questions like whether a car's steering wheel qualifies as an abstraction that exists to hide the axles. I would argue not. The interface's primary responsibility is to provide a mechanism of interaction, rather than to reduce complexity (though a good interface is simple and intuitive).

Both you and the author of the article posit a similar definition of 'abstraction'. From the article:

> An abstraction is only as good as its ability to hide the complexity of what lies underneath.

And from your comment:

> Abstraction means removing details from the thing you present.

I would actually argue that both, while very close, are missing the mark.

An abstraction exists to reduce a concept down to its essentials.

This doesn't necessarily contradict the definitions offered, but I think there is a nuance here that, if missed, causes the offered definitions to become useless.

The nuance is in deciding what is essential or necessary. If, definitionally, you choose to dispense with acknowledging the essential... well then you get the problems that the author is writing about. You get shit abstractions because no one bothered to think in terms of what they INCLUDING rather than DISPENSING with.

Yes, obviously, we abstract in an attempt to simplify. But that simplification needs to come from a positive rather than a negative.

In other words: What is the thing for? What does it do?

"Hides complexity" is the shittiest answer that anyone could ever offer as a response when faced with a given problem. First, what is the complexity that we are trying to reduce? Secondly, why are we trying to reduce it? Thirdly, when we have achieved our primary goal of reducing the complexity, then what does the thing look like? What value does it offer over interfacing directly with the "thing" being abstracted?

Abstractions in computer science are extremely valuable. So valuable, I would offer, that any time we hear engineers decry abstractions or point to abstractions as the root of all evil we ought to ask a very pressing question: "who hurt you?"

A good engineering solution is a simple one, and an abstraction is intended to be a simpification mechanism. But it doesn't have to necessarily simplify the intuitive understanding of the problem at hand. This is a good goal if you can achieve it, don't get me wrong. But that abstraction might exist so you can swap vendors in the future if that's a business priority. Or because you've identified some other element / component in your system that will be difficult to change later. So you stick it behind an abstraction and "Program to Interfaces" rather than "implementations" so that you can simplify the process of change down the road, even if it comes at an more immediate cost of making the code a bit less intuitive today.

Everything in software is tradeoffs. And a good abstraction exists so that we can focus on requirements and programming to those requirements. This is a smiplification when done properly.But the focus ought to be on defining those requirements, of asking "what should simple look like?"

Re: That's not an abstraction, that's a layer of indirection

#205

The best way to achieve a good abstraction is to recall what the word meant before computer science: namely, something closer to generalization . In computing, we emphasize the communicational (i.e. interface) aspects of our code, and, in this respect, tend to focus on an "abstraction"'s role in hiding information. But a good abstraction does more than simply hide detail, it generalizes particulars into a new kind of…

this feels like you are talking about langchain haha:https://medium.com/@fsndzomga/jailbreaking-langchain-ad9415a...

Re: That's not an abstraction, that's a layer of indirection

#206

I wish articles like this had more examples in them. In between “this thin wrapper adds no value but a lot of complexity”, and “this thin wrapper clarified the interface and demonstrably saved loads of work last time requirements changed” is an awful lot of grey area and nuance. I did like the advice that if you peak under the abstraction a lot, it’s probably a bad one, tho even this I feel could use some nuance. I t…

"I wish articles like this had more examples in them."

There is a class of things that don't fit in blogs very well, because any example that fits in a blog must be broken some other way to fit into a blog, and then you just get a whole bunch of comments about how the example isn't right because of this and that and the other thing.

It's also a problem because the utility of an abstraction depends on the context. Let me give an example. Let us suppose you have some bespoke appliance and you need to provide the ability for your customer to back things up off of it.

You can write a glorious backup framework capable of backing up multiple different kinds of things. It enforces validity checks, slots everything nicely into a .zip file, handles streaming out the backup so you don't have to generate everything on disk, has metadata for independent versions for all the components and the ability to declare how to "upgrade" old components (and maybe even downgrade them), support for independent testing of each component, and has every other bell and whistle you can think of. It's based on inheritance OO and so you subclass a template class to fill out the individual bit and it comes with a hierarchy pre-built for things like "execute this program and take the output as backup" and an entire branch for SQL stuff, and so on.

Is this a good abstraction?

To which the answer is, insufficient information.

If the appliance has two things to backup, like, a small SQL database and a few dozen kilobytes of some other files, such that the streaming is never useful because it never exceeds a couple of megabytes, this is an atrocious backup abstraction. If you have good reason to believe it's not likely to ever be much more than that, just write straight-line code that says what to do and does it. Jamming that into the aforementioned abstraction is a terrible thing, turning straight code into a maze of indirection and implicit resolution and a whole bunch of code that nobody is going to want to learn about or touch.

On the other hand, if you've got a dozen things to backup, and every few months another one is added, sometimes one is removed, you have meaningful version revs on the components, you're backing up a quantity of data that perhaps isn't practical to have entirely in memory or entirely on disk before shipping it out, if you're using all that capability... then it's a fantastic abstraction. Technically, it's still a lot of indirection and implicit resolution, but now, compared to "straight line" code that tries to do all of this in a hypothetical big pile of spaghetti, with redundancies, idiosyncracies of various implementations, etc., it's a huge net gain.

I don't know that there's a lot of abstractions in the world that are simply bad. Yeah, some, because not everything is good. But I think they are greatly outnumbered by places where people use rather powerful, massive abstractions meant to do dozens or hundreds of things, for two things. Or one thing. Or in the worst case, for no things at all, simply because it's "best practices" to put this particular abstraction in, or it came with the skeleton and was never removed, or something.

Re: That's not an abstraction, that's a layer of indirection

#207

The best way to achieve a good abstraction is to recall what the word meant before computer science: namely, something closer to generalization . In computing, we emphasize the communicational (i.e. interface) aspects of our code, and, in this respect, tend to focus on an "abstraction"'s role in hiding information. But a good abstraction does more than simply hide detail, it generalizes particulars into a new kind of…

Great point, and agree that generalization makes for the clearest wins from abstraction.

But there are also cases where there is no generalization, but the encapsulation / detail hiding is worthwhile. If you have a big function and in the middle of it you need to sort some numbers, you would probably implement a Sort routine to make the control flow much easier to understand - even if you only use the function once (let’s pretend there’s no sort functionality in standard library).

Curious if others agree, and what heuristics you use to decide when implementation encapsulation is worthwhile.

Re: That's not an abstraction, that's a layer of indirection

#208
I found this to be a pretty poor article. The article lacks concrete examples and speaks in generalities to explain its core thesis. But without specificity, a reader can nod along, sure in the knowledge that they already are wise and follow this advice and it's everyone else who's out there mucking up code bases with layers upon layers of garbage. I mean,

> The next time you reach for an abstraction, ask yourself: Is this truly simplifying the system? Or is it just another layer of indirection?

Is anyone reading this truly going to alter their behavior? If I could recognize that my abstraction was "just another layer of indirection" as simple as that, obviously I wouldn't have added it in the first place!

Re: That's not an abstraction, that's a layer of indirection

#209
I don't consider TCP an abstraction at all. The abstraction is the unix API over it, and then again, the

> ssize_t send (int socket, const void *buffer, size_t size, int flags)

is not a nice one. When was the last time you had the data in a buffer, wanted to send it over to the peer at the other side, but didn't mind that it's not sent in it's entirety ? So you have to write a loop over it. Also, is the call blocking or not ? (well, you'll have to read the code that created it to know, so that's no fun neither).

However, it does prove the point the author is trying to make: good abstractions are hard to find!

Anyway, I tried to think of a better example of a good abstraction and found the "Sequence" that's available in plenty of programming languages. You don't need to now what the exact implementation is (is it a list, a tree, don't care!) to be able to use it. Other example I found were Monoid and Monad, but that's tied to the functional paradigm so you lose most of the audience.

Re: That's not an abstraction, that's a layer of indirection

#210
Let's not forget about a particularly frustrating kind of "level of abstraction": the bespoke interface to a part of the code that has side effect, and that has exactly two implementation : one in the production code, and one in the tests.

If I were to create a language tomorrow, that's the one aspect where I would try something that I have not yet found elsewhere : can you make it so that you can "plug" test doubles only for test, but keep the production path completely devoid of indirection or late binding.

(I'm curious if you know of a language that already does that. I suppose you can hack something in C with #ifdef, of course...)

Post reply on HN