Live data from Hacker News

The Cost of Abstraction (2016)

250bpm.com

11–20 of 65 posts

Re: The Cost of Abstraction (2016)

#11
Very insightful. I like thinking about software complexity and one of the concerns there to deal with complex software is that the design and intentions should be communicated (which means either documentation or exist as a common understanding of purpose and function).

From your perspective, it means that there is also a need to establish agreements on the levels, depth and ways abstractions in the code are formed. Indeed, I worked with software where the functions and operations weren't implemented in a messy way per sé, but the many levels of indirection, abstraction (and obscurement) made things just really difficult to read and a real tail-chaser when it came to maintenance.

Those levels can also make it much more difficult to understand the flow and the operations that are happening, because in many languages you pass references to data objects, so data gets changed in many ways.

Nice article, puts me into thinking mode again! :)

Re: The Cost of Abstraction (2016)

#12
post #6
post #3

That's a really simply abstraction there, and I bet most people won't even call that an abstraction. It's a bit like saying bricks are useless, by limiting the entire argument to a single brick.

It's almost like he's making a small non-real-life example to illustrate his general point, which is not confined to the particular example.

Your comment reads just as well without the condescending "It's almost like" at the beginning

Re: The Cost of Abstraction (2016)

#13
post #5

I've seen excessive abstraction kill projects time and time again. The crime scene is similar in every case: - What if we ever need to change database server or driver? Proceeds to write a layer to abstract data access - We might have different login forms one day? LoginFormFactory it is - This code hits our KV Redis/memcache/NoSQL by calling the driver lib directly? Can't have that, I'll write a CacheStorage or Docu…

Which is not to say that we shouldn't wrap dependencies. We absolutely should. But by default, the wrapper should not offer an abstraction that is so flexible that the dependency can be exchanged. Instead, it should start with the actual problem, by offering only abstractions that (a) make sense in the context of the program and (b) translate well to concepts of the dependency/library. For example, hiding POSIX-style…

> Which is not to say that we shouldn't wrap dependencies. We absolutely should.

Why?

If I'm writing something for a known environment that's unlikely to change, it seems like a waste of time.

Re: The Cost of Abstraction (2016)

#14
post #13

Earlier quoted context omitted.

Which is not to say that we shouldn't wrap dependencies. We absolutely should. But by default, the wrapper should not offer an abstraction that is so flexible that the dependency can be exchanged. Instead, it should start with the actual problem, by offering only abstractions that (a) make sense in the context of the program and (b) translate well to concepts of the dependency/library. For example, hiding POSIX-style…

> Which is not to say that we shouldn't wrap dependencies. We absolutely should. Why? If I'm writing something for a known environment that's unlikely to change, it seems like a waste of time.

Even then, often there will be small bits that don't fit well. By wrapping everything you make the model and assumptions of your application explicit. Code that is written against your own model (which is almost always simpler than what the library offers) will be more understandable.

I really like the Dijkstra quote, "The purpose of abstraction is not to be vague, but to create a new semantic level in which one can be absolutely precise."

Usually I even wrap libc and POSIX functionality in my C programs. Advantages include (1) not having to mess with specific types, such as size_t, time_t, DIR*, and so on -- which often don't fit my own model (e.g. dealing with unsigned size_t vs signed integers is painful), and often need small fixes to be portable. (2) compiles a lot faster since I don't need to include 10000s of lines from system header files (3) not wrapping makes huge portions of the project dependent on the library, instead of only the wrapper. (4) You tightly control access to the library, which makes it easier to troubleshoot. You can also make up your own strategy for managing library objects in a central place.

Re: The Cost of Abstraction (2016)

#16
I totally agree that the cost of abstraction should become more important. It is often the number one cause of frustration when trying to add a new feature to an existing code base. Building a mental model of any code base takes time. Abstractions for the sake of abstraction makes it harder to grasp.

Re: The Cost of Abstraction (2016)

#17
post #5

I've seen excessive abstraction kill projects time and time again. The crime scene is similar in every case: - What if we ever need to change database server or driver? Proceeds to write a layer to abstract data access - We might have different login forms one day? LoginFormFactory it is - This code hits our KV Redis/memcache/NoSQL by calling the driver lib directly? Can't have that, I'll write a CacheStorage or Docu…

Which is not to say that we shouldn't wrap dependencies. We absolutely should. But by default, the wrapper should not offer an abstraction that is so flexible that the dependency can be exchanged. Instead, it should start with the actual problem, by offering only abstractions that (a) make sense in the context of the program and (b) translate well to concepts of the dependency/library. For example, hiding POSIX-style…

Dependencies should be treated like if it was your own code. After you have replaced some API for the third time you can start thinking about wrapping it.

Re: The Cost of Abstraction (2016)

#18
post #9

I find that there's two core points that help me figure out where I'm missing some form of abstraction: the body of a function should only operate on a single level of abstraction, and it should only know technical details about one thing. If you're writing some database code, having high-level fetchMyEntity() calls mixed with connection/resultset/cursor logic is bad news. If you're writing something that reads from…

Yes. I look for something I can measure when I make this decision. Will it result in less code? Will it improve performance? Will users/customers care?

Re: The Cost of Abstraction (2016)

#19
post #13

Earlier quoted context omitted.

> Which is not to say that we shouldn't wrap dependencies. We absolutely should. Why? If I'm writing something for a known environment that's unlikely to change, it seems like a waste of time.

Even then, often there will be small bits that don't fit well. By wrapping everything you make the model and assumptions of your application explicit. Code that is written against your own model (which is almost always simpler than what the library offers) will be more understandable. I really like the Dijkstra quote, "The purpose of abstraction is not to be vague, but to create a new semantic level in which one can…

Yes, a library is already an abstraction, just somebody else's. Thread parent is complaining about bad design that doesn't model the problem, not abstraction.

Re: The Cost of Abstraction (2016)

#20

Earlier quoted context omitted.

Even then, often there will be small bits that don't fit well. By wrapping everything you make the model and assumptions of your application explicit. Code that is written against your own model (which is almost always simpler than what the library offers) will be more understandable. I really like the Dijkstra quote, "The purpose of abstraction is not to be vague, but to create a new semantic level in which one can…

Yes, a library is already an abstraction, just somebody else's. Thread parent is complaining about bad design that doesn't model the problem, not abstraction.

What do you mean? Bad design in the library? In a wrapper? What's the difference between "design" and "abstraction" here?
Post reply on HN