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