The Cost Of Abstraction

The Cost Of Abstraction

 

Just because something is generally good does not mean it comes for free. Abstraction is generally a good thing. It’s so good; it’s a concept in Object-Oriented Programming (OO). 

But Abstraction comes with a cost. And even though Abstraction is by and large a good thing, it is worth being aware of the cost.

This cost is a loss in understandability. With Abstraction in our code, we will no longer know exactly how our program works.

Consider the following CustomerController class:

  public class CustomerController
  {
     private SqlServerDbAccess DbAccess { get; set; }

     public CustomerController()
     {
        DbAccess = new SqlServerDbAccess();
     }

     // ...
  }

There is something nice about this code. A programmer knows precisely what type DbAccess is. They would be able to navigate directly to the SqlServerDbAccess class and see how it works. That’s a high-level of concreteness for you. 

Let’s make CustomerController more abstract:

  public class CustomerController
  {
     private IDbAccess DbAccess { get; set; }

     public CustomerController(IDbAccess dbAccess)
     {
        DbAccess = dbAccess;
     }

     // ...
  }

With a loss in concreteness, we have also lost how DbAccess works. We can look at the declaration of IDbAccess to see what it does, but we won’t know until runtime what type it is and how it works.

Another example. I’ve got a TransactionsGetUseCase class, and it has this constructor:

When I want to see the implementation of the parameter ITransactionProviderFactory, my IDE shows me these two options:

The ITransactionProviderFactory reference could be either one. My IDE doesn’t know which implementation one I want.

OK, Abstraction necessarily leads to a reduction in being able to follow a program in precise detail.

OK, I’ve been playing Devil’s Advocate.

We need Abstraction—the right amount of it. 

When we create fully concrete applications, we lose all flexibility. It likely will take much effort on our part to make changes to such applications. Abstraction makes our programs modular and pluggable. We should gladly pay a slight reduction in our knowledge of how precisely a program functions to gain the significant advantages of modularity. 

When we couple our CustomerController to SqlServerDbAccess, we are stuck with SQL Server data access. That’s how concreteness works; it is devoid of flexibility. 

Furthermore, Abstraction allows us to unit test our code. How are we meant to unit test CustomerController when the constructor is creating an instance of SqlServerDbAccess? Well, we can’t; not without actually having the unit test trying to connect to a SQL Server database. And if we do that it’s not a unit test but an integration test. 

The abstract version of CustomerController does not have this dependency on SqlServerDbAccess and can be unit tested with ease.

To sum up, Abstraction is so useful because it allows us to design pluggable architectures. However, with an increase in Abstraction, there is an inevitable loss in understandability of how our application works. We must find the right balance between Abstraction and Concreteness. 

0 replies

Leave a Reply

Want to join the discussion?
Feel free to contribute!

Leave a Reply