Marcell Ciszek Druzynski

Abstraction

Abstraction is a technique to manage complexity by making a system simple to use, while hiding unnecessary details of what is really happening.

March 22, 2023

Intro

I would like to discuss programming abstraction and its prevalence in our daily lives as programmers. Each day, we interact with some form of abstraction when we write code, whether it's using a new language feature, an external API, or creating our own abstraction, such as building our own React hook.

This post will include:

  • Overview what is abstraction
  • Interfaces
  • Examples
  • Downsides

Abstraction is a useful tool in computer science that aims to simplify complex systems to enhance comprehension and ease of use. This means that irrelevant implementation details of APIs or data are hidden from the user, allowing them to focus on the relevant information. To illustrate this concept, consider a coffee machine; when using it, you do not need to understand the intricacies of how it functions, as all that matters is that it produces coffee. The machine's inner workings are abstracted from the user to make the experience simpler and more enjoyable. Similarly, imagine a city where every task must be approved by the mayor, including hospitals, schools, and fire departments. This process would be cumbersome and time-consuming. A solution would be to group tasks into specific departments such as the fire department. This grouping and labeling process is an abstraction, allowing the mayor to delegate tasks to the fire department without needing to know all the details of how they will carry them out.

Layers of Abstraction

In order to effectively manage complex systems, it is crucial to break them down into manageable components with clearly defined tasks. Whether it's computer systems or human systems, abstractions serve as a valuable tool to help navigate the intricacy of such systems. However, the use of abstractions can result in multiple layers of complexity, which is not always desirable. Although abstractions are a common practice in programming, adding too many layers of abstraction can have its drawbacks. For instance, consider the scenario where the Mayor communicates with the head of the Fire Department, who then communicates with the heads of each of the four firehouses, and so on. At each stage, there is a layer of abstraction being added, treating each component as an abstract entity. This can lead to significant delays in communication as it moves down the chain of command, which is one disadvantage of using multiple layers of abstraction.

Programming abstractions

The organizational layers that the Mayor encounters are not limited to human systems, but are also prevalent in computer science. For instance, when companies such as Intel or AMD design computer chips that power electronic devices, they also release an abstraction layer consisting of a set of commands for controlling the chip. These commands, known as assembly or machine instructions, provide a highly detailed way of writing programs that the chip can execute. While it's possible to write programs in machine code, it's an arduous process, akin to the Mayor micromanaging every detail of rescuing a cat or fixing a water pipe by calling every employee. Instead, it's more practical to use a programming language that's better suited for application development and is easier to write and comprehend, such as Javascript. Numerous programming languages, including Javascript, operate via interpretation. This entails the Javascript program acting as an interpreter, which takes the code written in Javascript and determines the corresponding machine instructions required to execute that code.

interpreter vs compiled

What is the difference between interpreter vs compiled?

The Cost of Abstractions

The incorporation of multiple layers of abstraction does not necessarily result in decreased speed or efficiency of a system. Even if abstraction does lead to reduced speed or efficiency, it can still have value. It is important to keep in mind that the purpose of abstractions is to simplify the management of complexity. At times, there is a tradeoff between the time taken by humans to solve a problem and the speed at which a computer can execute a solution designed by humans.

Interfaces

An important aspect of an interface is that it can be utilized without knowledge of its inner workings. For instance, the mayor may not be aware of the process used to prepare the meal they are consuming for lunch, yet they can still place an order. The mayor has other responsibilities besides obtaining the fire department memos and therefore does not need to concern themselves with the precise procedures involved in obtaining them. The focus is solely on obtaining the desired outcome, and the means by which it is achieved or the implementation details are not significant. When using an external API, for instance, the crucial aspect is obtaining the necessary data rather than the technical specifics of how the API delivers the outcome.

Interfaces for abstractions outline their capabilities and limitations.

Interfaces serve as abstractions that simplify complexity by outlining how to engage with a process while concealing the intricacies of the actual process implementation.

Abstraction is a methodology employed to simplify complexity by rendering a system more user-friendly, while obscuring extraneous details of its actual operations.

Abstraction in code

There are many different examples how we can demonstrate attractions but a common way that you learn in school is to give examples from the OOP(object oriented programming) paradigm.

  • Classes and Objects: Classes are an abstraction that represents a group of related objects, and objects are an abstraction that represents a specific instance of a class.

  • Inheritance: Inheritance is an abstraction that allows a new class to be based on an existing class, inheriting its attributes and methods.

  • Interfaces: An interface is an abstraction that defines a set of methods that a class must implement, without providing any implementation details. We are describing just the behavior but we don\t care about the details using interfaces.

  • Encapsulation: Encapsulation is an abstraction that involves hiding the implementation details of a class from other classes, and exposing only a public interface. With help of private fields and methods we hide the details and only make what is needed public, like methods.

  • Polymorphism: Polymorphism, which means many different forms/shapes is an abstraction that allows different objects to respond to the same message or method call in different ways, depending on their specific implementation.

A example could like like this:

1public interface Person {
2 void greet();
3 void birthday();
4}
5
6public class PersonImpl implements Person {
7
8 private final String name;
9 private int age;
10
11 public PersonImpl(String name, int age) {
12 this.name = name;
13 this.age = age;
14 }
15
16 @Override
17 public void greet() {
18 System.out.println("Hello My name is " + name + " and I am " + age + " years old!");
19 }
20
21 @Override
22 public void birthday() {
23 age++;
24 System.out.println("My age is now " + age);
25 }
26}
1public interface Person {
2 void greet();
3 void birthday();
4}
5
6public class PersonImpl implements Person {
7
8 private final String name;
9 private int age;
10
11 public PersonImpl(String name, int age) {
12 this.name = name;
13 this.age = age;
14 }
15
16 @Override
17 public void greet() {
18 System.out.println("Hello My name is " + name + " and I am " + age + " years old!");
19 }
20
21 @Override
22 public void birthday() {
23 age++;
24 System.out.println("My age is now " + age);
25 }
26}

Here, the interface defines the behavior of our class. We do not require knowledge of the object's variables or any additional details; we solely have access to a straightforward API provided by the interface, which fulfills our requirements. In this instance, we only necessitate calling the greet() and birthday() methods, and do not require any further information about the object itself.

Summary

Programming abstraction involves simplifying intricate systems by focusing on essential features and concealing unnecessary details that are not needed. This technique includes creating abstract models or representations of real-world objects or systems in code that can be used to construct more complex software. Abstraction offers programmers the ability to develop reusable code and modify complex systems, making it simpler to maintain, update, and debug software over time. By using abstraction, developers can conceal implementation details and reduce cognitive load, allowing them to focus solely on what they need to use and know. However, there are drawbacks to using abstraction. As we add more layers, the code can become increasingly mysterious, which isn't always desirable because developers want to have control over what they build and use. Another disadvantage of abstraction is that it can come at the expense of performance, as additional layers of abstraction can result in computational overhead. This is concerning in systems with tight performance requirements, such as real-time applications or high-throughput data processing.

Resources