Intellectual Control Levels

Code can be rated for its level of understandibility, or its intellectual control level. This can be used by a development team to self-rate its code. This is a simple process that allows management to get a quick rating of the amount of work left to bring a system to the ICL desired for shipment, by measuring the number of lines of code at different ICLs. It also keeps workers continually aware of the project's quality goals.

The rating system for the intellectual control level (ICL) of a class ranges from 1 to 10, where 10 has perfect intellectual control, and 1 has no intellectual control. This document gives some guidelines as to what code at different ICLs looks like.

ICL 1: spaghetti code

We've all heard the term, but few modern programmers have really seen this sort of really horrendous code. Certainly no one who could conceivably work in our group would be constitutionally capable of writing it. This sort of code is such a mess it's beyond the point of being quicker to write than something more structured, so it's useless even for demo purposes. Large code blocks are cut-and-pasted from one part of a module into another, even where it would have been faster to make a common subroutine of them; most of the program is concentrated into one mammoth subroutine, thousands of lines long, with dozens of global variables.

Even seeing a piece of code of this sort can shake a good programmer to his/her philosophical foundations. For those of us who take programming almost as a religion, this code can shake our faith. For how can there be a god in a world where such garbage is accepted by the same processor that runs your code? By all rights, after executing the first ten instructions the processor should burn out and the disk heads should grind into dust. Thankfully, such code does crash regularly, although not enough to shake off a creepy feeling that something's not right with the universe.

If the above seems hyperbolic to you, it means you're one of the lucky ones who's never seen such code; that's more and more common in this era of structured training from the ground up, where even BASIC has become a well-structured language.

On the other hand, while spaghetti code is disturbing, it can be educational to examine. Such code acts as link to our prehistoric programming ancestors, making it clear why structured and then object-oriented programming came about. All the issues of maintenance and quality that we discuss nowadays are magnified a hundred fold within these code-trilobytes: studying them can bring the problems we face in the context of low-defect code into clearer focus.

ICL 2: hack demo

This is the first ICL that one might write code to on purpose. This is used for code that must be written quickly, is expected to be full of bugs, and for which there is no intention of putting into a shippable product. In other words, for prototypes.

This code has quite a few global variables for outside communcations; usually all instance variables are made public to make it easier for everyone to be able to reach in and mess with each other's guts. Methods are overly large (sometimes very much so) and messy. Documentation? What's that?

Usually such code starts out at ICL 3 or higher, but as more features are jammed onto the original structure, more and more disorderliness is injected into the basic structure. After some point it starts rising like yeast; when the code has doubled or tripled in bulk it is about ready for retirement, as it becomes difficult to hold together even for demo purposes.

Production programmers perfect the art of holding yeasty code at ICL 3 even as more and more features are acquired, so that the demo can continue to grow long past the lifespan a novice coder could maintain. It's a special skill that involves continual rework and effort, to make each new code addition a slightly cleaner piece than deadline pressures would demand, and to go in for major unscheduled reworks to sustain the whole structure.

Although a much-repaired hack demo can be reworked into a shippable high-ICL product, usually it's more efficient to design and write the product from scratch at the higher ICL.

ICL 3: rough

This is the sort of code experienced programmers can turn out quickly. Some companies then do a lot of testing on it and ship the result. It's full of bugs, but the fundamental structure can be sort of sound.

That's the difference between this and ICL 2: it has some sort of underlying design, whereas ICL 2 modules just agglomerate haphazardly. The code may be buggy, the modules overlarge, and the design messy, but at least there is a design.

Although code at this ICL is sometimes documented (usually by management edict), it doesn't really make a lot of sense to do so, because the code is sort of half-baked and changes a lot. The design is often moving around semi-fluidly so the doc invariably ends up out of date shortly after it is written. Such doc is worse than nothing, as it is actively misleading, as well as having taken valuable time to produce.

Another characteristic of ICL 3 code is that some of the hard decisions are put off until later, greatly speeding up development times. For instance, error handling is usually incomplete or nonexistent, difficult features work only partially, and so forth. This sort of ICL 3 code can be particularly expensive to improve, since the author purposely left the hardest parts for later. This is something to be aware of, and in general one should try to do a mix of easy and hard parts together at each stage of development of code that is intended to eventually become shippable, so as to avoid scheduling surprises where the last 10% of the project takes 50% of the time.

ICL 4: clean

Once the underlying structure settles down and the programmer gets a chance to polish up some of the rough edges, it reaches a stage that many programmers consider "clean" or "shippable".

