Author: [[simpleprogrammer.com]] <!--ID: 1614239817606--> Full Title: Respecting Levels of Abstraction - Simple Programmer <!--ID: 1614239817633--> URL: https://simpleprogrammer.com/respecting-abstraction/ <!--ID: 1614239817649--> ### Highlights first synced by [[Readwise]] [[2020-09-16]] the importance of good naming of variables and functions, encapsulation, class cohesion, the usage of polymorphism, concision, readability, code clarity, expressiveness, and many other principles. If you consistently deploy all of these practices, you're in fact doing one thing: respecting levels of abstraction. As we’ll see in greater detail in this article, an abstraction is characterized by what a particular piece of code intends to do as opposed to how it is implemented. - this is the most central notion of all. - Respecting levels of abstraction means that all the code in a given piece of code (a given function, an interface, an object, or an implementation) is at the same abstraction level. Said differently, abstraction levels are respected if, at a given level, there isn’t any code coming from another level of abstraction. - When we move from a higher level of abstraction to a lower one, the execution of the tasks in the less abstract level is how we implement the more abstract level. In our example, evaluating an asset is accomplished by computing a probability. We compute a probability (higher abstraction) with elementary mathematical operations (lower abstraction), and so on. - One principle to rule them all I deem respecting the levels of abstraction to be the most important principle in programming, because it automatically implies many other best practices. - polymorphism involves providing interfaces or abstract classes to manipulate decoupled implementations of a single concept. Polymorphism consists of segregating levels of abstraction. > Indeed, for a given interface (or abstract class) and concrete implementation, the base class is **abstract** and the implementation is **less abstract**, because the base class describes **what** it does as an interface, while the implementation code describes **how** it does it. ^abfb8b - Good naming, encapsulation, cohesion - But as you might notice, “getMap” is not a good name. It isn’t a good name because — at the abstraction level of the caching interface — “Map” is a term of how (observe that it appears in the bottom part of the diagram), and not what, so “Map” is not at the same abstraction level as the thing it names. Calling it “getMap” would mix several abstraction levels together. - A simple fix would be to call it “getAllValues” for instance. “Values” is a consistent term with the level of abstraction of the caching interface and is therefore a name that is more adaptable than “Map”. You can accomplish good naming by giving names that are consistent with the abstraction level they are used in. This works for variable names, too. - encapsulation is the restriction of access to implementation data inside an object. - breaking encapsulation means providing information that goes beyond the abstraction level of the interface. - Now imagine that we added a new method in the caching class to do some formatting on values: This is obviously a bad idea because this class is about caching values, not about formatting them. Doing this would break the cohesion of the class. In terms of abstraction, even though caching and formatting don't have a what-how relationship, they are two different abstractions because they are in terms of different things. So cohesion consists of having only one abstraction at a given place. - Concision, readability, expressiveness - A first trial might write a for-loop to do this, but the best solution here in C++ is to use the remove_if algorithm of the C++ Standard Template Library (STL). STL algorithms say what they do, as opposed to hand-made for-loops that show how they are implemented. By doing this, STL algorithms are a way to raise the level of abstraction of the code to match the one of your calling site. I think expressiveness is the primary characteristic to strive for in code. This is particularly true for long-term or industrial-strength projects because expressive code is manageable in that it tells what it means to do. - The problem is code that describes how it performs an action rather than what action it performs. To improve such a piece of code, you need to raise its level of abstraction. And to do so you can apply the following technique: Identify what things the code does, and put a label on each one of them. - If you think about this principle when designing your code and constantly ask yourself the question, “In terms of what am I coding here?”, your code will flow naturally, perform its function well, and be a pleasure to use for the other programmers and developers who have to work with it. As developers, expressive code is generally what we call “beautiful” code. And as stressed in John’s post about the advantages of clean code, having code that developers find beautiful is something a software company should look for. By identifying what things the code does and replacing each one with a label, we know how to raise levels of abstraction in order to make code more expressive.