Hello Winston,
thanks for your reply!
Reading your comment, I wished that I had read something like that when I was first confronted with JEE because it explains the "why" very clearly.
However, the problem isn't so much that I don't understand the need for this "abstracted" approach in certain cases. Unfortunately, this awareness does not make it any easier to deal with. Though I can certainly learn things such as OO - I cannot change how I think and function; what my strong points are and my not-so-strong points. That's part of who I am.
Winston Gutkowski wrote:This is entirely at odds with the bottom-up approach, which is all about understanding how things work, and you do need to rewire your brain a bit to be able to deal with problems in terms of objects rather than procedures.
I did not find the switch from "procedural" to "object oriented" all that difficult to make. I admit that I still feel a bit inclined to think in procedural terms, but I can certainly think in OO terms.
This is not the problem. I'll try to clarify it a bit more.
Last weekend I found a
blog post titled "Whatever happened to programming?" by Mike Taylor which
exactly describes what I'm trying to say.
(I first took some quotes from that post, but because I ended up quoting practically the whole thing I figured that the link would do just as well)
His point comes down to this: like me, he has the experience that the largest part of modern software development is an entirely different activity as it used to be.
"It's not creative; it's not making".
He then quoted Donald Knuth from from
Peter Siebel's book Coders at Work, who says largely the same thing: he's worried that the way programming goes these days isn't any fun, because
"it's just plugging in magic incantations". You don't get the chance to do anything new. Nowadays, the reward is to see results coming after a load of boring work, but
"the work didn't use to be boring".
Mike Taylor then talks about what he calls Phases 1 and 2 in development: Phase 1 being the initial, creative part
where it all comes together and Phase 2 the consolidation, documenting, writing
test cases etcetera. Phase 2 has always been part of development - that's not the problem. But today, practically everything is Phase 2.
In the
follow-up post he answers some commentators of the original post, further working out his ideas.
For one thing, he argues that using libraries in itself is not the problem. I agree: it is great to have a set of existing (and well-documented!) functionality that we can call on whenever we need it. As he says: the problem arises when ALL we do is glue libraries together.
He then shifts towards Frameworks, defining the point where the "don't call us, we'll call you" principle kicks in as
"not always, but often, marking the line where this stops being fun".
The Framework rant that follows goes into the supposed promises which Frameworks (usually) fail to fulfill. Now, as I said, this is not the gist of my point but I certainly recognise it. Here it is, slightly abbreviated:
Mike Taylor wrote:In my experience of programming with frameworks they do keep their promise of making things very quick and easy … so long as you do things in exactly the way the framework author intended.
The moment you go off-piste, everything goes Pete Tong, and what should be simple is suddenly not merely hard but often impossible. The framework goes out of its way to prevent you from doing what you intended. Strange side-effects hamper your efforts. The hook that you need to get the functionality you want isn’t there. Your attempt to work around it causes something else, apparently unrelated, to start misbehaving in subtle and unpredictable ways. Congratulations! You are now suffering from Framework Fever! Doctor Taylor prescribes a period of complete rest before building up your strength by working through the exercises in K&R.
(...)
You know the real problem with frameworks? They demo too well. Someone shows you their favourite framework and demonstrates how you can build 50% of your application in half an hour! Great! That other 50% can’t be hard, can it? But it turns out that what looked like 50% is actually 5%, and filling in the other 95% gets exponentially more difficult as you approach the 100% mark. Frameworks are great for building toys, and that fools us — again and again — into assuming they’re good for building products.
I'm aware that my topic may be rather ill-defined. Mike Taylor also seems to shift from "libraries" to "frameworks" - and I use the term JEE a lot, because that's where in my experience the trouble always occurs.
But it seems that the root cause of my uneasiness and frustration comes from a shift in my job from "mostly creative programming" to "mostly administering frameworks". Apart from how well those Frameworks actually perform; apart from
any considerations about the desirability of building and using large distributed systems based on Frameworks - I have noticed time and again that this calls for another sort of person.
I'm unhappy and frustrated because what I consider to be my best skills are almost never used.
Instead, there is ample call on skills that I don't have: the ability to absorb large amounts of high level information without understanding it technically. I'm supposed to work with things created by others - while I would rather have done that myself. It's not the sort of thing that I am good at, and it is all the more frustrating because I am continuously getting the message that what I am good at is not needed.
Should I get out of Java programming, or is there still a place somewhere where I can do what I'm good at?
Winston Gutkowski wrote:
The best analogy I can think of for abstraction like that (in fact, any type of abstraction) is driving a car:
1. In order to drive a car, you don't have to understand how the internal combustion engine works.
(...)
Funny
you should give this example, because I have, even as a seven-year-old girl,
always wanted to know how things work. Because I was also quite smart, I figured out how the television and radio and cars worked. By asking my parents - I even had a big notebook in which my father wrote down (and drew) all he explained to me, or, if they didn't know, I went to the library and read until I knew.
I have oftentimes wondered how people can work with things that they don't have any idea about how they work: I was, for instance, much surprised that not one of my 50 colleagues in my first IT job had ever taken a computer apart (and put it back together again). They neither knew nor cared - and indeed as you say: they could nevertheless do their work. But I'm different. I want to know how things work, because otherwise all that I do is nothing but voodoo.
Magic incantations. Which is precisely the phrase that Donald Knuth uses
"it's just plugging in magic incantations".
There's nothing wrong with magic incantations as such - but surely not in something so inherently logical and rational as software development!
Winston Gutkowski wrote:
2. If every car had its own way of responding, learning how to drive would be awfully complicated.
So the abstraction is simple: You have either 2 or 3 pedals and a steering wheel; and they work the same way in every car that you get into. You'll also find the pedals in the same position whether you're driving on the left or the right, so your brain has less to remember and can concentrate on the business at hand, which is driving.
That said, if someone put you in the cockpit of a Formula one car, you'd probably want to run a lot of practise laps to familiarise yourself with the layout (not to mention the experience of 6G cornering).
Interesting point - but I think it only applies as long as you restrict yourself to one framework only, so that you are very familiar with it. In this case the argument would also apply to using a sufficiently high-level language: you don't need to know the exact instruction sets of different processors because they are abstracted (far) away behind the core elements of the language.
In practice however, the complexity of the abstraction layer far surpasses the complexity of whatever it encapsulates. And that's just one framework - but there are many! A typical JEE framework does not so much simplify the underlying language features - but it clusters them in pre-configured chunks. Because there are so many possible ways of assembling and configuring these chunks, the framework specs are hugely complex. Much more so than the language.
To think of an analogy that would demonstrate my point: take washing. The basic language would translate to a handful of basic elements: adding
water, draining, spinning, adding
soap, etcetera. The controls of such a very simple machine would be easy to understand and I would not find it very difficult to figure out a workflow that would result in clean laundry.
Now, someone thinks that this is all too much hassle: too procedural, too much error-prone, whatnot. So they develop an abstraction layer: the LaundryButler. The demo that comes with it involves setting a row of switches for laundry colour, shape, amount, location and exact fiber composition. Among others. And then the magic happens: the LaundryButler takes your laundry and processes it fully automatic.
Of course, when you really start using the thing, you need to go through the
LaundryButler Unleashed volume (1200 pages) that came with it in order to get it working for your specific household situation. The control panel resembles that of a Boeing-747.
The essence: while this LaundryButler may indeed work very well in a given situation, it requires a completely different sort of skill to get the damn thing working.
But that is only the beginning, because as these things go, LaundryButler is actively developed and you get an update every year, requiring you to change the whole configuration. And on top of that, there isn't just the LaundryButler - your mother has a
WashRobot (c); the neighbours to the left have a
Wash-O-Matic and the neighbours to the right a
Spic-and-Spantastic (c). They are all completely different in the way they operate - knowing one does not help you to understand another - rather the contrary.
It makes you wonder if it's worth all the hassle in the end, if you wouldn't have been better off with the simple low-level washing machine.
Winston Gutkowski wrote:On average, the human brain can handle 7 ± 2 things at once, so if you had to think about the order in which cylinders were firing, you'd be a lousy driver. Abstraction is a way of managing complexity.
Understanding how the internal combustion engine works is not the same thing as needing to be aware of the order in which the cylinders fire.
Still, I agree with
"Abstraction is a way of managing complexity". But I'm afraid that it's not that straightforward. It's rather that Abstraction replaces one kind of complexity with another kind. Instead of the low-level complexity of the programming language, you get the high-level complexity of the framework. As Mike Taylor also says:
"Frameworks demo too well". In the ideal situation, a framework does indeed work wonderfully well. But it is also my own experience that as soon as you try to use it in a real-world scenario, things can get very hairy, very quickly. And then the problem arises that it is never straightforward to find out how to make the framework do what you (or the customer) wanted - while, using the programming language it would have been trivial.
I have imagined a sort of visual representation of how this works. Imagine the whole field of possible programming situations as a rectangle. The vertical axis represents
depth - the intrinsic richness or complexity; the horizontal axis represents
width - the multitude, the amount of elements, the extent. In this view, a (3G) programming language is a narrow, high (deep) rectangle. It doesn't have many elements (narrow), but they can be combined in many subtle ways (depth). Applying a framework somehow translates depth into width: by creating a manifold of combinations of language elements. The intrinsic complexity is shallow, because you cannot combine Framework elements in the same way as language elements. Framework elements are not atomic like Language elements, but complex entities of their own. They are more or less given and can only be configured.
In both ways - programming language or framework - it is in essence possible to address all possible programming situations. The difference is that the cognitive labour required to arrive on a given point is very different. Using the programming language, one has to construct a pathway to access it. Using a framework, one has to look up the nearest solution, and tweak it until it fits.
Well, I hope it makes some sense