Let's say we write a program called simple-application-1, which has straight forward logic.
Then we may write another program called slightly-complicated-application-2, which shares the logic with simple-application-1 at a more or less abstract level -- details vary but overall logic is the same.
Now as we start to write yet another program, complicated-application-3, we get lazy and would like to refactor the abstract logic out. After some struggle, we have --
- class abstract_logic
- simple app1, uses abstract_logic
- slightly complicated app2, uses abstract_logic
- complicated app3, uses abstract_logic
Now we have a problem. The abstract_logic is very difficult to comprehend on its own. Without putting the abstract logic in a concrete background, abstract logic become very complex.
Let's illustrate with an example. Say a simple app as "go to school"; the abstract logic is "go to ...". Go to where? As we trying to comprehend it at abstract level, we can't help but to imagine/enumerate all potential cases, from "go to school" to "go to the himalaya" and all the necessary preparations in between. That is complicated.
Of course the key is to put the abstract logic into a simple application background. So we look at the "simple app1", and we have trouble comprehend it as well because "simple app1" uses "abstract logic" and we haven't comprehended "abstract logic" yet.