The modules are midsized, and a casual observer can often figure out approximately what's going on, after working at it a bit. And the original programmer is able to come back to it after potentially years of absence and fix up a few bugs, since the undocumented structure is pretty clear in his/her mind.

Of course, the code is by no means bug free, and it is probably easier for new maintainers other than the original author to rewrite all or some of it when a major change is needed. Still, for many this is the epitome of the development art; in fact many don't believe code can be much better than this.

ICL 5: documented

It's possible to improve slightly on ICL 4 code, at some expense, by adding documentation. This doesn't do anything about the remaining bugs, but can help maintenance programmers quite a bit. It can even help the original author after some time has passed.

I'm not talking here about the little comments that go inside the routines, showing why some tricky code was done that way, or documenting a bug in the OS call being used. That sort of doc was a part of ICL 4. Here we're talking about something written down to convey to others the structure that the original author has in his/her head. Usually this manifests as a comment block at the top of each class definition and perhaps at the top of each method. Nothing fancy, just a quick road map so that newcomers can navigate through the multi-class intricacies of the code.

ICL 6: specified

This is the first step into new territory for most programmers; the attempt to make documentation that helps in reducing bugs, rather than just in describing what a module does. We'll call this more advanced form of documentation a specification, or spec.

One of the goals of a good spec is completeness. A complete spec means that a user of this object need not ever look at the code, but only at the object's spec. The idea is to break the infinite recursion that can happen when one tries to understand method A, which requires understanding method B, which requires understanding method C, and so on. A complete spec for method B, done without reference to the methods used internally, breaks the cycle and makes intellectual control of A possible.

See the discussion of specifications in the Intellectual Control document for more details.

The only way to decide if code is at ICL 6 is to decide whether one gets a feeling that the spec is really complete. There's really little way to tell for sure until ICL 7 but one gets a sense for what goes into a complete spec after a while.

In practice ICL 6 and 7 are inextricably intertwined, because making a good spec invariably involves writing the code in a very simple, understandable form. Complex code is unspecable; even seemingly reasonably-simple code can be unspecable. So the spec can't be written first, and then the code adjusted to match; usually it's a back-and-forth of tucking in the code here, streamlining the spec there. With that way of looking at it, ICL 6 is where this process is most of the way through but isn't done yet. It is a requirement that ICL 6 code have no side effects though, the spec must clearly "surround" the code to that extent, even if it can't really control it.

ICL 7: provable

It's not enough for a spec to be complete; the underlying code must also be correct. A good spec enables a reviewer to compare the code against the spec to such a degree that correctness of the code is provable, in a mathematical sense. This means that an infinitely smart reviewer could theoretically take just the spec, the code, and the specs of any routines the code makes use of, and could state with certainty that the code does or does not implement the spec.

At ICL 7, code can be seen to be provable: it has no side effects, the methods are reasonably small, and a matching from the spec to the code is there. However, it might be a strain for a finitely smart reviewer to prove that the code is correct. There might well be just too much going on for one person to grasp all at once. In a way, it's a veneer of provability without the meat.

ICL 8: obviously correct

Since human reviewers aren't infinitely smart, "provable" as we defined it above isn't all that helpful to use. It may be provable, but we're not smart enough to do it.

The next step is to have code that is "obviously" correct. This means that it is not only provable, but that any coder can prove it. To verify this, code must be so easy, so transparent, and so obviously correct that the reviewer has no doubts. This means that an implementation must be directly mappable to the spec, in small chunks of 3 lines or so to implement one line of spec.

Obviously correct doesn't mean quickly obviously correct. It may still take a while to do all the checking needed. Obviously correct just means that if one takes the time to check everything, one can convince oneself that all the pieces involved have been checked and that the way they fit together has been checked, so therefore everything's correct.

To make it practical to write the typical 20-line methods while gaining the advantages of 3-line chunks for obvious correctness, one can use a intramethod specs.

ICL 9: globally proven

This is the same as ICL 8, but where all modules the code depends on are also fully specified. To achieve ICL 9, all modules used by this code are at ICL 7 themselves, and have had their specs checked against this module's. This is the first level where the author can truly say that a module is absolutely correct.

ICL 10: certified

Once ICL 9 code has been inspected by at least 2 non-author reviewers, and any discovered deficiencies repaired, the code is certified. This just means that the author thinks it's correct and several other people agree.
Substantive changes:
    March 25, 1996: created.
    April 10, 1996: modified.
Copyright © 1996, Steve Colwell, All Rights Reserved
Home page