The process of taking away or removing characteristics from something in order to reduce it to a set of essential characteristics
The idea behind abstraction is to hide complexity - we try to hide away all the complex details. For example, you may want to persist some type of data - that’s the high level view of what we want to be able to do. Whether we’re storing that in a text file, a database or what not, we shouldn’t really care, that’s someone else’s problem, that is an implementation detail - one less thing to worry about, all we know is that our data will be persisted somewhere. We don’t really care where or how.
The main problem with abstraction is when it’s done wrong is that it becomes a lot more damaging than helpful the longer it’s around, and other parts of the codebase or separate services become dependant on our bad abstraction.
Perfection is Achieved Not When There Is Nothing More to Add, But When There Is Nothing Left to Take Away
Antoine de Saint-Exupery
When thinking of an abstraction, don’t try to think of all possible situations that someone may want to do - instead, keep the scope small, and let it naturally grow as required.
In the case of interfaces, a few tips when designing:
- A property or non-void method cannot be derived from another non-void method or property - this just makes it redundant
- Make sure that the interface defines the behaviour of a specific concept e.g. if you’re defining a concept for reading and writing customer information, don’t put anything about a product in there.
- Names of what you can do make sense - naming things can be difficult, but try to be descriptive - non-descriptive names just make the interface leaky as you would always have to look up what it does.
- Get rid of everything you don’t need right now - keep it simple - it’s much easier to add things later in the future than removing.
Any intelligent fool can make things bigger, more complex, and more violent. It takes a touch of genius — and a lot of courage — to move in the opposite direction.
Joel Spolsky also once wrote about leaky abstractions, whereby, in order to work effectively (correctly?) with a certain abstraction that abstracts away the complexity of particular actions you want to take, you have to learn the internals. This is something that isn’t completely 100% unavoidable when it comes to edge case bugs or when you’re trying to optimise for speed and/or memory usage.
Aim for simplicity, only make something as complex as it absolutely needs to be.