Modern software orthodoxy endorses the notion of collections of code that are separated by high walls. Object-oriented thinking codifies the supposed virtue of data hiding, and keeping all the code that works on a particular block of data (a class) behind a wall. Everyone seems to like the idea of components; people will talk in terms of assembling applications out of component building blocks (when has this ever happened except in seminar rooms?). Finally layers or tiers are supposed to introduce discipline to an application. The idea is you have the user interface (top) tier; then you have the application or business logic layer; and finally you have the database layer. Frequently, these are designed and built by separate groups, each a specialist in its domain – do you really want those superficial, flashy, image-obsessed UI people messing around with your transaction data – do you??? Of course not. But you also don’t want the groups to “hold each other up,” so the idea of having the layers be strictly separated so the UI people can do their thing without being held up by the others.
This is the theory. Lots of people practice it, or at least say they do. If you’ve never experienced anything else, it makes sense. Just the other day I met a software company chief scientist, a PhD in something or other, who explained to me that they were converting some scripts from PERL to java because java was a “real” language, and the scripting languages – all of them! – were not. I didn’t get a real explanation of why this was so; he took it as self-evident to all educated and reasonable people that it was, and by questioning it I really tried his patience, since I was apparently uneducated and unreasonable…
Components, layers, microservices and objects can be good things in limited circumstances, but it’s really, really important to see that if you accept that the prime measure of goodness of a piece of software is occamality for the reasons already discussed, in general, components, objects and layers reduce occamality to the extent they are applied.
The core problem with these things is that they result in multiple definitions of what amounts to the same data. The theory actually encourages this. Take a simple data element such as “account number.” In any program involving accounts, this piece of data will be all over the place. If you’ve got layers, it will be in all of them, because surely it will appear on screens, business logic and the database. If you’ve got objects, it will be in the interfaces and internal implementation of many of them – think, for example, of “account master” and “transaction.” If you think you’re being clever and have built yourself a message passing architecture, it will be in the message definitions – lots of them.
Naturally, you assume and hope that the definition of account number doesn’t change, and in most cases it won’t, in which case the wild redundancy won’t hurt you much. But problems come most often from things you didn’t think about – what happens if there’s a merger, and suddenly there are a whole set of accounts you’d like to bring into your software, and the new account number definitions are totally incompatible. What if they’re bigger and there’s no way to cram them into the existing scheme? You desperately cast around for translation schemes, but in the end you accept the inevitable: you’re hosed.
Now think about this: what if there was a central place where everything you know about account number was defined? Suppose the central place had everything that all the layers needed, for example label for the UI and foreign key relationships for the database. You could go to this single place and take care of most of the account number issues. I assume the program isn’t perfectly Occamal, and there are a few other places you have to go for everything to work. So what? You’re way better off than you otherwise would be.
The painful, anti-orthodox but blindly obvious conclusion is this:
- Each “layer” you put into your software increases its complexity and time to construct, and increases the time and risk to make changes to it.
- The more you use classes and other forms of object-orientation in your code, the more redundancy you introduce, and thus the harder you make your code to construct and change.
- You may think – before you’ve had lots of experience – that the data hiding of classes increases the “componentization” of your code, and thus makes it easier to change without trouble. Sadly, your thinking on this subject needs revision. Parameters and calls weave your objects together and make them do useful things, and the greater their interaction, the greater the redundancy.
There will always be people who love components, objects and the rest, just like there will always be people who insist on having half a dozen gin-on-the-rocks before supper to whet their appetites. Words don't work. Logic is irrelevant. They should stay in university or wallow around in some giant software bureaucracy where they'll have plenty of company.
Comments