[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)