6 ms·
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 promis
by danparsonson 2y ago
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 with the register-level minutiae of pushing individual triangles, but the core benefit is that the same code should work on multiple different hardware devices.
Good abstractions break a codebase up into compartments - if you drop a grenade in one (change the requirements for example), then the others are unaffected and the remedial work required is much less.
- uoaei 2y agoIn short: good abstractions simplify by centralizing operational logic. But it's not until a certain scale where that option is more efficient from bespoke implementations.
- magicalhippo 2y agoA heuristic we use at work is to not introduce an abstraction layer until there are at least two different implementations required. That is if you think you'll probably need multiple implications, delay introducing an abstraction until you actually do. Also, there are different ways of providing abstraction. Perhaps you don't need to abstract the entire implementation but, as an example, rather change one parameter from passing a value to passing a function returning a value.
- hansvm 2y agoThat touches on a couple related principles: - not doing extra work now if it's not necessary yet and if it's as cheap to do later - delaying building a thing till you know what that thing should be
- wvenable 2y agoA good abstraction is like documentation written in code.
- bruce511 2y ago>> but the core benefit is that the same code should work on multiple different hardware devices. I came here to say this. Attractions act as a bridge between things which allow those things to change independently. Using an ORM allows my program to easily work against multiple sql databases. Using a compiler allows me to target different hardware. Using standard protocols allows me to communicate with different programs. Using libraries to do say email hides me from those protocols and allows me to adapt to service providers Using APIs not protocols. In other words the abstraction is designed to hide a layer (which can change) from a program not interested in that level of change. The key is to stop abstracting when the program cares. By all means encapsulate rules and processes, but they're a direct implementation of those rules and processes. One can argue my "calculateLeaveForEmployee" function is an "abstraction" - but that would be a misnomer. Since there's only one set of rules in play (the set that matters now) its an implementation. An abstraction supports (at least) two things at the same time.
- necovek 2y ago> Using an ORM allows my program to easily work against multiple sql databases. A curious example, since most developers who've worked on any project with significant amount of data in a database would likely disagree. IMO, ORMs mostly allow using programming-language-of-choice as a syntax for relational queries instead of constructing it by hand on top of serialization and deserialization of objects into rows and vice versa.
- ludston 2y agoIndeed, given that most sql dialects have subtle differences that make them noncompatible with one another, and most ORMs have support for dipping into raw sql, sufficiently large systems tend to end up coupled with a particular database anyway. That's not to mention that the BAs will want raw sql access for report writing and switching systems breaks all of their scripts too.
- zharknado 2y agoYes, 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.
- cpeterso 2y ago“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.
- crabmusket 2y agoThis is such a great quote, and helps explain what is a good abstraction. Because CRDTs have been in the zeitgeist a lot lately, I want to pick them as an example of a "good" abstraction. CRDTs have mathematical properties which can be described and understood independently of a specific implementation. And importantly, you can judge whether an implementation is correct with reference to these abstract rules. This means that when using a CRDT, you largely can treat it as a reliably-solved problem. Once you understand the concepts, and work out how to use the library you've picked, you don't have to think about the details. Though that doesn't mean sometimes the behaviour can be surprising: https://www.moment.dev/blog/lies-i-was-told-pt-1 https://www.moment.dev/blog/lies-i-was-told-pt-1 TCP and HTTP are great examples too, though interestingly I don't know if they rely on mathematical definitions so much as just being extremely widespread to the point that reliable implementations are available anywhere you care to write code. I like this article which also leans on the Dijkstra quote: https://www.pathsensitive.com/2022/03/abstraction-not-what-you-think-it-is.html?m=1 https://www.pathsensitive.com/2022/03/abstraction-not-what-y...
- sgarland 2y agoCRDTs are also an excellent example because of how their supporting infrastructure is impacted by their design, namely that Postgres’ method of dealing with updates makes for massive write amplification. I wrote this [0] previously, but it still applies. IMO, as a dev, there are times where you really do need to think somewhat deeply about infrastructure choices. Unfortunately, knowing when you need to care practically requires you to already understand it. [0]: https://news.ycombinator.com/item?id=40834759 https://news.ycombinator.com/item?id=40834759
- chii 2y ago
- voidhorse 2y agoWhile 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.
- danparsonson 2y agoYes, abstraction and modularity are coincident but distinct topics, and my last paragraph implies that I am equating those two things. Good point. I disagree that considering a text file as a set of lines really qualifies as an abstraction; it's just a different representation of the data - you could instead choose to use a list of words or a tree or whatever. An abstraction is a general interface to a concrete thing that allows you to substitute different but similar concrete things without changing the consumer of those things. The Linux filesystem is a great example - I can 'cat' basically anything that has a path, and some driver will pull data from the associated endpoint and display the data on screen. "File" is the abstraction, and consumers of files need not care about the specifics of communicating with the underlying devices. Such a system is also modular, but it's hard not to be when your abstraction is well conceived. Perhaps we're saying the same thing with different words?
- mannykannot 2y ago
- zdragnar 2y ago> 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.
- danparsonson 2y agoHmmm I prefer Wikipedia's definition: > In object-oriented programming languages, and other related fields, encapsulation refers to one of two related but distinct notions, and sometimes to the combination thereof:[5][6] > - A language mechanism for restricting direct access to some of the object's components.[7][8] > - A language construct that facilitates the bundling of data with the methods (or other functions) operating on those data The hiding is absolutely the point of abstraction, in the sense that caller can manipulate the subsystem without knowing about (important) inner details of it. As I said, graphics drivers are a great example - I just want to put a triangle on the screen, I don't want to care about the registers I have to set on an NVidia card vs those on an AMD card, or what their memory maps look like, and I don't want to have to rewrite my code when they release a new generation of hardware. Drawing a triangle is an abstraction, hiding away the details of how a specific graphics card achieves that. Think about what the word 'abstract' means - the idea of a 'human' is an abstraction for bundles of molecules conforming to a general pattern with broadly similar qualities but almost infinite variability. The word conveniently hides a wealth of detail that we usually don't need to think about; if I tell you there are three humans in a room, you can make use of that information without knowing anything about their exact physical attributes or who they are. I would refer to what you're describing as 'modelling' - these are related topics but I don't see them as the same thing.
- voiceofunreason 2y agoBerard 1993 offers a good survey of the meanings of Abstrasction, Encapsulation, and Information Hiding https://web.archive.org/web/20071214085409/http://www.itmweb.com/essay550.htm https://web.archive.org/web/20071214085409/http://www.itmweb...
- mgaunard 2y agoThat would be encapsulation, not abstraction.
- danparsonson 2y agoI disagree; to save duplicating my other reply to a similar comment: https://news.ycombinator.com/item?id=42529743 https://news.ycombinator.com/item?id=42529743