Live data from Hacker News

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

fhur.me

41–50 of 240 posts

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

#41

>There’s a well-known saying: "All abstractions leak." It’s true. No matter how good the abstraction, eventually, you’ll run into situations where you need to understand the underlying implementation details This is false. One can read up on Theorem's for Free by Wadler to see that not all abstractions are leaky.

Theorems for Free tells you that some abstractions satisfy some mathematical properties (for free!) under some circumstances.

If you write down a function with signature

  {T : Type} -> T -> T
then it must be the identity function, if you do not use "malicious" extensions of the type system.

But what is the performance of the identity function?

Here is an identity function:

  lambda T, lambda t, if (2 + 2 = 4) then t else t
In other words: I can hide pretty much arbitrary computation in my identity function.

Users of my identity functuon will notice that it is wicked slow (in reality, I let my identity function compute Busy Beaver 5, before doing nothing). Their complaints are evidence of leaky abstraction.

Now you might have a smart optimizing compiler that knows about Thm4Free... But that's another story.

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

#42

I got a piece of advice writing UI code a long time ago: Don't marry your display code to your business logic. I'd like to say this has served me well. It's the reason I never went for JSX or other frameworks that put logical code into templates or things like that. That is one abstraction I found unhelpful. However, I've come around to not taking that advice as literally as I used to. Looking back over 25 years of c…

I learned that lesson building an utility with JavaFX. I've done a few years with React and the usual pattern was to move almost everything out of the components. Unless it's an event handler, a data transformer for the view, or something that manipulates the view, it has no business belonging to this layer. I don't try to generalize it, I just try to make the separation clear using functions/methods/classes. Instead…

When you say "components" do you mean that in the mixed React sense where a component could contain HTML? In my own usual cases, I call the Javascript a component, and the HTML a template. I usually take a handlebars approach on the template content and something like "data-role" to identify the template tags to the JS, and beyond that don't mix them. However, my client-facing JS components themselves are totally bound to the templates they load up - they expect the presence of certain fields to work with. I'm talking more about not mixing any business logic into those JS components: Let's say, in a form component, not anticipating that a dropdown menu will have any particular shape or size of dropdown item, which means those items need to be specified separately. This leads to JS components relying on lots of other components, when sometimes you just need one type of dropdown item for a particular component, and having dropdown items be a 20-headed beast makes everything upstream need to define them first.

Sometimes you just need a form to do what it says on the label.

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

#43
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 "object" that is easier to reason about.

If you keep this in mind, you'll realize that having a lot of particulars to identify shared properties that you can abstract away is a prerequisite. The best abstractions I've seen have always come into being only after a significant amount of particularized code had already been written. It is only then that you can identify the actual common properties and patterns of use. Contrarily, abstractions that are built upfront to try and do little more than hide details or to account for potential similarities or complexity, instead of actual already existent complexity are typically far more confusing and poorly designed.

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

#44

Perhaps this is a minor nitpick, but > Abstractions are also the enemy of simplicity. Each new abstraction is supposed to make things simpler—that’s the promise, right? Not exactly, no. The purpose of abstraction is to hide implementation detail, and thereby insulate one part of the codebase/application/system from variations in another. Graphics APIs for example - yes your code may be simpler for not having to deal…

While this is how the term is often used, I think it's cavalier use of language and confuses abstraction for modularity, and this linguistic confusion is one of the reasons a lot of programmers write bad "abstractions".

Organizing your code into components that are as independent as possible is a good practice and is the pursuit of modularity. A proper abstraction on the other hand, is a generalization that simplifies a conceptual layer in your code base.

Abstraction often enables greater modularity as a consequence, but they are not the same thing. For example, in the problem of text editing, people eventually realized that the manipulation of text is typically line oriented. Thinking of a text file as a collection of lines may seem like an obvious and modest abstraction, but it works well. This abstraction, in turn, leads to other couplings (e.g. line oriented motion is highly dependent on the line abstraction), but it also leads to potential modularity (e.g. printer code may no longer need to understand exactly how a display renders each character of text in a grid, instead, it too can work on "lines"). Good abstractions support modularity to the extent that they establish a shared domain of objects to communicate about and across systems, but they do not necessarily produce modularity in themselves.

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

#45

