[HN Gopher] Abstraction is expensive ___________________________________________________________________ Abstraction is expensive Author : pclmulqdq Score : 140 points Date : 2022-12-07 15:10 UTC (7 hours ago) (HTM) web link (specbranch.com) (TXT) w3m dump (specbranch.com) | yason wrote: | Abstraction has a slight cost but doesn't inherently mean it's | very expensive. The cost of abstraction is generally worth buying | because it allows you to write code in more independent blobs | which reduces complexity and thus bugs and potential bugs. | | But using abstractions to "solve" a hard problem is dearly | expensive. By "solving" I mean pushing up the hard parts one | layer at a time until you eventually can't avoid solving it for | real. At best, maybe you're lucky and someone else has to solve | it, by working through all the layers of abstractions you built | on your way to negotiate yourself out of the hard spot. But those | abstractions are expensive because they don't reduce complexity | nor offer any tangible benefit except keeping their creators in | their comfort zones. | mattacular wrote: | One of my favorite quotes about software engineering, sorry not | sure who to attribute it to: | | "First you learn the value of abstraction, then you learn the | cost of abstraction, then you're ready to engineer" | pphysch wrote: | Junior, mid, senior? Explains why the mid phase is brief. | Zigurd wrote: | In most cases time and capital are more expensive and | abstraction, well-used, is the cheapest technical debt. | fnordpiglet wrote: | A CS prof of mine liked to say: | | Every problem in computer science can be solved with abstraction | other than too much abstraction. | falcolas wrote: | I don't know if this will help (or even resonate) with anyone | else, but it's helpful to me to view abstractions as a form of | DRY. | | All developers have created functions to de-duplicate their code. | And all developers have consequently seen how the more code a | function de-duplicates, the larger and more cumbersome a function | becomes; how many more if statements and safety checks come into | play. | | Now imagine how complex - how many if statements and safety | checks and introspection - have to go in to replacing hand- | written SQL with custom constructors with an ORM. | Arch-TK wrote: | It's unfortunate that you have only ever experienced | abstractions which grow in size over time. The best | abstractions out there are ones which operate well together to | solve a large set of problems in the smallest amount of | complexity (local to any given abstraction) as well as the | smallest amount of total complexity at any given abstraction | layer, as well as the smallest amount of total solution | complexity. Now yes, this end goal is an idealized world, when | you build on top of crusty old APIs and crusty old software you | inevitably end up with crusty abstractions, especially | difficult to deal with is the real world. That being said, | there are plenty of examples out there where complexity at all | three levels of detail that I outlined above has been | painstakingly minimized. It usually takes a lot more effort to | produce a simple solution to a problem than a complex one. This | really requires the "alignment" the article talks about. | | Speaking of "alignment", ORM is one of the best examples of | complete and total misalignment. The sets-of-tuples model of | relational databases and the graph-of-objects model of object | oriented systems are so seriously at odds with each other that | there isn't a single ORM out there which successfully fully | resolves the mismatch without severe abstraction leaks. (No, | the fact that you can successfully use an ORM without | abstraction leaks at the cost of severe performance degradation | doesn't really matter.) | | On the other hand, large parts of the design of a project such | as Plan 9 are extremely aligned. | falcolas wrote: | You're right, I have never seen an abstraction which hasn't | grown with time. I think that's because either an abstraction | project either ends, or receives constant feature requests. | Kind of a grow-or-die mentality as applied to software | development. | anfilt wrote: | This post makes me wish more research was done on exo-kernels: | https://en.wikipedia.org/wiki/Exokernel | | The concept makes dealing with some the topics in this post much | more logical and easier in my opinion. | photochemsyn wrote: | One takeaway for dealing with what the author calls misalignment | seems to be that abstractions should be reversible, that is, | easily rolled back to the base layer, without disrupting other | parts of the system. This facilitates swapping out one | abstraction for another. | | Another way of putting it is that if you lay out all the | dependencies in a system, it should look more like a tree than a | graph, with the abstractions closer to the leaves than to the | root. | vlovich123 wrote: | Path dependency makes that often difficult / impractical. | revskill wrote: | I think many misunderstand/misinterpret abstraction with magic. | Abstraction is naming things that share common properties and | structures. | | Magic is expensive because it adds debts in debugging. | | Non-abstraction is also expensive because it adds debts in | development and refactoring. | | Good abstraction pays later, it reduces debts, but you need to | buy it first. It's not expensive if it's well produced and | consumed. | agentultra wrote: | I'd argue that abstraction is cheap. You should do it more. As | often as possible. | | Consider a world where the software industry state-of-the-art is | completely nascent and isolated to every owner of a computing | system. You buy these huge refrigerator-sized machines and get a | bunch of manuals with them but nothing else. You have no | operating system. No compiler. Nothing. The expense for this | project can only be funded by a large university or government. | The timeline to deliver is measured in years. | | In todays world? We write programs that generate new programs, | that emulate entire classes of machines, and we ship software | projects in days, weeks, and months. | | It's so vastly complex that it's a wonder it works at all let | alone so well. | | Abstraction is what makes it all work without toppling over when | someone, somewhere in the stack, makes a slight change. | chousuke wrote: | I like abstractions when they are transparent enough that it's | easy to tell how it _could_ be implemented one layer down. | | There might be many implementation details that you hide under | the abstraction, but if the interface is so abstract that I can't | envision a straightforward implementation of it just based on the | interface, there's probably something wrong with the abstraction. | | Additionally, if the behaviour of the implementation conflicts | with the simplified model communicated by the interface, that'll | also cause issues. | taeric wrote: | Similar to liking them for being easy to see what they mean one | layer down, it is also nice to know what they mean one layer | up. Your program has to inhabit a middle layer between what it | is you want, and how it is that it will be executed. | | Sometimes, we can get lucky and a declarative statement of what | we want works. Often, that isn't the case. | [deleted] | warrenm wrote: | This sounds like an application risk-aversion/-seeking that | Kahneman highlights in "Thinking, Fast and Slow" | | Specifically... each of these individual decisions (wrt to | abstraction, in this context) was made to _locally_ optimize | (speed, simplicity, etc) some issue or other | | But when taken in gestalt, they're _overall_ not only not | optimal, but downright _bad_ | | Most of those decisions are made by people far to close to a tiny | portion of the problem to understand the implications of their | choices | | Alternatively, it's an application of the blind mice finding an | elephant story: yes, it's like a rope, a fan, a tree, a hose, and | on and on | | But it's none of those, it's an elephant | projektfu wrote: | The title needs work too. People will undoubtedly assume that | reducing abstraction will make things cheaper. | sghio4Q2 wrote: | Indeed. | cryptonector wrote: | Eh, _some_ people might do that, but, really, titles like | that beg you to read the article (or at least it 's why I | read it). The article absolutely does not say anything like | "reducing abstraction will make things cheaper". | danShumway wrote: | Sometimes reducing abstractions will make things cheaper. | | Some regular traps that I see people run into with | abstractions: | | - building around scenarios that they can be pretty confident | that they will never need to handle. | | - building abstractions that are larger and more complicated | than the thing they are abstracting (this tends to happen | when people build abstractions of abstractions). | | - building abstractions before they have a proper | understanding of what they're abstracting and what they'll | need to encapsulate. | | In many of those cases, reducing abstractions (even just | temporarily) reduces complexity. | | When I'm building purely personal projects, I don't use | abstractions to help me deal with directory structure on | Windows, because I don't use Windows, and that would be | additional complexity for no benefit -- so it's simpler for | me to just work with the lower level OS paths. | | When I start writing an abstraction I look at the amount of | documentation I'm generating, and if I'm generating more | documentation than it would take to explain the underlying | system, I look to see if there are concepts that I can | remove. I worked at a company where our build process became | considerably simpler when we stopped using high-level build | tools like Gulp/Grunt and switched to writing simple Node | scripts, because it was easier to debug what those scripts | were doing. We simplified that process even further by | occasionally just dipping into Bash scripts. | | Working with low-level concepts for a while often also gives | you better understanding of what you need to abstract. I've | worked with codebases where the abstractions all get built | first, and it's not uncommon for those abstractions to be | built around tasks that are pretty simple and easy to do with | lower-level code, at the same time that the abstractions | completely ignore the really difficult tasks that are very | annoying to do. And once abstractions get baked in, it was | time consuming and difficult and expensive to pull them out | and rewrite them. | | Going back to the scripts above, our build process got better | because we made it simple to begin with -- a set of scripts, | rather than a large established pipeline -- and then as we | identified pain points, we started abstracting those pain | points away. That allowed us to not waste time rewriting | abstractions over and over and instead to have targeted small | interfaces that helped us with the actual painful parts of | building and deployment. | | It is surprisingly common for software to be over-abstracted | to the point where it is more complicated to deal with than | it would be otherwise. I mean, heck, this comes up in web | development all the time, it is one of the primary criticisms | people have of the JS ecosystem -- that it overcomplicates | development. In many cases those complications exist for | reasons, they solve real problems that people have had. But | also in many cases, someone's individual blog doesn't need | any of that, and it would be cheaper and easier for them to | build something smaller and simpler. If I can build a site | that is one HTML file and one CSS file, and I know that's all | I'm going to need, then it's overkill to try and set up a | bunch of abstractions on top of that. | hinkley wrote: | You're speaking to impedance mismatch which is one of the | classic blunders. | | Systems that don't use the same jargon as the user base end up | having substantial bugs, especially ones the authors insist are | features. The abstractions are a bad fit for the problem domain | and they break things. | | I'm in a project that did that massively, at the hands of both | architectural astronauts and another common blunder: people who | seemed to think the concerns of the user base are beneath them | tend to create a fantasy world for themselves where they can | pretend they work on something more esoteric than the petty | concerns of the people who pay their salaries. | | Because of the bullshit (and more importantly, the top-heavy | sources of that bullshit) we've lost a lot of the better people | who could have fixed that situation. Meanwhile we are also | trying to expand into a new industry, and I can't help but | wonder if we would have been in trouble even if our | abstractions had matched our core competency. I would have | needed all of those missing people to make the refactors | necessary to do that work, so the agents of chaos and delusion | are a little vindicated. | | I have a couple of things I want to button up but they are all | fast approaching. I don't expect to be here in six months. I've | started fantasizing about my exit interview. In which I will | probably suggest that my team is too powerful and isolated from | the end user and so needs to be disbanded, its members | dispersed into groups one and two steps closer to the users. So | as to concretize some of the code and confront them with the | day to day struggles of internal customers, dealing with the | batshit parts of the code. | BurningFrog wrote: | I find this seemingly trivial insight very useful: | | Everything has costs _and_ benefits, and they need to be weighed | against each other. | | If you look for it, you'll see _tons_ of arguments like "this | has costs, so it's bad" and "this had benefits, so it's good". | | Both are missing half of the analysis! | danielmarkbruce wrote: | Absolutely. Most political "debates" suffer from this. | | "Everything is a trade-off" is similar - trivial yet profound. | agentultra wrote: | For the mathematically minded, this is not about abstractions. | This is about technology choices! One more interpretation of an | overloaded word that means a very specific thing. | vlunkr wrote: | Agreed, they should probably include their definition of | 'abstraction' in the post. | adamrezich wrote: | I would've thought that everyone who has done _any_ | programming at all would be familiar with the term as used in | the article--why would this not be the case? | agentultra wrote: | I think that's part of the problem with the use of the word | in programming circles: it means different things depending | on whose talking. | nine_k wrote: | Lack of abstraction is also expensive: try writing something | large in assembly. | | I'd say that lack of a _language / system of notions adequate to | the subject area_ is expensive. The desire to describe things in | a way that's efficient for a particular class of problems leads | to invention of various frameworks. Say, Rails makes you _hugely_ | productive at solving a particular type of problems (see | [Shopify]), though it 's less than helpful if you try to apply it | to unfitting problems (see [Twitter]). | | [Shopify]: https://tomaszs2.medium.com/how-shopify- | handled-1-27-million... (Sorry for a Medium link) | | [Twitter]: | https://www.theregister.com/2012/11/08/twitter_epic_traffic_... | LAC-Tech wrote: | _Lack of abstraction is also expensive: try writing something | large in assembly._ | | I can't think of a single "best practice" abstraction we have | in web development are anywhere near as watertight and useful | as what C offers over assembly. | | React VS The DOM is more like CFront over C. | ghaff wrote: | The headline is sort of misleading. It is (appropriately) | primarily about inappropriate abstractions. As you say, some | abstractions are unavoidable. Even assembly language is an | abstraction. | cryptonector wrote: | That's why real programmers write binary object code | directly. | LAC-Tech wrote: | Ah yes, the All Abstractions Are Equal fallacy. | fnordpiglet wrote: | I wire my magnetic core with artisanal copper. | choeger wrote: | You use copper? These kids today... | noam_k wrote: | Relevant xkcd: | | https://xkcd.com/378/ | nine_k wrote: | Don't tell them about the lost art of loading microcode on | boot. | taeric wrote: | I think arguing that assembly is an abstraction is going the | wrong direction on why it is hard. Assembly largely forces | numerical abstraction on your problem. Which is a lot harder | to reason about than folks want to acknowledge. | | That is, higher level languages let you get farther away from | the abstraction that is the computer itself. As such, you can | have a less abstract program in a language that has higher | abstraction away from the execution environment. | dlivingston wrote: | > Even assembly language is an abstraction | | Is this true? I thought assembly mapped 1-to-1 with actual HW | instructions. If so, assembly wouldn't be an abstraction, it | would be an interface. | Spivak wrote: | Nope, the CPU presents you an interface of the available | instructions but those instructions are a complete fiction | on modern processors and don't have to match at all what | the underlying hardware does. The CPU guarantees that the | observable effects of the instructions are consistent (i.e | if the processor wants to do some fuckery it can't change | the instruction semantics) but beyond that is free to run | your code however it wants. | nine_k wrote: | Simpler RISC designs, like simpler ARM cores, more or | less directly execute instructions; same for old 8-bit | cores you can still widely find in MCUs. Complex high- | performance cores, with pipelining, instruction fusion, | and OoO execution, turn instruction stream into a | microcode lava. | Spivak wrote: | So maybe the right thing to say is that assembly is a | contract between you and the processor and the underlying | implementation can map directly to hardware when | appropriate but it doesn't have to. It is an abstraction | over different underlying hardware implementations. | eterm wrote: | If you're not manually setting voltages on different pins | then at some level it's an abstraction. | [deleted] | nine_k wrote: | First of all, you normally use symbolic labels, not offsets | for jumps; the assembler will calculate them for you, and a | linker will possibly build a relocation table based on | them. Then, any good assembler has macros. Also, data / | text blocks, etc that are not code but an abstraction which | the linker later uses. | | Writing machine _code_ directly, as a byte stream, is fun, | but is exhausting. | ilyt wrote: | Arguably it's more of translation layer not abstraction. | You're not abstacting away any concepts or code blocks | here, you still have to write every single instruction, | you just get a bit of a help with math. | constantcrying wrote: | Assemblers like nasm have an entire macro language. Of | course that isn't part of the ISA. But in the end even | the ISA is fiction. | chacham15 wrote: | It is true. Abstraction means that you dont have to worry | about some lower level concerns. With computers, the rabbit | hole goes quite deep. | | High-level language (C/python) Assembly language | (att/intel) Byte code Micro code | | So, with assembly code, you dont care about what the actual | bytes that get generated are (they can change and you'd | never know if the system was backwards compatible). | Similarly, if the microcode that the CPU generates to | implement the instruction changes youd also never know. | constantcrying wrote: | >I thought assembly mapped 1-to-1 with actual HW | instructions. | | Assembly encodes a wide varity of abstractions (it is a | human readable format after all) and lots of assembly | instructions have a clear relation to an instruction on the | hardware, but definitely not all. E.g. a CPU does not | understand what a "label" is and the semantics of a labels | and jumping to them is removed by the assembler. | | But _not even the assembled binary_ actually maps to | executed instructions. The CPU is actually a virtual | machine which presents itself as e.g. an x86 ISA | interpreter, but internally it uses microcode executed in | various performance enhancing ways to speed up the process. | pclmulqdq wrote: | This is true. Ignoring the labels, macros, and directives, | there are many ways in machine code to encode most common | x86 instructions (zeroing a register even has many possible | assembly instructions!). Assemblers pick the best encoding. | unwind wrote: | Is that true? They swap actual instruction mnemonics as | written in the assembly source into different | instructions, for performance? I hope that is controlled | by some flag or something, seems like a strange thing for | an assembler to be doing unless asked. | | I seem to remember the venerable combined | assembler/monitor/editor ASM-One [1] on the Amiga having | a mode to do that, an "optimizing assembler", but I think | it mainly worked with instruction and data sizes, i.e. | optimizing short jumps into branches which were cheaper | on the 68k. | | [1]: https://en.wikipedia.org/wiki/ASM- | One_Macro_Assembler | pclmulqdq wrote: | I believe that there are some assemblers that will swap | "mov rax, 0" for "xor eax, eax" (which is smaller and | faster), if you let them, but not all of them. Some | instructions like "jmp LABEL" correspond to many | different options (short relative jumps, long relative | jumps, absolute jumps, etc.) and the assembler picks the | best one. | | As another example, almost all of the vector instructions | have an encoding with a VEX prefix (an AVX encoding) as | well as the older SSE encoding. If you mix the VEX and | SSE encoded instructions, there can be a big slowdown, so | an assembler will give you VEX encodings if you have AVX- | only instructions in the stream, and default to SSE | encodings if you don't (they are often smaller). | | Some instructions, like LEAs and ADDs, have several | different encoding options corresponding to different | operand orderings, and an assembler will pick the best | one - some of these encodings will force an extra SIB | byte when you use R12 as an operand, for example. | | This is kind of assembler-specific in terms of how smart | it is. I'm not sure that the dumber assemblers do this | for you. | deckard1 wrote: | > I thought assembly mapped 1-to-1 with actual HW | instructions. | | on x86 it's a 1-to-many relationship. There are, for | example, many different MOV instructions that can be | encoded based on the parameters used. All assemblers I know | of hide this from the user, as well as featuring labels, | macros, etc. which are not defined by the hardware at all. | For the most part, the x86 assembler hides the details of | prefix bytes and ModR/M+SIB from the user. Some assemblers | are quite advanced and if you took them just a few logical | steps beyond where they are you would end up with C. | littlestymaar wrote: | > Is this true? I thought assembly mapped 1-to-1 with | actual HW instructions. If so, assembly wouldn't be an | abstraction, it would be an interface. | | Assembly gives you a nice sequential list of instructions, | completely hiding pipelining, speculative execution, and | all the magic that modern (since the 90s at least) CPU do | to do the job fast. | | And as the Spectre family of CPU vulnerabilities, these | abstractions are in fact more leaky than most people | assume. | trashtester wrote: | And cache management, thread switching | optimization/prioritization, and so on. | | If a CPU were to ONLY do the instructions that were | written in the assembly code, the code could be maybe | 5-10 times slower when using cached memory and 100x | slower if accessing RAM constantly. | | And this is part of the reason why it's hard to write | assembly that is faster than a well optimized C/C++ | program. The C compiler "knows" (to some extent) what the | machine code leads to at the hardware level, and will | often create machine code that is more liklely to allow | the CPU to reap all such advantages in a way many | assembly programmers wouldn't know about or think of. | agentultra wrote: | I pick only the best artisinal integer representations for my | programs. Only fools use abstractions. | pclmulqdq wrote: | I wrote the piece. The argument I tried to get across is: "You | must use abstractions. Find the ones whose values align with | your interests." | | I find people frequently torturing their problems into | abstractions they like rather than finding abstractions that | work for their applications, and this is very much wrong. | | Edit: By the way, the examples are fairly low-level databases | because that's what I know about. If I knew about web | frameworks, I would have used those instead. | danielmarkbruce wrote: | The material is good, nice going. But the title is | misleading. | pclmulqdq wrote: | Thank you. I will add that the title is intentionally | provocative. However, I want to encourage developers to | think of an abstraction as something you pay a significant | cost for rather than something you get for free, and use | that logic to make good choices. | | In a sense, you hire abstractions a little like you hire | employees. Interview them and make sure your values match. | danielmarkbruce wrote: | "abstraction in expensive" makes people think you are | implying one shouldn't use abstraction. It's all well and | good that the content doesn't say that, but as | journalists say: "don't bury the lede". | danielmarkbruce wrote: | An aside - if you haven't read any Michael Porter, you | might find it interesting. | | https://iqfystage.blob.core.windows.net/files/CUE8taE5QUK | Zf8... | | Slightly different concept, but similar ideas around | consistency given a set of explicit choices/constraints. | danShumway wrote: | I would argue that abstractions are usually expensive. | | It's just that sometimes not doing something expensive is | also expensive. Getting your car regularly maintained is | expensive, so is not doing that. | | The issue with abstractions is that people have _not_ | internalized them as "an expensive thing we do to prevent | ourselves from running into expensive problems later"; | they're internalized them as a zero/low-cost process that | has no downsides and thus should be pursued all the time. | | It's like if people said, "not getting your oil changed | will be more expensive, and therefore I get my oil changed | every other week." | | I kind of think that the only reason that the phrase | "abstractions are expensive" sounds like a controversial | take is precisely because people have not internalized that | abstractions are not a binary good/bad thing and that they | should be applied situationally, because they do have | maintenance costs and development costs. | danielmarkbruce wrote: | Sure, the statement isn't wrong. But the content is | mostly about making good/consistent choices given the | situation. | danShumway wrote: | > But the content is mostly about making good/consistent | choices given the situation. | | That's what I'm saying though. You need to make | good/consistent choices about the given situation because | abstractions are expensive, not free. If they were free, | we'd just throw them everywhere with no thought. | danielmarkbruce wrote: | What you are saying isn't wrong, but when someone reads | "abstraction is expensive", they immediately assume the | implication "and hence you shouldn't use it". | | To make an analogy: people shouldn't buy a sports car if | they want to take their family of 5 skiing every weekend. | A person might reasonably write an article on all the | factors one should consider when buying a car. They | shouldn't title said article "Cars are expensive", even | though the reason they wrote the article is because cars | are expensive and hence the choice is important. | danShumway wrote: | > but when someone reads "abstraction is expensive", they | immediately assume the implication "and hence you | shouldn't use it". | | I suppose? But if someone's attitude is that expensive | things should be universally avoided, that seems like a | problem that's going to need to be addressed sooner or | later. | | Would we be having this conversation under an article | titled "abstractions have benefits"? Would we be worried | that someone is going to look at that title and think, "I | should use them everywhere all the time then"? | | I don't know. I'm not against phrasing something in a way | that minimizes confusion, but on some level I think that | internalizing that programming concepts aren't binary | good/bad is arguably one of the most important lessons | that a programmer can learn. And I regularly see a kind | of pushback to the (correct) notion that abstractions | have costs that I don't see in other contexts. But that | could just be, and my experiences might be different than | other people's. | | This is largely a subjective take by me, so I understand | if people disagree with it, but the prevailing attitude I | personally see in software development is one where | people do not realize that there is a cost to | abstractions, and in fact sometimes bristle at the idea | that they do have costs. At most, I can get people to | agree that 'bad' abstractions have costs, but it is much | harder to get them to say, "it's possible to abstract | _too much_ , and even good and necessary abstractions are | still additional code with additional costs." | | So I think the notion that it is not always correct to | abstract every piece of code is weirdly controversial -- | and the underlying idea behind that that I think people | haven't internalized is "sometimes good things have a | cost, and we should talk about the costs that they have." | | But again, could just be me. If a bunch of people are | confused over the title, then... I mean, I can't tell | people what they should and shouldn't be confused about. | If it's better to communicate with them in a different | way, then it is what it is. It just worries me if on a | programming site so many people interpret "is expensive" | as "should never be used." That's not a good programming | philosophy for people to have. | pclmulqdq wrote: | That's very well-phrased, and you beat me to this | comment. :) | | I wanted to get across that an abstraction is an | expensive thing you should use to solve a difficult | problem, not a cheap thing you use to solve a simple | problem. | infogulch wrote: | > abstraction is an expensive thing you should use to | solve a difficult problem, not a cheap thing you use to | solve a simple problem | | Nailed it. | btilly wrote: | One point about abstractions that you might want to make in a | future article is that developers tend to discount the cost | of all abstractions that they have internalized. Therefore | when they get to a new environment, they immediately try to | recreate and incorporate the abstractions that they used | previously. | | However these abstractions are not free. They are not free | for performance. They are not free for debugging. And they | are especially not free for any future developer who is not | familiar with them. | | The joke I grew up with was, "Andy giveth, and Bill taketh | away." It is no longer Intel under Andrew Grove who gives us | better performance. It is no longer Microsoft under Bill | Gates who gives us slower software. But the basic phenomena | is still true. Hardware improves over time. But developers | happily introduce abstractions with no awareness of the | associated costs. | 1vuio0pswjnm7 wrote: | "Lack of abstraction is also expensive: try writing something | large in assembly." | | What about writing something small. | kenjackson wrote: | And then using that small thing as a subroutine that you can | call into to repeat that same functionality... | kenjackson wrote: | Right. Abstraction has cost. It may or may not be expensive. | Know the cost and then decide if it's worth the cost. | cle wrote: | IME the best abstractions hide the underlying complexity by | default, but allow you to "pop the hood" when necessary. The | more this exposes the guts of the underlying implementation | details, the better (though obviously that comes with tradeoffs | around changing underlying impl details, although I think as an | industry that we over-index on that too much, which leads to | exactly this problem). | | Go's compiler intrinsics immediately come to mind here. They | allow you to easily write Go functions in native assembly, | without CGo, for hot code paths. We get the benefits of a high- | level language with a fat runtime, but can easily drop down to | assembly when we need to. | anfilt wrote: | In my opinion good abstractions layers should also have a way | to peel things back like layers of onion. | | Taking the authors example of a TCP network stack you often | can't do though since OS won't let you have that low level of | access by default without using or writing some custom driver | since the OS ends up trying to isolate usee-space completely. | | Kinda makes me wish more research has been done on things | like exo-kernels where the OS is mainly concerned with | security and not the abstraction. All the abstraction runs in | user space on such a kernel and you can choose what level is | suitable for what your doing. | https://en.wikipedia.org/wiki/Exokernel | ChicagoDave wrote: | Abstractions are at their worst when they cross bound contexts. A | customer in a billing system is not the same as a customer in a | sales pipeline system. By merging disparate purposes for | seemingly technical benefit, we often create complexity where | none need exist. | | Domain Driven Design helps wall off inappropriate and costly | abstractions. | cloogshicer wrote: | Even though many people call abstraction 'the essence of | programming', it is rarely fully understood. Maybe no human on | the planet really understands it. I've long had an essay in me | about this topic that I really need to put to paper soon. | | Here is the brief version of that essay: | | * Programming is about building theories/models of the problem. | Source code largely has no value by itself [1] | | * It is very difficult, if not impossible, to transfer these | models/theories between humans (see the essay I linked below for | details) | | * Because of this difficulty, programming is essentially teaching | (when writing program code, we're teaching other people of the | problem domain, and models that fit that problem domain) | | * Another way to phrase this: All programming is building user | interfaces. When you're writing, say, a function, you're writing | a more abstract UI for the next programmer or yourself | | * The tools we have for writing these UIs are terrible - taken | the above example of writing a function, what are the tools you | have to communicate this idea to the next person? A single string | of characters (the function name). In a typed language you get a | bit of extra info because of the type information (I believe this | to be the main advantage of type systems). | | * The big question is: What would a better UI for communicating | abstractions look like? | | * I don't know the answer to that question but I have a hunch | that it has to be bi-directional. If you've ever worked with a | GUI library that has a visual editor, you know how awful they | are, unless there is also a representation of the same GUI in | code. This bi-directional mapping of code and GUI makes it very | easy to understand the two different ways of looking at the | problem. I think something like this is needed down to the very | lowest levels of abstractions. | | * Another way to phrase this: Imagine two different scientific | models for the same problem. For example, for the model of an | atom, its protons and neutrons, there is the more simple Bohr | Model, which is completely wrong, given our current knowledge, | but still very useful in many modern calculations. But in certain | situations, a more accurate model is needed, which takes quantum | mechanical effects into account. I see an analogy for programming | here: In most cases, a simplified model suffices, but as more | performance is needed, a more complex model is required. The | question is, how can we easily teach someone the more difficult | model, once they've understood the simple one? And the other way | around (which is often also not easy, since simple is not the | same as easy). | | If you have any thoughts on what I've written, any at all, I'd | love to hear from you (I'll watch this thread, or find my email | in my bio). | | [1] https://hiringengineersbook.com/post/autonomy/ | agentultra wrote: | > it is rarely fully understood | | I beg to differ. Case in point: type classes, the Monoid type | class, and Monoids as the mathematical concept; all well | understood, proofs of their existence and properties are stated | exactly, and when implemented by a compiler behaves exactly as | expected when the program is executed. This is precisely what | people mean when they say "abstraction is the essence of | progamming"... | | ... when they understand what abstractions are and use a | precise definition. | | Unfortunately there exist many programmers in the world who do | not use precise definitions and don't know how to state | mathematical laws or invariant properties of relations. They | too use the word "abstraction" and they often mean... whatever | it is they mean. It differs from person to person and is often | used when they're waving their hands and trying to make a | point. | | _Update_ : The overwhelmingly vast majority of programmers | don't think about integer representations and how arithmetic is | implemented these days; some do and that's fine, but the | software world continues to ship vastly complex programs and | systems without having to care about it and everything still | works. That's abstraction at work. | a1369209993 wrote: | > Case in point: type classes, the Monoid type class, and | Monoids as the mathematical concept; [...] when implemented | by a compiler behaves exactly as expected when the program is | executed. | | Not true in general. For some specific instances (such as | fixed-size Int under addition or multiplication[0]), it | works[1], but in the general case (eg Integer under add or | mul, [Foo] under concat) `a <> b` can fail with out-of-memory | if a and b are large enough. (This debateably violates | closure of `<>` (you could say `undefined`/`error "out of | memory"`/etc is a valid element), but indirectly breaks all | the other Monoid laws like `(a<>b)<>c==a<>(b<>c)`, since the | result is `undefined`(/etc), rather than `True`.) | | 0: Actually, I'm not sure it's true even then: does Haskell | actually guarantee 2s-complement truncation on overflow? | | 1: Give or take "How many bits does Int truncate to?". | agentultra wrote: | Isn't this why fixed, signed integer types don't have a | Monoid instance? | | https://hackage.haskell.org/package/base-4.17.0.0/docs/Data | -... | | For arbitrary sized `Integer` type, which is basically a | libgmp arbitrary integer, we also don't have a Monoid. | a1369209993 wrote: | > Isn't this why fixed, signed integer types don't have a | Monoid instance? | | No. Integers (signed or unsigned, fixed or arbitrary- | precision) don't have Monoid instances since Haskell | requires a single class instance per type, and it's | ambigous which instance should be the "canonical" one. | | The types `Num a => Sum a` and `Num a => Product a` have | Monoid instances, but it's not clear whether the | "canonical" instance for a given integer type should have | `(<>)` defined as `(+)` or `(*)`... or `min`, `max`, | `and`, `or`, `xor`, `lcm`, `gcd`, or any of several dozen | other monoidal operations. | | Conversely, `[a]` doesn't really have any resonable | monoidal operation _other_ then `concat`, and most of the | existing Monoid instances (most conspicuously Sum and | Product above) are even more nothing-else-is-reasonable, | if only because of their names. | garethrowlands wrote: | The main reason Haskell does not define Monoid instances | for numbers is that there are two equally valid | instances: with 1 and * or with 0 and +. So, instead, | there are two newtypes defined: | | * `Sum` whose `mempty` (identity) is `Sum 0` and `<>` | (combining operator) is multiplication; and * `Product` | whose `mempty` is `Product 1` and `<>` is addition | | You have to choose one explicitly. That is, you can't say | `2 <> 3` and expect 6 (or is it 5?). Instead you have to | say `Product 2 <> Product 3` | a1369209993 wrote: | > * `Sum` whose [`<>`] is multiplication; and * `Product` | whose [...] `<>` is addition | | ... Uhh? | cloogshicer wrote: | I'm one of those programmers you mentioned. Could you help | me? I'm genuinely trying to learn more about this. What is | the precise mathematical definition of the term abstraction? | | Any links to good resources are appreciated. | agentultra wrote: | > Mathematical abstraction is the process of considering | and manipulating operations, rules, methods and concepts | divested from their reference to real world phenomena and | circumstances, and also deprived from the content connected | to particular applications. | | https://journals.openedition.org/philosophiascientiae/914?l | a... | cloogshicer wrote: | Thanks for the link! | cwzwarich wrote: | Those abstractions are still leaky, e.g. it's entirely | possible that an optimizing compiler could apply correct | monoid laws and end up with a program that has vastly | different space usage. | agentultra wrote: | Without abstraction it would be difficult to write a proof | that your implementation of the monoid laws stay within | specified bounds. | | It's not "leaky" if the specification doesn't say anything | about the space bounds. That's a separate concern from | "abstraction" itself. | | _Update_ The idea of a monoid is divested of any real- | world implementation and that 's what makes it useful (and | consequently also hard to explain). The important thing is | that there are laws to how the operations on monoids | compose and relate to one another that must be maintained | no matter how they're implemented in an actual computer. | travisjungroth wrote: | I've had similar thoughts. Extremely condensing things, I'd see | lots of value in: | | * Better code folding, so you can cram more info into source | code but also hide it easily. | | * Function signatures with "types" that are arbitrary | predicates and optional generators. | | * Function signatures with properties e.g. this binary function | is commutative over type X. | | * Combine those and you can name algebraic structures. | | * "Enforce" this all through property based testing. | | IMO, this would make code that's much easier to reason about | than untyped code while being more approachable and flexible | than other typing systems. | gpspake wrote: | Abstractions are inevitable in software so the important thing is | to think about, recognize, identify, and manage them. Sometimes | it's appropriate to "unroll" bad abstractions in a codebase. | | quotes I live by (Mostly accurate from my memory): | | Repeated code is better than the wrong abstraction - Sandi Metz. | Always know what the abstraction is, its value, and its cost - | Kent Dodds. | fdgsdfogijq wrote: | I think its a meme now to hate abstraction. In big tech I see it | as a justification to build parallel systems that do almost the | same thing. Abstraction done well is where technical leverage | comes from. Abstraction done poorly is where technical debt/bad | technology comes from. Management prefers the safe route of | gating their engineers from abstraction to get the work done with | certainty, the trade off being less technical leverage. Its a | corporate engineering meme to pin tech workers into being | replaceable cogs pumping out low abstraction widgets | BlargMcLarg wrote: | I wish it was a meme. The things people complained about | decades ago are still happening today, and the practitioners | are all too eager to turn a 100 line program into a 1000 line | one, while taking weeks to test if it does what it should. | | The average loud dev is a GoF fanatic in love with inaccessible | reflection. Double points if their tools are still stuck in a | time where stack traces weren't extended to deal with such | practices better. | | And with everything being sliced into pieces: the fun has only | just begun | fdgsdfogijq wrote: | Call me blunt, but ive come to the conclusion most people | arent intelligent enough to create complex abstractions | BlargMcLarg wrote: | I don't think intelligence or lack thereof is the problem. | Rather, it seems people are paralyzing themselves by | enjoying the endless discussions, stakeholder indecision, | or boredom. All leading to these grotesque things which | lack words in the right places, but have plenty in the | wrong places. | | The average web dev CRUD job isn't interesting enough to | warrant that much intelligence. | trashtester wrote: | Intelligence is definitly a factor. In fact, more often | than not when I encounter a person or team that seem to | spend their time on everything else except addressing | their most important problems, the reason for the | apparent procastination is that they simply do not even | know how to START solving the problem. | | This is not exclusive for developers. It happens in | management, too. Which is a second source of the problems | you describe. | bbkane wrote: | I'm certainly not. I try to compensate when I can by | aggressively rewriting until an abstraction stops breaking | things and feels natural | trashtester wrote: | Every person have a limit on how complex abstractions | they're able to properly create. Then there is another, | usually lower, limit for what kind of abstraction they're | able to understand well enough to make use of it. | | In a lot of cases, people try to leverage abstractions | above that second level (for them), in which case they're | simply imitating in a cargo cult manner some abstraction | that will often not work well if not properly understood. | | This is where the atrocities start, imo. | | And the sad part is that many of these programmers do have | a fairly good understanding of the business needs of the | stuff they're making, and often those things are quite | simple from a technical perspective. | | Programmers that might have been able to create perfectly | usable apps in VB or something similar 20 years ago, are | now only churning out useless garbage in some moder cloud | based stack. (Or, at bes,t are using 80% of their time | struggling with their tech, while with a simpler setup, | they could have spend only 20% on the tech and used 80% of | their attention on addressing business needs.) | adamrezich wrote: | my experience is quite the opposite, it's much more | difficult to create a _simple_ abstraction as opposed to an | overengineered and /or overgeneralized one. | fdgsdfogijq wrote: | complex != overengineered and/or overgeneralized one | | some technical problems are actually just complex | adamrezich wrote: | sure, but it's easier to solve a complex problem by | building an abstraction that is more complex than the | problem requires, that to build an abstraction that is as | simple as possible (given the complexity inherent to the | problem). then, once you have your too-complex | abstraction, it can be difficult to restrain yourself, | especially as an eager junior developer, to not take your | amazing feat of abstraction engineering to its logical, | generalized conclusion... or at least die trying. | | "see, now, every time I want to do _x_ , all I have to do | is _y_ and _z_ , instead of _a_ , _b_ , _c_ , and _d_ " | is an incredibly addictive drug! (I write this as a | recovering addict.) | fdgsdfogijq wrote: | right, but my point is thats what we call a bad software | developer. and most software developers are warned, | because real abstraction is beyond their capability. a | world class software engineer knows that maxim, but also | is capable of building an abstraction that lasts. | civopsec wrote: | Call me blunt, but this statement feels about as hard- | hitting and impactful as someone shouting in a crowd that | they like pastrami sandwiches. | auggierose wrote: | GoF = Game of Failure? | gpderetta wrote: | Gang of Four, as the authors of the Design Patterns book | are known (and by extension the book itself). | auggierose wrote: | Oh right, that book is so old, I forgot that it ever | existed ... | feoren wrote: | Reading the article and most of these comments, I've concluded | that no two people are using the word "abstraction" exactly the | same. I don't really understand what the author's definition of | an "abstraction" is. He seems to call a poor database schema an | "abstraction misalignment"; is anything _not_ abstraction | misalignment? It feels like we 're in an old-folks home where | everyone is talking but nobody is conversing. Nobody is agreeing | on what "abstraction" means. A better title for this article is | "mistakes are expensive", or possibly "bad design is expensive". | But of course then nobody reads it, because everyone loves to | hate on whatever they've decided "abstraction" means for them. | NoZZz wrote: | Hey talking heads. | pca006132 wrote: | The problem is that application performance doesn't only depend | on the thing you want to do, but also depends on the low level | implementation details and workload, which the programmer may not | fully understand or in control of. Some operation may be optimal | when executed alone but exists better alternative for batch | processing. Some programs may be optimized for throughput but is | really bad for low latency application. The designer have to | consider these when designing their system, and compilers/library | writers can't help much except write a more comprehensive | documentation which the programmer will probably not read :). | | I think abstraction guides implementation, so it is very | beneficial to think about what will be the bottleneck in the | application, and if a certain abstraction will hinder the | performance or prohibit future optimization. And although a low | level abstraction can _in theory_ allow for better performance if | the programmer spend enough time to optimize for it, they often | won 't and a simpler interface (with sane implementation and | perhaps escape hatches for performance tuning) may allow for | better performance with much less effort. | AnimalMuppet wrote: | > I think abstraction guides implementation, so it is very | beneficial to think about what will be the bottleneck in the | application | | I think this way, but in terms of the "performance" of | _writing_ the application. What makes it hard to write this | program? For example, in high-performance computing, you may | need to control memory alignment (for SIMD and cache reasons). | That makes it harder to write a program that just implements an | algorithm. | | So I think you should identify what it is that makes the | program hard to write, and pick abstractions that help with | that, that give you easier ways of controlling or managing that | hard part. | AtNightWeCode wrote: | I think it is too common that you have to work with abstractions | that hides functionality in the underlying tech. | [deleted] | LAC-Tech wrote: | I know this is about back-end, but it partly describes my issues | with front end - the industry standard abstractions save you very | up front development time, but they increase the project | complexity massively. | another_devy wrote: | I think front end is possessed with abstraction and DRY. | Everything has to be a library or npm module, People keep on | writing their on versions of same stuff most of the times | because they didn't liked the name of the function or order of | arguments. Complexity in front end is definitely increased by | obsession of abstraction while it should've reduced it | kahon65 wrote: | Not if ChatGPT creates it. | uvdn7 wrote: | And no abstraction is perfect, as by definition an abstraction | hides some details from the layer beneath. A good abstraction is | one that allows you to not look under the hood most of the time. | One can be happily writing code in their favorite programming | language until you want better performance and started looking | into cpu caches, branch prediction, etc. which are "breaks" the | nice abstractions provided by the OS and high level programming | languages. | gavinray wrote: | ScyllaDB is, ironically, maybe one of the worst examples the | author could have come up with for "abstraction" in the article. | | If folks aren't familiar with their work/internal tech, go check | out some of their repos like Seastar. They have some of the most | talented systems programmers on the planet writing thin veneers | over kernel and hardware API's to squeeze every ounce out of | performance. | | https://github.com/scylladb/seastar | | You want to talk about getting nerd-sniped to work somewhere if | you're into performance/low-latency systems and databases =P | | I know it's beside the point, but I just had to share because I | thought that was funny ___________________________________________________________________ (page generated 2022-12-07 23:00 UTC)