Anyone who has programmed for a while knows that all code is not alike. There are important broad categories of code. I wish there were a generally agreed to categorization, but there doesn’t seem to be. Many years ago, there were these categories (from lesser to greater in terms of perceived expertise and prestige):
- Operator (your hands actually touched a physical computer!) – low status!
- Applications programmer (many variations here, from business analyst to debugging and maintenance). And even they are not all the same! While I was working in a COBOL shop, I discovered that there is an intense, sharp difference among COBOL programmers:
- Batch COBOL. There is no direct human interaction here.
- Interactive COBOL, the kind that paints the infamous “green screens.”
- Guess which is more prestigious?
- Systems programmer (these got the problems when the application programmers were stumped)
- Computer vendor employee (these people wrote the operating systems, compilers, and other tools that systems programmers “maintained = got blamed for” at user sites)
When I worked at a computer vendor, there were clear distinctions among those who were concerned with:
- The operating system kernel (and then there are the drivers, the people who deal with them have to suffer from hardware dependencies)
- The operating system utilities
- Compilers
- Database systems (“simple” file systems fell under quasi-core OS; add a serious index or mention “b-tree” and you moved here)
- Networks
These distinctions were necessary and real. The coding disciplines, received knowledge, experience, and so on were different enough for these things that people could really be good at one and not at another. Unlike in the dreaded and despised world of end users, there was no clear hierarchy. While the kernel guys felt themselves at the center of the world, as in some sense they were, there was no denying the fact that compilers involved all sorts of special knowledge, and this got really annoying once OS’s started getting written in languages requiring compilers.
I suspect there are other reality-based classifications of code. But for these purposes, I would like to break all programming into some categories that cut across these and others I have heard of:
- True algorithms
- Abstract realizations of generic functions
- Application and device specific definitions and logic
Algorithms
Algorithms are the blocks of code studied so well in Knuth’s multi-volume series, The Art of Computer Programming. They are things like sorting, searching, managing lists, etc. There are lots of other sources, but he focuses on the key factors for code that implements algorithms. In spite of the impression that may be given by his many volumes, there are a relatively small number of algorithms, and it is important that a relatively small number of people like Knuth study them intensely, understand everything about them, and make them available (I’ll gladly pay!) in standard, canonic, guaranteed implementations. Most of the metrics in this paper are not relevant to algorithms.
Why is this? Because, for most algorithms, we continue to value the amount of space they use and the amount of time they take to execute. In increasing numbers of business applications, sub-optimal algorithms could be used without ill effect, at least in some places. But if an optimal algorithm is available, why not use it? Why make life complicated (not to mention error-prone) by introducing two classes of algorithms, the optimal ones and the good-enough ones – what’s to gain?
The life and analysis of algorithms in practice is by no means complete. There are important advances to be made. But most algorithms are advanced by someone solving a previously unsolved problem (like Dijkstra and the shortest path) or by taking advantage of a newly altered constraint (disk memory is now much cheaper than it used to be, therefore we can reasonably do X, which was a terrible idea in the days of expensive disk). Because of their different goals (minimization of space and time within constraints), algorithms play by different rules than other programs.
Abstract generic functions
Abstract generic functions implement things useful to many applications, but not specific to any one of them. Application “frameworks” are a mother lode of such functions. The Rails framework in Ruby is a reasonable modern example.
Any programmer who has written a variety of programs knows what I’m talking about here, and has his own candidates for inclusion. This has its origins in the FORTRAN FORMAT statement from Paleolithic times. Major categories of software products have emerged that started as application-specific code, moved on to be abstract generic functions, and then finally hardened into products. CRM and Content Management systems are recent examples. However, software products as currently typically designed and delivered aren’t nearly as useful or flexible as unified collections of abstract generic functions. The closest thing we have is application frameworks.
Application-specific definitions and logic
This is where everything else goes. This is the code and meta-data that makes your application your application, different from others.
Even this can and should be broken into layers of generality! For example, there should be one place for the common aspects of your UI design, and one place that defines what is unique to each particular interface.
The important thing is that, to the largest extent possible, you are mostly selecting and marshaling the general mechanisms available, and making them particular to the problem at hand.
Of course, your problem may have some highly unique elements. These elements may involve writing some serious code. The code may resemble in depth and complexity that of abstract generic functions. But you’d better just write it to solve the problem at hand, and leave generalization to another day.
Comments