Monday, October 22, 2007

peeve no. 251 is equating programming and art

I think I understand. Someone can appreciate art by contemplating a work's brilliant juxtaposition of shapes or colors, or by admiring the high level of craftsmanship, or by projecting his or her own reactions onto it (hence, art appreciation has a subjective aspect). Similarly, someone can appreciate code by contemplating its achievement of minimal complexity through a brilliant combination of simpler elements, or by admiring the high level of knowledge and skill applied to it, or by reacting to the symmetric use of whitespace.

Oh, right. The visual distribution of whitespace is entirely beside the point in code appreciation. Know why?

Code has a specific reason to exist. It has a purpose. (When the sentient programs in Matrix Reloaded, whether agents or exiles or Smith, talk about purpose, they're showing a laudable degree of self-awareness.) It does something. It operates. It executes. Data isn't merely one of the concerns addressed by a particular piece of code; data is in a fundamental sense the only real concern. Every cruddy program in existence performs one or more of the universal tasks of creating, reading, updating, and deleting data. True, some programs may do no more than yank pieces of data from here and there, transform or summarize the pieces, and dump out a transitory result. However, what came out (a display screen, a printout) still differs significantly from the data that came in, so data creation has happened. Even games process data: the data is a singularly trivial but highly-lucrative stream resulting from the iteration of a loop of the abstract form "Game State += UI input".

The definite purpose of every snippet of programming code, data processing, is what separates it from art. There is no inherently common purpose of art. Well, besides being the expression of the artist's vision, but a work's success in fulfilling this purpose is necessarily a subjective judgment by the artist, and once the work is finished that purpose is as completed as it will ever be. (Remaking and revising a work to better express the artist's original vision is the creation of a new work. Hi, George Lucas!) This difference in essence between code and art underpins several important distinctions. Although comparing programming and art may be instructional, these are reasons why equating programming and art is not quite right.
  • Primarily, programming is objective in a way that art isn't. Code has a specific purpose, which is processing data in a specific way. If a machine executes the code, but the data processing has not occurred correctly, the cause may be complicated and subtle (or so simple as to be overlooked), but something has undeniably failed. The purpose(s) of art are not so explicit and obvious, which means the failure(s) of an artwork are not so explicit and obvious. Horrible art may be "ugly", but horrible programming is borked.
  • For computers and code to feasibly/acceptably automate data processing, the objectively-evaluated accuracy just described must be consistently reliable. Therefore, computers and code must be deterministic. Parts of the data processing may be "indeterminate", like a string of pseudo-random numbers, or parts of the execution order itself may be indeterminate, like a set of parallel threads, but taken as a whole, the guaranteeing of accurate results implies determinism. Determinism, in turn, implies that inaccuracies do not "happen spontaneously", but have a root cause. The root cause in any particular situation may in fact be an erratic one, due to flaky memory for instance, but nevertheless the inaccuracy has a determinate cause. More to the point, if the programming is at fault, then this cause is known as a bug. Since all parts of the code are intertwined, and code, while it can be fault-tolerant, certainly isn't self-conscious and self-correcting (that's what programmers are for!), it follows that, speaking in general of code from the metaphor of a "black box", an inaccuracy could potentially be due to any part of the code. When the code as a whole can objectively fail, then every part of the code can objectively fail, too. An artwork is much more forgiving of its parts. Critics of any art form will comment that a work had some "regrettable qualities", but "by and large, succeeded". Programming has a much more menacing antagonist, the bug, and no matter how artistically or aesthetically correct the code is, one lil' bug means the code, at least under some conditions, is fatally flawed.
  • Continuing the bug discussion, the dirty little non-secret of programming is that, with few exceptions, no sufficiently complex code is entered without mistakes the first time, or the second time, or the third time. The wizards and geniuses of programming confess to regularly forgetting about some minor detail (is it array.length or array.length()?), and mistyping identifiers (what was the name of the variable for the number of combinations?). Speaking out of my ignorance and lack of artistic talent, the mental exertion/concentration required to perfectly perform the concrete actions of programming--obeying syntax, tracking semantics, remembering the general flow of the design/algorithm, error-free typing--outweighs the similar demand on the artist. In response, helpful programming-oriented editors arose, built for relieving some of the strain with auto-completion and other code assists.
  • Moreover, bugs in the manual transcription of a design/algorithm are some of the easier ones to catch. Programming is an excellent illustration of how easy it is to gingerly proceed through a canned series of steps, appearing to conscientiously complete each one, and end up creating complete horsepucky (or, if you prefer, bulldooky). As people swiftly discover after exiting school, the unwritten assumptions and the errors in reasoning about the data domain can yield code which processes the wrong data, processes data irrelevant to the user's needs, processes the data insufficiently for easy use. Consequently, transactions with programming clients differ from transactions with art patrons. The art patron (editor, supervisor, commissioning official) has a set of loosely-defined outlines/parameters for the artist to follow, and the art should be acceptable if it is within those boundaries. The programming client quite likely also has a set of loosely-defined requirements, but, because code is not art, code is strictly defined: this input transformed to that output. Loose definitions of the purpose are insufficient for code because loose results from code are insufficient. Take a stupid example, a crayon illustration. Is the purpose of "calculating sales tax" met by code which assumes a tax rate for California? Yes--but just if the input and output is Californian! A programming client who loosely states he or she wants code that "calculates sales tax", receives that code, and runs it in Wyoming, is not happy.
  • A greater amount of precision distinguishes programming requirements from artistic. Time does, as well. Artworks can be unchanging, and remain sublime expressions of the human spirit--this "requirement" of the artwork doesn't shift. In contrast, as the turn of the century reminded everyone, a shift in requirements around pristine code can make it useless. "Functioning as designed" turns to "bug". It's a cascading effect: the world changes, the data that represents the world changes, the processing of the data changes, the code that implements the data processing changes. No doubt, certain codebases are long-lived, but only by embodying the most general of concepts and nurturing areas of change. emacs continues both on account of meeting the continuing need to edit text and supporting arbitrary extensions.
All code has a data processing purpose. When the code executes but its purpose (the original need that motivated its creation) has not been met, it has failed. If the failure lies somehow with the code, it could be in the code, like a typo, in the design/algorithm, like an unconsidered case of atypical data, or in the code's very requirements, like a property missing from the data model. Over time, the code must change to better meet its purpose, and react to new bugs. (The "bug" may be a change in requirements, like "we're switching platforms, rewrite so it can run exactly the same!")

The practical conclusion is that the degree of beauty exhibited by code, as appreciated by discriminating programmers, is beside the point if it doesn't imply fewer short-term and long-term bugs. Evaluating and debating code prettiness is not something programmers need to do in order to have substantive discussions about software development. Why is using a popular, well-supported framework likely better than making your own? Yours probably has bugs you don't know about yet. Why is code modularization good? It cuts down duplication, enabling easier and more effective bug fixes. Why is uncluttered syntax good? It affords the programmer more time and attention for the subtler bugs of analysis and design. Why is increasing development agility (whether or not ye gods have deigned you Agile-Approved) good? It minimizes the possibilities for bugs to creep in. Why is understandable code good? It makes the tasks of finding and fixing bugs more productive later.

Don't show and tell me how shiny my code will be, thanks to your silver bullet. Show and tell me how bug-free, how effortlessly correct my code will be, thanks to your silver bullet. I am not an artist.

No comments:

Post a Comment