TalentTuner
TalentTuner

Reputation: 17556

How to identify that code is over abstracted?

What should be the measures that should be used to identify that code is over abstracted and very hard to understand and what should be done to reduce over abstraction?

Upvotes: 18

Views: 10338

Answers (5)

Juh_
Juh_

Reputation: 15549

I completely agree with what @ArnisLapsa wrote:

"Simplicity over complexity, complexity over complicatedness"

And that

an abstraction is used to "de-level" those, from complicated to complex

(and from complex to simpler)

Also, as stated by @MartinHemmings a good abstraction is quite subjective because we don't all think the same way. And actually our way of thinking change with time. So Something that someone find simple might looks complex to others, and even become simpler with more experiences. Eg. A monadic operation is something trivial for functional programmer, but can be seriously confusing for others. Similarly, a design with mutable object communicating with each other can be natural for some and feel un-trackable for others.

That being said, I would like to add a couple of indicators. Note that this applies to abstractions used in code-base, not "paradigm abstraction" such as everything-is-a-function, or everything-is-designed-as-objects. So:

  • To the people it concerns, the abstraction should be conceptually simpler than other alternatives, without looking at the implementation. If you find that thinking of all possible cases is simpler that reasoning using the abstraction, then this abstraction is not suitable (for you)
  • Its implementation should reason only about the abstraction, not the specific cases that it will be used for. As soon as the abstraction implementation has parts made for specific cases, it indicates an "unfit" abstraction. And increasing generalization to cope with each new case, is going the wrong way (and tends to fall to the next issue).
  • A very common indicator of over-abstraction I have found (and actually fell for) are abstractions that represent more than what is needed, now. As much as possible, they should allow to do exactly what is required, but nothing more. For example, say you're thinking of, or already have, a "2d point" abstraction for which you can define many operators you need. Then you have another need that could really be a "4d point" similar to the 2d. Don't start to use a "Ndimensionnal point" abstraction, especially thinking that you might later need it. Maybe you'll never have anything else than 2 and 4d (because it stays as "a good idea" in the backlog forever) but instead some requirements pops to convert 4d points into pairs of 2d points. That's going to be hard to generalize to n-dimensions. So, each abstraction can be checked to cover and only cover the actual needs. In my point example, the complexity "n-dimensional" is actually only used to cope with the 2 and 4d cases (and the 4d might not even be used that much).
  • Finally, in a more global point of view, a code-base that has many not related abstractions, is an indicator that the dev team tends to abstract every little issues. So probably many of them are or became over-abstracted.

Upvotes: 3

John Hunt
John Hunt

Reputation: 4072

Download Magento and have a look at the code, read some documents on it and have a look at their ERD: http://www.magentocommerce.com/wiki/_media/doc/magento---sample_database_diagram.png?cache=cache

I'm not joking, this is over-abstraction.. trying to please everyone and cover every base is a terrible idea and makes life extremely difficult for everyone.

Upvotes: 4

Yttrill
Yttrill

Reputation: 4931

I will give an answer that will get a LOT of down votes!

If the code is written in an OO language .. it is necessarily heavily over-abstracted. The purer the language the worse the problem.

Abstraction should be used with great caution. If in doubt always use concrete data structures. (You can always abstract later, this is easier than de-abstraction :)

You must be very certain you have the right abstraction in your current context, and you must be very sure that concept will stand the test of change. Abstraction has a high price in performance of both the code and the coder.

Some weak tests for over-abstraction: if the data structure is a product type (struct in C) and the programmer has written get and set method for each field, they have utterly failed to provide any real abstraction, disabled operators like C increment, for no purpose, and simply not understood that the struct field names are already the abstract representation of a product. Duplicating and laming up the interface is not a good idea.

A good test for the product case is whether there exist any data invariants to maintain. For example a pair of integers representing a rational number is almost sufficient, there's little need for any abstraction because all pairs are valid except when the denominator is zero. However for performance reasons one may choose to maintain an invariant, typically the denominator is required to be greater than zero, and the numerator and denominator are relatively prime. To ensure the invariant, the product representation is encapsulated: the initial value protected by a constructor and methods constrained to maintain the invariant.

To fix code I recommend these steps:

  1. Document the representation invariants the abstraction is maintaining

  2. Remove the abstraction (methods) if you can't find strong invariants

  3. Rewrite code using the method to access the data directly.

This procedure only works for low level abstraction, i.e. abstraction of small values by classes.

Over abstraction at a higher level is much harder to deal with. Ideally you'd refactor the code repeatedly, checking to see after each step it continues to work. However this will be hard, and sometimes a major rewrite is required, rather than a refinement. It's probably not worth it unless the abstraction is so far off base it is not tenable to continue to maintain it.

Upvotes: 12

Arnis Lapsa
Arnis Lapsa

Reputation: 47637

"Simplicity over complexity, complexity over complicatedness"

So - there's a benefit to abstract something only if You are "de-leveling" complicatedness to complexity. Reasons to do that can vary: better modularity, better encapsulation etc.

Identifying over abstraction is a chicken and egg problem. In order to reduce over abstraction You need to understand actual reason behind code lines. That includes understanding idea of particular abstraction itself (in contrast to calling it over abstracted cause of lack of understanding). And that's not enough - You need to know a better, simpler solution to prove that it's over abstracted.

If You are looking for tool that could do it in Your place - look no more, only mind can reliably judge that.

Upvotes: 14

Martin Hennings
Martin Hennings

Reputation: 16866

Personally I would say that "What is the ideal level of abstraction?" is a subjective question.

I don't like code that uses a new line for every atomic operation, but I also don't like 10 nested operations within one line.

I like the use of recursive functions, but I don't appreciate recursion for the sole sake of recursion.

I like generics, but I don't like (nested) generic functions that e.g. use different code for each specific type that's expected...

It is a matter of personal opinion as well as common sense. Does this answer your question?

Upvotes: 2

Related Questions