Software Development: Science or Engineering?

In the first section of his essay Engineering and Star Trek Michael Wong does a pretty good job of pointing out the differences between science and engineering (after that he moves on to rant about Star Trek’s engineering blunders, but we shall not concern ourselves with that here).

Michael writes:

Engineering is more difficult than science in some ways, and it is also easier in some ways. Scientists need to understand their theories in much more detail than engineers do, and they require stronger abstract thinking skills. They must be able to explain the principles behind every idea, and they don’t have the luxury of relying on “rules of thumb” and empirical correlations when in doubt. While engineers can concentrate on the applications of a theory, scientists must study its derivation from first principles. However, scientists do catch a break in three crucial areas: time, complexity, and consequence.

Time because of the temporal constraints placed upon projects: the competition can’t be allowed to finish it earlier, or a solution is needed urgently for an already running projects.

Complexity because of the environment the project is running in. The operating system’s peculiarities must be adhered to, interfaces to other vendor’s software must be handled, emergencies (hardware failure, malicious software) taken into account.

Consequence because the consequences of failure are often more dire. Computer science is the most important field today, pervading everything from hospitals to household devices. Well, you don’t need to imagine what will happen if one of those systems has a serious failure.

Enter Edsger Dijkstra. The famous computer scientist’s writing On the cruelty of really teaching computing science scorns the engineering labeling of all software development issues:

As economics is known as “The Miserable Science”, software engineering should be known as “The Doomed Discipline”, doomed because it cannot even approach its goal since its goal is self-contradictory.

It wouldn’t be so bad if it would limit itself on issues of Computer Science, but that’s not the case. And he doesn’t seem to be exactly rational about it, as can be seen in his usage of logical fallacies (biased sample, spotlight, appeal to ridicule), like in the following passage:

But it [the engineering label] is totally symbolic, as one of the US computer manufacturers proved a few years ago when it hired, one night, hundreds of new “software engineers” by the simple device of elevating all its programmers to that exalting rank. So much for that term.

There are many more such rhetorical devices all over the paper, and a commentary pointing them all out would probably be a good exercise. But since it’s obviously a polemic pamphlet, let us turn away from nitpicking and look at the guts of his arguments.

To begin with:

Unfathomed misunderstanding is further revealed by the term “software maintenance”, as a result of which many people continue to believe that programs –and even programming languages themselves– are subject to wear and tear. Your car needs maintenance too, doesn’t it? Famous is the story of the oil company that believed that its PASCAL programs did not last as long as its FORTRAN programs “because PASCAL was not maintained”.

My dear Edsger, programs are subject to wear and tear. If software necessary to run a program (e.g. compiler, interpreter, external library, operating system) or the software itself is not maintained, it will severe its ties with the future with time. Because the environment is not static (see “Complexity” above), a program needs to be changed in regular intervals to keep up with the changes in its surroundings.

Let’s get to the next:

[The programmer] has to derive that formula, he has to derive that program. We know of only one reliable way of doing that, viz. by means of symbol manipulation.

Who’s using a theorem prover to derive his latest database report program? Hands up. I am not; if I tried to do so, I will have a provably formally correct program at the end of the process. Unfortunately, a few months or years will have passed since I have begun, and the program’s environment has radically changed, and with it the assumptions that were used in the derivation of the program.

Now let us put the crown on our pamphlet and build an ivory tower by attacking “all soft sciences for which computing now acts as some sort of interdisciplinary haven”. I don’t know what to say in reply to that. Does he want to shut off all other disciplines from the usefulness of computer programs?

Let’s end the slaughtering here and see whether we can come to a sensible bottom line. Dijkstras paper is a good one, if read carefully: Computer Science is a vital part of good software development, and formal methods are a valuable tool one should not neglect. But let us not deny engineering, but let it have its place beside science, like it has in many other disciplines.

Simply put:

Good software engineering is a solid engineering discipline grown from the soil of computer science.

The design of programming languages

Only two weeks ago Larry Wall wrote a quite comprehensive paper featuring a list of common major decision points in programming language design.

Today I came across Kent Pitman’s paper Condition Handling in the Lisp Language Family from the year 2001 where he voices his personal experiences in the design of a programming language standard. The most interesting part is this:

“In my experience, much of language design is like this. We think we know how it will all come out, but we don’t always. Usage patterns are often surprising, as one learns if one is around long enough to design a language or two and then watch how expectations play out in reality over a course of years. So it’s a gamble. But the only way not to gamble is not to move ahead.

I once saw an interview on television with a font designer from Bitstream Inc. about how he conceptualized the process of font design. It is not about designing the shape of the letters, he explained, much to my initial surprise. Then he went on to explain that it was really about the shape of words. The font shapes play into that, but they are not, in themselves, the end goal. Programming language design is like that, too. It’s not about the semantics of individual operators, but about how those operators fit together to form sentences in programs.

