Anyway, I finally had a chance to read Knuth's "Computer Programming as Art" speech given in 1974 (at his acceptance of the Turing award). He gives some interesting perspective on the history of "art" (where the word art was traditionally used as a counterpoint to science the way we use the word engineering now). He was also amused to find that scientists have been trying to get rid of the "art" in their fields for hundreds of years. From the preface to a textbook on mineralogy,
"Previous to the year 1780, mineralogy, though tolerably understood by many as an Art, could scarce be deemed a Science."It looks like he was struggling with the same questions we were in January when we tried to identify "beauty" in software.
My feeling is that when we prepare a program, it can be like composing poetry or music; as Andrei Ershov has said, programming can give us both intellectual and emotional satisfaction, because it is a real achievement to master complexity and to establish a system of consistent rules.He ended up with this list of general "goodness" for computer programs:
Some programs are elegant, some are exquisite, some are sparkling. My claim is that it is possible to write grand programs, noble programs, truly magnificent ones!
While we have basically ceded the desktop as a hopeless land of bloatware, there still are plenty of domains where resources are still tight, and programmers have to be careful. From cell phones, to PDAs, to microwave ovens; small microcontrollers are being put to work every day with limited CPU cycles, memory and IO capabilities. Perhaps this is one reason why Java hasn't been a smash hit on portable devices: its style of programming (and VM itself) lead to decadence in resource usage. Programmers writing in Java don't think of the CPU costs or memory fragmentation resulting from the use of invariant objects and explicit assignments, they just plow right ahead creating and destroying hundreds of objects as they go about their task.
While I tend to go a little overboard, there are certain areas where the harder path should be taken up front (this is not premature optimization). For instance I have a template engine for a UI engine I am writing. At start up the app loads all of the assets into memory, so it can shoot it down the channel when needed. For templates, I process the file at loading, breaking it up into text blocks and variable names, so that macro expansion would just be a matter of going through all the pieces, putting the text blocks and looking up the variables. Another engineer on this project, when faced with the same problem just wrote a look running
strstr() on the source text and doing string substitutions. His approach words, but I feel mine is the more elegant solution, and it was not that difficult or complicated to implement. Moreover it is a routine/module I will carry forward with me into the future and can apply to other solutions, where the
strstr() solution is just throwaway.
Knuth's turing award lecture (PDF 750k scanned)