Sunday, December 19, 2010

Are you ready for another step?

The history of programming languages has introduced concepts over time. Most of these concepts add rigor to our programming most of these changes were accompanied by complaints and much gnashing of teeth from the "old school" programmers. The big changes were high-level languages, structured programming, and object-oriented programming.

The step to high level languages was perhaps the most traumatic, since it was the first. It saw the deprecation of assembly language and fine control of the program in exchange for the ability to write programs with little concern for memory layout and register assignment.

The step to structured programming was also controversial. The programming police took away our GOTO statement, that workhorse of flow control and limited us to sequential statements, if/then/else blocks, and while loops.

When we moved from structured programming to object-oriented programming, we had to learn a whole new "paradigm" (and how to spell and pronounce the word "paradigm"). We learned to organize our code into classes, to encapsulate our data, to build a class hierarchy, and to polymorphize our programs.

Funny thing about each of these steps: they built on the previous steps. Structured programming assumed the existence of high level languages. There was no (noticeable) movement for structured assembly language. Object-oriented programming assumed the tenets of structured programming. There was no GOTO in object-oriented programming languages, except for the C++ "goto" keyword which was offered up on the altar of backwards compatibility and only then with restrictions.

And now we are about to move from object-oriented programming to functional programming. Once again, the "old school" programmers will gnash their teeth and complain. (Of course, it will be a different bunch than the teeth-gnashers of the golden age of assembly language. The modern teeth-gnashers will be those who advocated for object-oriented programming two decades ago.) And once again we will move to the new thing and accept the new paradigm of programming.

Yet those shops which attempt to move up to the step of functional programming will find a challenge.

Here's the problem:

Many shops, and I suspect most shops, use only a small fraction of object-oriented programming concepts in their code. They have not learned object-oriented programming.