Unlike the situation with fonts, where whole books can be viewed instantly in a new font to see how the design works, we don’t know in advance what sentences will be made in a programming language. We have to wait and see what people choose to write. Common Lisp took a step forward, and while we can quibble endlessly over whether any given design decision was right, the one design decision I’m most certain was right was to offer the community a rich set of capabilities that would empower them not only to write programs, but also to have a stake in future designs. Never again will I fear sending out e-mail to a design group asking for advice about what the semantics of HANDLER-BIND should be and finding that no one has an opinion! To me, that kind of progress, the evolution of a whole community’s understanding, is the best kind of progress of all.”

Kent Pitman, lead contributor of the ANSI Common Lisp Standard is a very competent advisor on Lisp matters and still greatly involved in the community. Quite often I’m amazed how much insight and effort was put by him and a bunch of other people into making Lisp a language very capable for Rapid Prototyping, Small Team Development (yeah, I made up that latter buzzword) and all the things that make software development a fun experience instead of a frustrating one.

Among those that instantly come to my mind are

  • the symbol data type
  • the condition system
  • the Common Lisp Object System (CLOS) and its Meta Object Protocol (MOP)
  • the reading and printing facilities
  • the type system
  • the garbage collector
  • the ability to use and mix the paradigms of imperative, functional, declarative and object-oriented programming

It is unfortunate that the standardization process has stopped in 1995. But it doesn’t really matter since it gave the Lisp community a solid base to build quasi-standards upon. This deters newbies, of course, but all mostly self-reliant programmers and those who are willing to ask smart questions on comp.lang.lisp happily make it. And this is the type of programmer who profits most from Common Lisp, anyway.

PHP array “functions”: a nightmare for functional programmers

Well, I used to think PHP itself was. But the language as a whole (no closures, no packages or namespaces, poor man’s single dispatch OO, could come up with a bunch of more things) is nothing compared to its low-level array API.

Walking an array on a low level, i.e. getting at the previous and next elements in natural array order, is done with the prev() and next() functions. The problem is that those only work as a function in that they return the corresponding array value ($val = next($array)). Besides that they act as procedures modifying internal array state. Read that again: those things have more side-effects than you can twist around in your brain, and their very core functionality relies on them.

Here’s some closely associated brain damage for you to witness:

$a = array(1,2);
reset($a); # make sure we're starting with a clean array pointer
var_dump(pos($a)); # integer, value 1, as expected
var_dump(prev($a)); # FALSE, to be expected
var_dump(next($a)); # FALSE!!

So the assertion that making one step backwards and one forward leaves you where you started is a no-go here.
Talk about common sense semantics…

And this is harmless in comparison, but still:

Note: You won’t be able to distinguish the end of an array from a boolean FALSE element. To properly traverse an array which may contain FALSE elements, see the each() function.

Oh, do I need to remind you they are at major version FIVE of their language?

String parsing with the LOOP facility

As part of a read macro I needed to parse strings. Lisp strings don’t have escapes except for double quotes (as they are string delimiters) and the backslash (which is the escape character).

Here’s what I came up with, a really fine example of Algol style code with three nested conditionals:

(defun read-lisp-string (stream)
  "Parse a Lisp string. Expects stream to point to the
  first character after the leading double quote."
  (coerce
    (loop for char = (read-char stream)
          with nbackslashes = 0
          with eos = nil
 
          if (char= char #\\)
            do (setq nbackslashes (+ nbackslashes 1))
            and if (and (evenp nbackslashes)
                              (not (equal nbackslashes 0)))
                collect char
                end
          else
            if (char/= char #\")
                do (setq nbackslashes 0)
                and collect char
            else
                if (oddp nbackslashes)
                    collect char
                else
                    do (setq eos t)
 
          until eos)
    'simple-string))

The most important thing I learned: although in all places you can read that there’s no accepted standard for the LOOP facility, the respective section of the spec is quite helpful in determining whether a certain clause is allowed at some place.

What type of coder are you?

Well, I don’t know.

But I can at least tell that I belong to the 20% minority.
Moreover, I’m a member of the bipolar faction, which also explains a lot of other things in my life.

What about you?

Web applications for the elite

Weblocks is a very impressive web framework for Common Lisp, and my experiences of hacking away with it a few days have produced quite encouraging results.

Imagine a world where you don’t have to keep track of or prevent the user from

  • hitting reload
  • opening multiple pages in his browser
  • using his back and forward buttons

Sounds good? You’d like to be there? Weblocks offers all this — and more, like automatic usage of AJAX requests if supported on the client side.

The only catch:
You need a firm grip on functional programming and a basic understanding of Lisp to use it, but learning Lisp pays off in any case, and functional programming does incredibly more so.
It helps to have experimented with Hunchentoot before.
So, from LAMP to Weblocks is probably a no-go.

Today I found another framework which has not crossed my way before that looks promising: It’s called and is apparently built on Scheme, so it makes use of continuations as well.