July 31, 2006

Doing Things Wrongly

Our DBA had a problem. He was trying to figure out the best way to populate a bridge table with the full set of keys from two source tables. The answer was to do a simple Cartesian product. It hadn’t occurred to him. The problem was that he had it classified as the wrong way to do things. Not surprising, I guess … this site describing such joins points out that Cartesian joins are “usually done by mistake.”

Be sure not to exclude things from your arsenal of solutions by classifying them as “the wrong way to do things.” Sometimes the wrong thing is precisely what you need.

July 30, 2006

Design and Ambiguity

Eide Neurolearnings has an article on “ambiguity” and how developing minds deal with it. I disagree with many of their implications (for instance, that the difficulty children have in dealing with ambiguity is a discrepancy between the development of the reasoning and communicating abilities), not to mention the very … err … ambiguous use of the term, “ambiguity” in each of the associated articles.

So I will limit myself to discussing ambiguity in brainstorming.

There’s no such thing.

Oh, fine, I’ll elaborate.

This referenced article describes the tolerance of ambiguity as “the ability to live in a universe where there are no right or wrong answers, where ideas or thoughts are vague and yet unformed.” These are two very different things. The former phrase is an assertion that, epistemologically, concepts have little or no relation to reality and, therefore, can not be used to determine truth or validity in relation to reality (alternatively, it could just be embracement of the same old tired subjective reality beliefs … yawn.) The latter phrase, on the other hand, is useful ... a statement that concepts can be incomplete. In other words, a statement of “insufficient data”.

What does this mean for us in a design situation … how do we minimize ambiguity, identify it, resolve it, and keep it from causing problems in our projects? (Note that this is not an exhaustive list … I don’t describe, for instance, the things that must be done in the process of mapping abstracts to concretes.)

  1. Thoroughly define your context.
  2. Identify constraints (typically concretes, so be aware of how these are reflected abstractly.)
  3. Take measures to know what you know about every concept (attributes, intrinsic behavior, relationships, classifications, and methods of interaction), both in terms of completeness and confidence.
  4. Take measures to know what you don’t know, both in terms of requirements to accomplish the specified goal as well as deficiencies implied by context, interaction, relationship, and      methods of implementation.
  5. Figure out if the things you don’t know are relevant to the individual step in the chain of reasoning.
  6. Figure out if a later reasoned step mitigates a lack of information in a former step.
  7. Describe the efforts necessary to resolve each deficiency.
  8. If you choose not to break up the brainstorming session in order to resolve the deficiencies, figure out what you think the conclusion will be, give it a degree of confidence, a      significance with regard to subsequent conclusions, and a description of risk to the entire solution if your conclusion is wrong.
  9. Figure out if you can design out the risk (i.e., if a deficiency in knowledge has two ways in which it can resolved, determine if you are able to implement your solution in such a way that either case can be handled).

Omniscience is a fantasy. Beware anyone who never says, "I don't know." Train anyone who acknowledges ignorance, but doesn't yet deal with it in a structured manner. Embrace anyone who can describe for you a solution that compensates for ambiguity. Fire anyone who says, "You can't know."

July 27, 2006

Programming: Language and Thought

Programming is a difficult art to do well. I don’t mean the high level design or the specification of implementation patterns to use, I mean the actual “let me type up the implementation of this single procedure” effort. The problem lies in the need to have both structured, repeatable, consistent patterns of consideration and thinking, while simultaneously having a set of mental processes that lend themselves to innovation and unconventional insight. There’s the added difficulty caused by the fact that programming is often iterative in nature … you might add the portions of the code here, expect there to be interaction over there, and have to come back here to change things around based on behavior and expectation there.

Setting up a template of things to consider doesn’t work for many reasons, not the least of which is that, for the template to be useful across the board, it would have to be so generic and abstract that the concrete specifics of how to use it in a particular circumstance would allow the programmer so much flexibility that he’d dismiss the template entirely (which he would be inclined to do, since a template of what to think about would be offensive to him and his expensive training). Besides, if you have a template of steps to consider, you allow yourself to be constrained by that template, and innovation suffers.

Frankly, there is no solution. However, there are things that can be done to improve the situation by nudging the programmer’s mind in such a way that he considers certain aspects as part of his normal (and possibly unique) programming manner. The key is language and its use.

Words are referents that point to concepts. When you use a word, you’re indicating to a person that they should consider aspects of the concept. Multiple words might refer to the same concept, but indicate that different aspects of the concept should be considered relevant (this is one of the reasons that accurate use of language is important to unambiguous communication.) The structure of the language can also indicate a particular contextual framework in which the referred concepts should be evaluated.

Similarly, if you force a programmer to consider the language he is to use, or the structure he is to use, you can nudge his thought processes in such a way that he considers a particular necessary aspect of coding that he might otherwise overlook. As such, the person responsible for establishing a company’s (or API) coding style must consider areas in which he can provide this nudge. I’ll provide a few examples (please note that these are _examples_, and I will not enter into a debate about whether my particular example is the right or wrong way to do things.)

Classes, in general, reflect a conceptual entity. Therefore, classes should be named with the noun or noun phrase part of speech. By doing so, the programmer is forced to envision the thing and its intended context. Not only does this cause the programmer to more thoroughly evaluate that context (project business processes) allowing the team to identify deficiencies in specification, and also allows him to identify a meaningful hierarchy of related concepts such that a class hierarchy can be defined, but it also makes it easier for him to keep a mental image of the entity being modeled in mind as the coding proceeds.

Properties and methods have their own requirements and naming styles that can lend themselves to better development style. I’ll address these in the comments if necessary, but otherwise I’ll leave it as an exercise to the reader.

The Microsoft Visual Studio environment allows a developer to construct code “regions”, which are just delimited areas of code identified by a common name (with the ability to collapse everything down to a single node identified by that name.) If the coding standards require regions based on the access type of a particular property or method (e.g., #region Protected Methods), that reminds and encourages the programmer to evaluate what access level is actually appropriate, since recommended practice requires that you use the most restrictive that is reasonable.

There are times when resources must be closed or explicitly released (in the case of interacting with unmanaged code or GDI objects, given a few Microsoft GDI leaks), but programmers will frequently forget to consider this. If your coding style always requires that every code block be put in a Try … Finally structure (given that the Finally block is usually where you want to do that kind of clean-up), then the programmer is reminded in every procedure that he should evaluate whether that kind of clean-up is necessary. You don’t want it to be a Try … Catch or Try … Catch … Finally block, because this would encourage the programmer to unnecessarily handle exceptions, and this is not recommended practice.

Keep these techniques in mind, and consider them when documenting your own coding standards guides. Comments of other suggestions welcome, of course.