Programming itself provides opportunities for self-expression.
In the midst of chaos and strife, when I need to take a break from the “real world”, I most often find my escape in source code, programming anything really. Of course, having more projects than I could hope to finish, and clients providing additional work to boot, means that I always have a ready avenue for directing my focus. However, it is not solely about the product, nor the money; it is also about the pleasure and enjoyment of coding itself.
There are a number of fairly passive experiences that I (and I imagine most of us) use to pass the time: playing games, reading books, watching television or movies. There are also more productive activities such as exercise (I quite enjoy hiking, bicycling, and swimming), house cleaning and organization, home improvement, and “gardening” (of a sort). None of these activities, however, provides the same creative outlet as programming.
When it comes to creative expression, appropriately, there are lots of different ways that people find to fulfill that need, which is important to our being. I know lots of people who like to sketch or doodle, or to write (for which I have gained some appreciation over the years), and others participate in higher commitment activities such as making stuffed animals, woodworking, or designing jewelry. When I was younger, I turned to more “design” oriented expression, such as creating original mazes, designing pinball machines, and architecting dream houses; at one time I designed a complete go-kart business, including the tracks and buildings.
The beauty of code is that it allows for self-expression within a systematic framework. I have always enjoyed numbers, logic, and the rational, and these all factor into programming. Within the rules, though, there are essentially infinite ways to express an idea, both in terms of method and of presentation. Of course, there are demonstrably “wrong” ways to do things, such as code that does not compile, fails to work, or crashes, but there are many levels of “right” ways to accomplish things, including how to efficiently increase functionality, how to handle errors and unexpected situations, and (importantly) how to make the source code understandable.
When I was required to attend an “advanced” BASIC course in high school, having already programmed for years (but with no formal education to show it took vociferous insistence just to avoid the “beginner” class), one of the first problems we were presented was to take a three-digit number as input and reverse the digits. I was the very first person to complete the task, twice. My second version was the anticipated method of accepting numerical input, with constraints placed on the operator (not the program) to limit the input to 3 digits, separating the number into ones, tens, and hundreds places, and printing them in reverse order, just to prove that I knew how to do it that way. My first version accepted the input as a string and printed the characters in reverse order, which worked on the specified input type, but also on numbers of arbitrary size, or any characters that could be input.
Around that time, I also set myself a challenge to create an “unbreakable” game, which I was able to accomplish with a high degree of confidence. To be unbreakable, the program had to be bulletproof, once executed, such that nobody could deliberately nor accidentally get to the prompt (and, hence, have access to the source code). This meant that the program needed to have no syntax errors (BASIC was interpreted code, rather than compiled, so such errors would only be found when executed), no logic or constraint errors that would allow a crash (such as selecting an unexpected/illogical action or overloading an input buffer), and also disallow breaking (via ^C), which was accomplished via system-specific methods. The only ways to end the program were turning off the power or hitting the reset button.
Programming has a lot in common with the scientific method. Although you use known logic to devise provably correct solutions, rather than testing hypotheses, you still test to confirm your approach and resolve errors, whether they be in your understanding of the problem, your design of a potential solution, or your execution of the plan. In fact, I constantly use this approach when building a program to regularly test my assumptions. I will make an interim change and state (to myself) the expected failure outcome, whether that be a compiler error (or specific number of compilation errors) or some weird behavior, just to confirm my understanding. If some code compiles unexpectedly, or the behavior is not as anticipated, I revisit the problem and make sure than I can explain why things went differently.
This shows yet another beautiful aspect of programming: its digital nature makes it precise and enables, at least ostensibly, the pursuit of perfection. You can experiment with something new with confidence that, if it does not work out, you can return to exactly the original situation. It does not matter how far out in the weeds I get with an idea; I can always get back to where I started. (Try that with oil painting.😉) Also, as my first computer book helpfully pointed out at the start of my career, nothing that you do with source code, short of typing it with a hammer, can break your computer (and while that is not strictly true, exceptions are exceptionally rare and not worth concern).
The fact that I value the actual source code as well as the outcome, which tends to be better for such appreciation, explains why I am not a fan of “visual programming”. With traditional source code, everything is enumerated and readily viewable, having been written by you or another programmer. While visual programming is ostensibly the same, it hides aspects of the code and logic behind objects, making development more like hide-and-seek. My first experiences were in the very early ’90s with Asymetrix ToolBook and Borland ObjectVision, where one would have to check every page and object to find all of the scripts to have a complete understanding of the logic, which unnecessarily fragmented the code. Today, such tools as Unity, Unreal Engine, and Interface Builder certainly make visual layout easier, but with the inherent risk that the complexity hides some of the logic, removing it from the source code and fragmenting it. It can be quicker to develop visually (especially if one is inclined toward fast results over quality), but it is inarguably harder to debug.
Outstanding programming is more craft than art, by which I mean that it can be learned and refined over the course of years, and one does not necessarily require an inherent creative ability. I can explain the rationale behind decisions in my source code, and I can teach you techniques, and if you have the requisite logical intelligence (which many people do not), then you can become at least a very good programmer. (I doubt one can read a book about fine art and learn what it takes to be a master.) One of the best compliments I can get is when I am told that I taught somebody the value of maintainable source code, or defensive programming, or quality assurance techniques.
With that in mind, I intend to document more of my approaches to development in general, to provide insights that interested parties can take or leave, along the lines of my Quality [index] series from many years ago. One current focus is refining my programming standards, so look for that in the near future.