(As with all "concise and simple" articles I assume no prior knowledge of the subject and keep the length to less than 1500 words.)
This is a personal reflection on programming: the creation and curation of instructions that make computers do things. Instructions (also known as "source code" or just "code") are organised into programs (or "software") that fulfil specific tasks. People who write programs are called programmers, developers, software engineers or (colloquially) hackers.
Instructions are expressed in programming languages that make it easier for humans to comprehend what is going on. So-called "high level" languages are easier for humans to work with than "low level" languages that express things in a way that is closer to how the computer works. In all cases programs are transformed from the original programming language into the binary instructions that cause the computer to function in a particular way. This transformation can happen in two ways:
- The program is "compiled" in to binary instructions by a special program called a compiler. The result is an "executable" run by the end user.
- The program is "interpreted" by an executable interpreter whose function is to act as a sort of on-the-fly translator of the instructions.
Both mechanisms have strengths and weaknesses. Because compiled programs have already been transformed in to the computer's binary instructions they are often much faster than interpreted programs where such transformations happen as the program is running. Yet interpreted programs offer the flexibility of adapting and changing themselves while they are run by the interpreter which makes it easier to solve certain sorts of programming problem. Sometimes a combination of these techniques is used: A JIT compiler will interpret until certain sets of instructions are obviously more frequently used, at which point only the popular sets of instructions get compiled "just in time" to make them faster.
Sometimes programs work as expected and produce valuable results. More often they do not. The failure to make a computer work usefully is called a bug. There are generally two sorts of bug: the wrong outcome is correctly implemented (the design is wrong) or the expected outcome is wrongly implemented (the instructions are wrong). In any case, because computers are complex machines, making them do something useful is surprisingly hard.
Managing and taming complexity is one of the core tasks of a programmer. A common piece of advice given to junior developers is "kiss" (keep it simple, stupid!), for there are fewer things that could go wrong. As computing pioneer Tony Hoare explains,
"There are two ways of constructing a software design: One way is to make it so simple that there are obviously no deficiencies, and the other way is to make it so complicated that there are no obvious deficiencies. The first method is far more difficult."
Personally, I think creating simple and useful software is more like writing succinct yet powerful prose than opaque logical wizardry. This has an important side effect: simple and coherent code is easy to understand. Code that is easy to understand is easy to maintain. Maintaining code is the act of fixing bugs and curating instructions so things work efficiently (also known as re-factoring). In this way a program is easy to improve as bugs are found and new features implemented.
Some languages have been created with the explicit aim of making code easy to read and understand (such as Python). Some developers promote certain development styles that they claim encourages programmers to produce high quality software. A classic example of this is test driven development where developers write a failing test encapsulating a feature of their program before actually implementing the feature itself to make the test eventually pass. Others (such as Donald Knuth) promote a literate style of programming where code is interspersed with natural language explanations that tell the "story" of the code.
Another core skill of a programmer is de-constructing and analysing problems. Often the problem is expressed in a vague and open-ended way and it is the task of the developer to precisely constrain the scope of the problem so they create some useful outcome. A personal example, from my first programming class, illustrates this beautifully: my tutor explained that programs were merely instructions and that we had five minutes to provide instructions telling him how to switch on the classroom's lights. How hard could it be to write such instructions? Take a minute to imagine what you would write (you may assume that the person following them knows about directions, actions and names of things).
I can still remember my list:
- Stand up.
- Look around until you locate the light switch.
- Walk in the direction of the switch.
- Press the switch with your fingers.
- Retrace your steps.
- Sit down.
Of course, I failed miserably. My tutor pointed out that he was already stood up, there were desks between him and the light switch and the damn lights were already on anyway.
Time and resources are also essential elements of software development:
First, the developer needs to have a feel of how best to organise a program. This means analysing their implementation of the algorithm (the instructions at a conceptual level) to ensure that it is both timely and makes efficient use of resources like the computer's memory and CPU. Often this is expressed using big-O notation.
Second, programming usually involves a deadline. Customers need to know how much time it will take to finish software given a certain number of developers and some sort of collaborative development process. I've heard this described as "the cat herding problem". Fred Brooks famously observed that adding developers to a struggling project only slows it down further. Furthermore, clients change their minds mid-project (in addition to providing vague problems like the one mentioned above) and there are always unknown unknowns that add unforeseen time and effort to the project. If this were not enough, how do you coordinate teams of programmers who are all working on the same software? It's like trying to get ten people to co-compose a symphony at the same time.
Happily, developers have created methods and tools to help them work together. Small autonomous "agile" teams are preferred over large managed cohorts of developers. Issue tracking systems make it easy for clients to request and prioritise features, report bugs and give developers a clear audit trail upon which to base development decisions. Code is stored in version control systems that allow developers to track each other's changes and resolve any conflicts in the software (for example, when two people edit the same piece of code). In fact, developers have become so good at this sort of thing that others borrow these tools and techniques: lawyers have been known to collaborate on complex legal documents with a version control system.
Finally, programming is a political activity: making software means defining the laws that dictate how the digital world should be. Often this obvious fact is left unacknowledged. However, incumbent interests affected by the rise of digital culture (for example, the so-called "creative" industries represented by organisations such as the RIAA, MPAA and their ilk) have attempted, with some success, to change the law to limit the use of file sharing software used to distribute pirated content.
Yet, programmers have turned the law to their advantage. Richard Stallman, founder of the Free Software Foundation (FSF), became disillusioned with locked down dis-empowering software so set out four essential freedoms:
- The freedom to run the program, for any purpose (freedom 0).
- The freedom to study how the program works, and change it so it does your computing as you wish (freedom 1). Access to the source code is a precondition for this.
- The freedom to redistribute copies so you can help your neighbor (freedom 2).
- The freedom to distribute copies of your modified versions to others (freedom 3). By doing this you can give the whole community a chance to benefit from your changes. Access to the source code is a precondition for this.
These freedoms are enshrined in the General Public License (GPL) - a license that subverts copyright (that seeks to expand the rights of creators at the expense of the rights of others) in to copyleft (that seeks to expand the rights of everyone). There is one important exception that limits everyone: any modifications to source code covered by the GPL must also be freely available under the GPL. While the GPL has been described as communist and cancerous it is not anti-commerce and (I think intentionally) does not mention any political affiliations. Code covered by the GPL can be sold (see sections 10 and 11). It's how the FSF first raised money for their cause.
1497 words. Image credits: © 2013 the author with this service.