Perhaps this is a minor nitpick, but > Abstractions are also the enemy of simplicity. Each new abstraction is supposed to make things simpler—that’s the promise, right? Not exactly, no. The purpose of abstraction is to hide implementation detail, and thereby insulate one part of the codebase/application/system from variations in another. Graphics APIs for example - yes your code may be simpler for not having to deal…

> The purpose of abstraction is to hide implementation detail

Technically, that's encapsulation, though the sentiment is close, I think.

I rather view it as a matter of semantics. At one low level, you have operations that deal with some concrete interface or API, etc. You bundle those operations up behind an abstraction, providing methods whose names involve your application domain. Perhaps they are still at a technical level, and you bundle those up behind another abstraction, whose method names involve your business domain.

Yes, the lower level details are hidden from the higher levels, but the hiding is not the point. The point is to be able to write code that readily corresponds to the problem you are trying to solve.

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

#46
Abstraction hides detail, but at what coat?

A network close call at a high level closes a network socket. But at the tcp level there's a difference between close and reset. Which do you want? Your api has removed that choice from you, and if you look you will have no idea if rhe close api does a close or a reset.

Is the difference important? If depends. If you have a bunch of half open sockets and run out of file descriptors then it becomes very important.

Another example: you call read() on a file, and read 10k bytes. Did you know your library was reading 1 byte at a time unbuffered? This abstraction will/can cause massive performance problems.

My favorite one is when a programmer iterates over an ORM-enabled array. Yes, let's do 50,000 queries instead of one because databases are too complicated to learn.

Just like any tool, abstraction has costs and benefits. The problem is that lots of people ignore the cost, and assume the benefit.

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

#48
Pretty easy to give generic advice without examples.

“Write more tests, but not too many”

“Use good abstractions where appropriate?”

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

It’s easy to create a strawman here (the FactoryAdaptorMapper or whatever) but in reality this kind of generic advice doesn’t help anyone.

Of course people want to use good abstractions.

That’s not the problem.

The problem is being able to tell the difference between generic arbitrary advice (like this post) and how your specific code base needs to use abstractions.

…and bluntly, the only way to know, is to either a) get experience in the code base or b) read the code that others have left there before you.

If it’s a new project, and you’re not familiar with the domain you’ll do it wrong.

Every. Single. Time.

So, picking “good” abstractions is a fools game.

You’ll pick the wrong ones. You’ll have to refactor.

That’s the skill; the advice to take away; how to peel back the wrong abstraction and replace it with your next best guess at a good one. How to read what’s there and understand what the smart folk before did and why.

…so, I find this kind of article sort of arrogant.

Oh, you want to be a great programmer?

Just program good code. Use good abstractions. Don’t leave any technical debt. Job done!

…a few concrete examples would go a long way here…

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

#49
post #38

Earlier quoted context omitted.

“The purpose of abstraction is not to be vague, but to create a new semantic level in which one can be absolutely precise.” — Edsger Dijkstra But sometimes a new semantic level isn’t needed. Abstraction gets so much press when you might just need some good ol’ fashioned information hiding and separation of concerns.

> some good ol’ fashioned information hiding and separation of concerns. that's exactly what you do to implement an abstraction isnt it?

In the same way wood is used to build a house.

That you used wood doesn’t mean you built a house.

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

#50
post #46

Abstraction hides detail, but at what coat? A network close call at a high level closes a network socket. But at the tcp level there's a difference between close and reset. Which do you want? Your api has removed that choice from you, and if you look you will have no idea if rhe close api does a close or a reset. Is the difference important? If depends. If you have a bunch of half open sockets and run out of file des…

I think an important distinction is hiding details from other parts of the program, and having details being hidden from you.

99.9% of the time I don't care what the tcp socket closes with as long as it isn't leaking a resource.

And if I did care, then I picked the wrong level of network abstraction to engage with. I should've used something more raw.

Regarding ORM arrays. I have myself recently debugged such a case. I chortled a bit at the amateur who wrote the code (me last year) and the schmuck who accidentally wrapped it in a loop (me 3 weeks ago). Then I changed it slightly to avoid the N queries and went on with my day. No need to lambast the tooling or the programmers. Just write something maintainable that works. No need to throw the entire ORM away just because we accidentally made a web page kinda slow that one time.

And don't worry, I too lament when web pages I don't control are slow. You may rest uneasily knowing that that page would be slow regardless of whether ORMs existed because it is not slow because of ORMs, but because there is no incentive for the business to care enough to make it faster.

Post reply on HN