Big shops (and medium-size shops, and small shops) have adopted object-oriented languages (C++, Java, C#) but not adopted the mindset of object-oriented programming. Much of the code is procedural code, sliced into classes and methods. It is structured code, but not really object-oriented code.

Most programmers are writing not clean, object-oriented code, but FORTRAN. The old saying "I can write FORTRAN in any language" is true because the object-oriented languages allowed for the procedural constructs. (Mind you, the code is FORTRAN-77 and not FORTRAN IV or FORTRAN II, but FORTRAN and procedural it is.)

This model breaks when we move to functional languages. I suspect that one can write object-oriented code (and not pure functional code) in functional languages, but you cannot write procedural code in functional languages, just as you cannot write non-structured code in object-oriented languages. The syntax does not allow for it.

The shops that move to functional languages will find that their programmers have a very hard transition. They have been writing procedural code, and that technique will no longer work.

What is an IT shop to do? My recommendations:

First, develop better skills at object-oriented programming. This requires two levels of learning: one for individuals, and the second for the organization. Individuals must learn to use the full range of object-oriented programs. Organizations must learn to encourage object-oriented programming and must actively discourage the older, structured programming techniques.

Second, start developing skills in functional programming. If using a "plain" object-oriented programming language such as C++, build discipline in techniques of functional programming. My favorite is what I call "constructor-oriented" programming, in which you use immutable objects. All member variables are set in the constructor and do not allow methods to change any values. This exercise gives you experience with some of the notions in functional programming.

The transition to functional languages will occur, just as the transition to object-oriented languages occurred. The question is, do you want your shop to move to functional programming on your schedule, or on someone else's schedule? For if you make no plans and take no action, it will occur as the external world dictates.

Friday, December 17, 2010

Think like a programmer

From time to time, it behooves me to think about how I think.

This past week, I've been working on a legacy application. It consists of 20,000 lines of C++ code, written and modified by a number of people of varying talent. The code works -- mostly -- and it certainly compiles and runs. But the code is poorly organized, uses unclear names for functions and variables, and relies on the C preprocessor. Identifying the source of problems is a challenge. As I work on the code, I look at the coding style and the architecture. Both make me wince. I think to myself: "Programmers -- real programmers --don't think this way."

It's an arrogant position, and I'm not proud of the arrogance. The code was put together by people, some who are not professional programmers, doing their best. But the thought crosses my mind.

Cut to my other activity this week: reading about the Haskell programming language and the concepts behind functional programming. These concepts are as different from object-oriented programming as object-oriented programming was to procedural programming. In functional programming, the design is much more rigorous. The central organizational concepts are recursion and sets. The programs are hard to read -- for one who is accustomed to object-oriented code or the procedural-laden code that exists in many shops. Yet despite the strangeness, functional programming has elegance and a feeling of durability. As I look at programs written in Haskell, I think to myself: "Programmers -- real programmers -- don't think this way."

This is not the arrogant position I have with poorly structure code, but one of humility and frustration. I am disappointed with the programmers and the state of the craft. I covet the attributes of functional programming. I want programs to be elegant, readable, and reliable. I want programmers to have a high degree of rigor in their thinking.

In short, I want programmers to think not like programmers, but like mathematicians.

Monday, December 13, 2010

The importance of being significant

In engineering computations, we have the notion of "significant figures". This notion tells us how many digits of a number are accurate or "significant", and which digits should be ignored. This sounds worse than it really is; let me provide an example.

If I tell you that I have 100 dollars in my pocket, you will assume that I have *about* 100 dollars. I may have exactly 100 dollars, or I may have 95 or 102 or maybe even 120. My answer provides information to a nice round number, which is convenient for our conversation. (If I actually have $190 something more than $150, I should say "about 200 dollars", since that is the closer round number.) The phrase "100 dollars" is precise to the first digit (the '1' in '100') but not down to the last zero.

On the other hand, if I tell you that I have 100 dollars and 12 cents, then you can assume that I have indeed $100.12 and not something like $120 or $95. By specifying the 12 cents, I have provided an answer with more significant figures; five in the latter case, one in the former.

The number of significant figures is, well, significant. Or at least important. It's a factor in calculations that must be included for reliable results. There are rules for performing arithmetic with numbers, and significant figures tell us when we must stop adding digits of precision.

For example, the hypothetical town of Springfield has a population of 15,000. That number has two significant figures. If one person moves into Springfield, is the population now 15,001? The arithmetic we learned in elementary school says that it is, but that math assumes that the 15,000 population figure is precise to all places (five significant figures). In the real world, town populations are estimates (mostly because they change, but slowly enough that the estimate is still usable). The 15,000 figure is precise to two figures; it has limited precision.

When performing calculations with estimates or other numbers with limited precision, the rule is: you cannot increase precision. You have to keep to the original level of precision, or lose precision. (You cannot make numbers more precise than the original measurements, because that is creating fictional information.)

With a town estimate of 15,000 (two "sig-figs"), adding a person to the town yields an estimate of... 15,000. It's as if I told you that I had $100 in my pocket, and then I found a quarter and tucked it into my pocket. How much do I now have in my pocket? It's not $100.25, because that would increase the number of significant figures from one to five, and you cannot increase precision. We have to stick with one digit of precision, so I *still* have to report $100 in my pocket, despite my windfall.

In the engineering world, respecting the precision of the initial estimates is important for accurate estimates later in the calculations.

I haven't seen this concept carried over to the computer programming world. In programming languages, we have the ability to read and write integers and floating point numbers (and other data types). With integers, we often have the ability to specify the number of character positions for the number; for floating point, we can specify the number of digits and the number of decimal places. But the number of decimal places is not the same as the number of significant figures.

In my experience, I have seen no programming language or class library address this concept. (Perhaps someone has, if so please send info.) Knuth covers the concept in great detail in "The Art of Computer Programming" and explains how precision can be lost during computations. (If you want a scary read, go read that section of his work.)

There may be several reasons for our avoidance of significant figures:

It takes effort to compute. Using significant figures in calculations requires that we drag around additional information and perform additional adjustments on the raw results. This is a problem of computational power.

It requires additional I/O There is more effort to specify the significant figures on input (and to a lesser extent, output) This is an argument of language specification, numeric representation, and input/output capacity.

It reduces the image of authority associated with the computer In Western culture, the computer holds a place of authority of information. Studies have shown that people believe the data on computer printouts more readily data on than hand-written documents. This is an issue of psychology.

Some domains don't need it The banking industry, for example, uses numbers that are precise to a fixed decimal place. When you ask a bank for your balance, it responds with a number precise to the penny, not "about $100". This is in issue of the domain.

My thinking is that all of these arguments made sense in their day, but should be re-examined. We have the computational power and the parsing capabilities for accepting, tracking, and using significant figure information. While banking may be immune to significant figures (and perhaps that is only the accounting side of banking), many other domains need to track the precision of their data.

As for the psychological argument, there is no amount of technology, hardware, or language features that will change our thinking. It is up to us to think about our thinking and change it for the better.

Sunday, December 12, 2010

Simple or complex

Computers have been complex since the beginning. Computer users have a love/hate relationship with complexity.

We can add new features by adding a new layer onto an existing system, or expanding an existing layer within a system. Modifying an existing system can be difficult; adding a new layer can be fast and cheap. For example, the original Microsoft Windows was a DOS program that ran on PCs. Morphing DOS into Windows would have been a large effort (not just for development but also for sales and support to users who at the time were not convinced of the whole GUI idea) and a separate layer was the more effective path for Microsoft.

But adding layers is not without cost. The layers may not always mesh, with portions of lower layers bleeding through the upper layers. Each layer adds complexity to the system. Add enough layers, and the complexity starts to affect performance and the ability to make other changes.

The opposite of "complex" is "simple"; the opposite of "complexify" (if I may coin the word) is "simplify". But the two actions do not have equivalent effort. Where adding complexity is fast and cheap, simplifying a system is hard. One can add new features to a system; if users don't want them, they can ignore them. One has a harder time removing features from a system; if users want them they cannot ignore that the features are gone.

Complexity is not limited to PCs. Consumer goods, such as radios and televisions, were at one point complex devices. Radios had tubes that had to be replaced. TVs had tubes also, and lots of knobs for things like "horizontal control", "color", "hue", and "fine tuning". But those exposed elements of radio and TV internals were not benefits and not part of the desired product; they were artifacts of utility. We needed them to make the device work and give us our programming. They disappeared as soon as technically possible.

Automobiles had their share of complexity, with things like a "choke" and a pedal for the transmission. Some features have been removed, and others have been added. Cars are gaining complexity in the form of bluetooth interfaces to cell phones and built-in GPS systems.

Software is not immune to the effect of layers and complexity. Microsoft Windows was one example, but most systems expand through added layers. The trick to managing software is to manage not just the growth of features but to manage the reduction in complexity. Microsoft eventually merged Windows and DOS and Windows became an operating system in its own right. Microsoft continues to revise Windows, but they do it in both directions: they add features and expand capabilities with new layers, but they also remove complexity and the equivalent of the "fine tuning" knob.

Google's Cr-48 laptop is a step in simplifying the PC. It removes lots of knobs (no local programs, and even no Caps Lock key) and pushes work onto the internet. I predict that this will be a big seller, with simplicity being the sales driver.

Friday, December 10, 2010

Goodbye, Capslock!

The newly-announced Google Chrome OS has proposed the elimination of the venerable Caps Lock key. Many folks are outraged, but I am content to see the Caps Lock key ride off into the sunset.

To truly understand the Caps Lock key, one needs to know the history of computer hardware, programming languages, and the typewriter. The notion of Caps Lock started with typewriters, which allowed their users to shift between lower case and upper case letters with a "shift" key. (Most typewriters had two shift keys, one on either side of the main keyboard. Depressing the key moved the key assembly up and changed the impact area of each key from the lower case letter to the corresponding upper case letter. The "Shift Lock" key engaged a mechanism that kept the key assembly in the upper position, allowing the typist to easily type a series of upper case letters.

The early data terminals duplicated this capability, but with "logical" shift keys that changed the keystrokes from lower case to upper case. Very early data entry devices, such as IBM keypunch machines from the 1950s, her only upper case and therefore needed no shift or shift lock keys. Very early IBM systems such as the IBM 1401 used a character set that had only upper case letters. Later systems (although still early in the computer age) allowed for upper and lower case.

For computers, the distinction between upper and lower case was important. Early (pre-1970, for the most part) systems worked only in upper case. Data terminals that allowed lower case input were a nuisance, since the lower case letters were ignored or rejected by the programs. Programming languages such as COBOL and FORTRAN (and even BASIC) expected the programs to be entered in upper case. For these systems, the Caps Lock key was a boon, since it let one type large quantities of text in upper case.

The mavericks that changed the world were Unix and the C programming language. The pair allowed (and even encouraged) the use of lower case letters. Soon, compilers for Pascal and FORTRAN were allowing upper and lower case letters, and doing the right thing with them.

By the time the IBM PC came along, the computer world was ready to accept upper and lower case. Yet there was enough inertia to keep the Caps Lock key, and the IBM PC kept it. Not only did it keep it, but it added the Num Lock and Scroll Lock keys.

Yet the Caps Lock key has outlived its usefulness. I don't use it; I haven't used it since I wrote COBOL programs back in the late 1980s. The varied tasks of my work expect upper and lower case letters, and long strings of upper case are not used. Tools such as Microsoft Word, Microsoft Excel, and Microsoft Visual Studio for C++ or C# do not need blocks of upper case letters. The modern languages of C++, Java, and C# are case-sensitive, and using them requires upper and lower case.

I say, let go of Caps Lock. We can do what we need with the rest of the keyboard. (Actually, I think we can let go of the Num Lock and Scroll Lock keys, too.)

Thursday, December 9, 2010

WebMatrix rides again -- but does it matter?

Microsoft has re-introduced a new version of its "WebMatrix" package for entry-level web developers. Not merely an incremental upgrade, the new WebMatrix is a totally new product with the old branding.

WebMatrix is its own thing, living in the space below Visual Studio (even the "Express" version) and doing its own thing. Yet it still uses .NET and C#. It has a neat little syntax, with things like:

value = @Request["username"];

It can use the auto-typing constructs of the modern C# language, and you can declare variables with "var" and let the compiler figure out the type. Microsoft has taken the unusual step of supporting an alien technology (PHP) in the package. They've worked hard on this product.

The real question is: does this new incarnation of WebMatrix have a future? It's a neat tool for web development. Some might say that it is what ASP.NET should have been. If ASP was "version 1", and ASP.NET was "version 2", then this is the famous "version 3" with which Microsoft succeeds.

But the time for web development has come and gone. WebMatrix is aimed at hobbyists, people working with a lighter tool than even the free Express version of Visual Studio. I don't know how many people are in that situation.

The WebMatrix product fills in a box on Microsoft's "we have solutions for all markets" diagram, but I have to wonder how many people live in that particular corner. WebMatrix is for hobbyists, and hobbyists have little money. The money is clearly in the enterprise packages, and enterprises won't be using WebMatrix. If Microsoft wants to grow an "ecosystem" of developers, their tools for hobbyists will have to offer something more than web apps. Hobbyists have moved on to mobile apps, mainly the iPhone and Android. The idea of WebMatrix strikes me as too little, too late.


Sunday, December 5, 2010

We don't need no stinkin phone numbers

Why do we need phone numbers? If you ask the average person, they will tell you that you need a phone number to call someone. I'm not sure that we need phone numbers.

A phone number is an interesting thing. What's more interesting is what it is not: it's not an attribute or property of a phone. That is, there is nothing in your phone (I'm thinking old-style land-line phone here) that knows its phone number. 

And that makes sense. I can take my land-line phone, unplug it from my house, carry it to your house, plug it in, and use it. When I do, calls made are charged to your phone number (your account) and not mine. The fact that I'm using the handset from my house doesn't matter.

One can view a phone number as an address, a target for phone calls. This is a pretty good description of a phone number. The phone jacks in your house are bound to a "pair number" at the central office, and a phone number is associated with that pair number. This level of indirection allows the phone company to move phone numbers around. For example, when my sister moved from one house to another in the same town, she kept her phone number. The phone company simply associated her phone number with the pair number associated with her new home.

Cell phones have a similar arrangement. There is no pair of copper wires running to a cell phone, obviously, but each phone has a unique identifier and the phone company associates your phone number with that identifier. Once associated, the phone company can route calls to your phone based on the identifier.

Another view of a phone number is that it is an instruction to a switching system. Specifically, an instruction to the public switched telephone network (PSTN) to connect you to a particular phone. This is a slightly more useful concept, since it binds the phone number to the switching system and not the device.

Binding the phone number to the switching system means that it is an artifact of the switching system. If we replace the switching system, we can replace the phone number. This is precisely what Skype does, and I suspect competing systems (Vonage, Google Phone) do the same thing.

With Skype, you don't need phone numbers. Instead, you use the Skype ID. I'm on Skype, and I can talk with other Skype users. To connect to another Skype user, I need only their Skype ID -- no phone number is necessary. The Skype switching system can connect us with just the ID.

Skype does let me call people who are not on Skype -- people on the PSTN. To call them, I *do* need a phone number. But this is not Skype's requirement; it is a requirement of the PSTN. (If you want to talk to anyone through the PSTN, you must provide a phone number.) When Skype takes my call and routes it to the PSTN, Skype must provide the destination phone number.

Just as phone numbers are instructions to the PSTN, and Skype IDs are instructions to the Skype switching system, URLs are instructions to the web system. (The switching system for the web is perhaps a bit more complex than that of the PSTN, as the web has multiple layers of addresses, but the concept is the same.)

We may soon see the decline of the phone number. It works for the PSTN, but not for other systems. Other systems (the web, Skype, Google Phone) have no need of phone numbers, other than to connect to the PSTN. If we abandon the PSTN for other systems, we will also abandon phone numbers.