The right level of abstraction in coding helps your code become easier to read/understand and bringing consistency and a logical design to your code. When you see the right level of abstraction used it intuitively seems right.
Getting the correct level of abstraction is creating a consistent level of design in your code.
Understanding Abstraction
Understanding Abstractions in code design is difficult and takes repeated attempts at learning the concepts. It’s worth persevering with because abstractions play a key role in code design and two important concepts of good code design
- Encapsulate what varies
- Code to an interface not a concrete class
To get started with abstraction in code design and understand the benefits read my blog post below
Why understanding abstractions can help you write better code
The right level of Abstraction
There are many articles/books which mention the concept of getting the level of abstraction right in your when designing code but not many of them explain the concept clearly.
To know if you understand something you should be able to explain it someone (or yourself) in simple terms don’t understand it well enough.
I found the concept of the right level of abstraction difficult to understand until I read a great section on exceptions in Code Complete 2. The chapter described defensive programming and exception handling. Below I will go through a similar example found in the book.
When you choose to pass an exception to the caller, make sure the exception’s level of abstraction is consistent with the routine interface’s abstraction
If I had a class called car with a method to return the engine size
Class Car{ Public GetEngineSize() throws ArrayTypeMismatchException }
Calculating the engine size if all the correct fields aren’t set the code throws an ArrayTypeMismatchException, so the code throws this error.
Now ask yourself the question, is this exception the right level of abstraction?
The calling code doesn’t need to know the detailed error about arrays or type conversion errors. Instead the calling code is more interested in data is not available.
The right level of abstraction would be improved with this error
Public GetEngineSize() throws CarDataNotAvailable
The calling function level of abstraction is concerned about the Car data, the original error message was at a lower level of detail. The lower level of detail is the correct error to the concrete car class which implements the code logic, it’s useful to know what type of exception is thrown because it might deal with different errors in different ways.
The interface is a higher level, Engine, wheels, colour. Classes using the interface are only interested in problems with the data, not the actual error which caused the problem.
The benefits of getting the right level of abstraction are
- The code feels right
- The design of the code is logical and easy to understand
- Consistency
Why should I care about the level of abstraction
Setting the right level of abstraction is one small part of the process of improving the design of your code to make it easier to maintain in the future.
Finding the right level of abstraction for your code is often done after the initial code has been written.
Creative writers have to edit their first draft, advice to writers is to give themselves permission to write a bad first draft.
Writing code is similar because the first draft of code is focused on getting the code working, delivering the required functionality. Designing good code is an emerging process, which I discuss in this blog post
Unit tests are a vital part of emerging code design
Developers should refactor their code after the initial draft. The initial draft usually gets the code to work (short term goal) further iterations should improve the code by
- simplify the code
- reduce complexity
- Improve readability
- Improve the naming of classes, methods and variables
- reduce coupling by creating new classes and methods
- Setting the right level of abstraction and putting code in the right place
Another similarity with writers emerges because hopefully we are removing unnecessary lines (and methods). In coding terms fewer lines of code means fewer lines of code to maintain, debug and read.
The refactoring and improving the design of the code is a stage often missed out by many developers. The code will still work the same so many developers don’t see the value of refactoring and improving the design of the code.
The code working as required is the initial requirement
Refactoring and improving the design fore fills the long term requirements of maintaining code once written, such as
- Reading/understanding the code
- Resusing code
- Easier to debug
- Easier to extend
- Reduces the effects of change on the code
If you miss out the refactoring stage you will soon end up creating legacy code and technical debt. Read the articles below for more information
Conclusion
Good development is as often making lots of small good choices and avoiding making mistakes. Each complex method/class you avoid writing should be replaced with something simple. Putting code in the right place and getting the level of abstraction correct is one of many small good design choices.
If you add put together lots of good code design choices you will end up with good code.
Filed under: Hosk CRM Dev, OO Design