What Is a Program?
We all rely on technology for each instant of our lives. But we are also threatened by this new and necessary magic because we don’t really understand it. Most of the devices we use are either broken, mis-configured, or just badly designed. But we can’t do anything about that, either, because we do not participate in the process that creates them. We can get out of that trap by learning more about these “toys”. Let’s begin with the computer itself:
A computer is as dumb as a toaster. In fact, an old-style toaster is much smarter than a computer will ever be. A toaster could tell if a piece of bread was cooked because at a certain temperature, a sliver of highly sensitive metal would curl and touch another piece of metal, causing electricity to flow through. That fired the eject button on the toaster, and POP, out flew the toast, hopefully onto your plate! A computer could never do that, at least not without a lot of help. All a computer can do on a hardware level is to tell the difference between 0 and 1. If you look into your back yard, you can see a large version of the hardware that exists inside the central processor of any computer: a simple gate. If it is open, the computer reads 0, or false. If the gate is closed, the computer sees this as 1, or true. The problem with this is that there there are actually three decisions that should be made if the computer is to rely on the gate as an analogy of anything and everything:
The gate is open because it has been opened.
The gate is closed because it has been closed.
The gate is unset because no one and nothing has decided to either open or close it.
So can a computer determine this at a hardware level? No! It is a binary system, so must assume that when it a gate is open, it was left that way on purpose. This does not reflect reality in any way. But it’s where we began, and nothing has been done about it since. So a computer is defective even by the simple standard that we have cited here.
So how does a computer do anything?
The answer is: software. Some kinds of software help the computer be a better physical device. The software that you encounter the most is in the form or software programs that are written to allow you to interact with a computer, and for the computer to pretend to be smart. If it sounds complicated, it is. But like anything if you can learn about something fundamentally, you can build on that over time. So let’s begin be defining what a software program is:
A program is an automation process in which highly organized variables interact through their relationships with each other and through events.
There’s also one key addendum to help set us on the right course when creating a software program:
The program shall be small.
Philosophical statements can be hard to digest. Take, for instance, the single statement that describes the United States’ government:
This is a libertarian society based on individual rights.
.. and for the addendum, we would refer to the Bill of Rights, which sets out clear rules that we must never break because that would violate the core philosophy.
Still, if you grew up in another country and migrated here, and had to take a Civics test to get a citizenship, you would find yourself repeating the words like a parrot, hoping for a peanut as a reward. Does that mean you grasp them? Philosophy is difficult to teach, so must be instilled from birth. That’s why it is so difficult for foreigners to feel at home here, at least until they become “one of us” — if that ever occurs. And all stemming from a philosophy that they never experienced until they stumbled off the boat in New York.
Most Americans are immigrants when it comes to technology. We just “don’t get it”. So we give up. We never “belong” to the new world of technology. We just visit there when we have to. This must change. This article is dedicated to the notion that everyone can learn about technology and with a little effort, gain more control of the technology that affects their daily lives. The reason I begin with the statement of Programming Philosophy — describing “What is a Software Program” — is to underline the importance of fundamentals in how we create things. If we respect design and plan what we do, we can achieve great things. If we ignore this process, we make a mess. Today’s programs are mostly a mess. Let’s see why.
The “Bad Old Days” of Linear Programming
I got curious about programming after buying my first IBM PC in the early 1980’s. The operating system was quite spare. I used Microsoft Word and Excel early on. I wanted to make those programs work better for my business. So I learned about a language called VBA (“Visual Basic for Applications”) that ran inside the Microsoft Office suite. This language was primitive, but for a beginner, it already felt like I was taking real control over the program’s behavior. For instance, I over-rode the print dialog to add a few extra buttons that allowed me to do things “my way”.
In 1985, I asked my brother — a trained professional programmer, with a Master’s Degree in Math and Computer Science — to write a program that would run my small wholesale business. He was busy, so only grudgingly agreed. I waited and waited. After a few months, he showed me the grand results: a window opened on the computer screen with a few labels and text. I slumped. “Is that it?” I gasped, not realizing just how much time it had taken him to accomplish this feat. My brother could see that I didn’t know what was actually involved in creating a program, especially for the time we were living in. So he invited me to his house in December, 1985, and sat me down in front of his computer. This time, all I could see was a text editor with some weird-looking words and symbols filling its screen. “What’s that?” I asked. My brother grinned. “That’s source code. You’re going to write your own program”.
This was first day as a programmer. I committed myself to learning how to create applications that would make my computer more efficient for users. I have been on this course ever since.
For the next ten years, I developed an ever-more-powerful program using a language called Turbo Pascal. At that time this was a great way to create a quick application. Eventually the program swelled to over 100,000 lines. It ran my entire wholesale business.
Now that I look back on my first decade as a programmer, I can see that it was not going to prove robust or lasting. I was engaging in a flat, simplistic sort of thinking. But so was the rest of the programming world.
What Is Linear Programming?
Linear programming is taking a “straight line” from the start of a thing to its perceived end, made up of steps. For example, an old MS-DOS batch file:
ECHO OFF CLS :MENU ECHO ............................................... ECHO PRESS 1, 2 OR 3 to select your task, or 4 to EXIT. ECHO ............................................... ECHO 1 - Open Notepad ECHO 2 - Open Calculator ECHO 3 - Open Notepad AND Calculator ECHO 4 - EXIT SET /P M=Type 1, 2, 3, or 4 then press ENTER: IF %M%==1 GOTO NOTE IF %M%==2 GOTO CALC IF %M%==3 GOTO BOTH IF %M%==4 GOTO EOF :NOTE cd %windir%\system32\notepad.exe start notepad.exe GOTO MENU :CALC cd %windir%\system32\calc.exe start calc.exe GOTO MENU :BOTH cd %windir%\system32\notepad.exe start notepad.exe cd %windir%\system32\calc.exe start calc.exe GOTO MENU
This generates an on-screen menu. Pretty handy, and can be created in moments. So why not just build all of our programs like this? Let’s have a closer look.
This is fairly clunky. What happens if instead of typing the correct language:
SET /P M=Type 1, 2, 3, or 4 then press ENTER:
… you type:
SET P M=Type 1, 2, 3, or 4 then press ENTER:
The batch file crashes and so no menu appears. All for the lack of a slash. Imagine if this batch file created the main menu of your program. The user would not be able to use the program at all. So linear coding is fragile. It is easily broken.
Also, why weren’t you warned about the error? There’s no good editor for this type of code that will warn about errors. Even in more advanced linear languages, such as VB Script, Pascal, JavaScript, etc., perhaps 90% of all possible errors are simply ignored. The editor can’t help. Linear programs do not provide adequate error checking. They are extremely difficult to debug. In very large programs, you may need to watch them line-by-line just to find a single tiny error. The program would take forever to develop. I know this because that’s how we debugged early programs. We don’t want to return to this tortuous practice.
Why are these two pairs of lines repeated?
cd %windir%\system32\notepad.exe start notepad.exe cd %windir%\system32\calc.exe start calc.exe
… and if they are repeated, how do I make sure that each time they are written, they appear exactly in the same way? Also, what happens if I get something out of order during that process? This is one of the biggest risks in programming in general: redundancy. Once we have copied and pasted something from one place to another, we cannot guarantee that each version will always be the same. Maybe someone will come along and change one of these lines (but not both) as follows:
cd c:\windows16\system32\notepad.exe start notepad.exe
.. and for a while, it works. But then a new version of windows comes along and it breaks. That’s because under the new Windows, the notepad is located at:
c:\windows32\system32\notepad.exe
So the first of the two redundant code pieces works, because it uses a system variable to find the windows directory:
cd %windir%\system32\notepad.exe
… and the second one now fails because it doesn’t. But this is where programmers go wrong again. Many beginners will actually repair both lines to match each other, so they both now say:
cd c:\windows32\system32\notepad.exe
.. which actually works. Until the next version of Windows, when the operating may move the notepad to some new location. The program was “fixed” through hard-coded linear thinking: that if we test something, it is good coding. But it failed at a design level because it was not robust over time.
So another weakness of the linear approach is that it is inherently redundant and almost impossible to keep up-to-date.
Let’s have a look at a VBA snippet that creates a new worksheet:
Sub AddNew() Set NewBook = Workbooks.Add With NewBook .Title = "All Sales" .Subject = "Sales" .SaveAs Filename:="Allsales.xls" End With End Sub Set NewBook = Workbooks.Add
Does that mean NewBook is an actual workbook? You’ll say to yourself: of course it is! How else could you create it? Well this is why nobody writes VBA anymore. The answer is not intuitive. We could actually substitute this for the code above:
Sub AddNew() Set NewBook = 1 End Sub
Now NewBook is an integer – ? – ! How is that possible? In VBA, a variable is “anything”. It is called an Object. Once it is assigned, it takes on the shape of the thing that it was assigned to. But it can be reassigned at any time to anything else. This makes VBA quite easy to code for beginners, but extremely hazardous to long-term safety and manageability.
For instance, what happens here?
Sub AddNew() Set NewBook = 1 Set NewTree = "tree" Set Explosion = NewBook * NewTree End Sub
NewBook is an integer. How can that be multiplied by the string, “tree”? It can’t. So the program halts where these two dissimilar elements are mixed together. The editor doesn’t tell you this in advance. You have to find out at “runtime” — when the program is running. So these old linear editors are deeply flawed.
Programming professionals call this principle Type Safety. Linear languages generally lack this key feature. They are hopelessly vague.
Procedural Programming Languages
A procedural language is one that is linear in its structure, just like a batch file. But it provides a few new tricks to make coding easier. The main one is the ability to create a procedure that can then be called redundantly. You can actually fake this effect in a batch file. For instance, runCopy.bat:
xcopy %1 %2
… which you can call directly from another batch file, as long as they are pathed together and can see each other. Here’s the second batch file, called CopyMyDocs.bat:
call runCopy “O:\MyDocs\*.*” “Q:\MyDocsBackUp\”
The term Call means to call the batch file. The two quoted strings are the two parameters which are received inside runCopy.bat as %1 and %2.
The Procedural Summit: C
With the development of C in the 1960’s, procedural programming reached a high water mark. Powerful, complex programs could be created that ran at lightning speed. The enormous power of C came at an extraordinary price: C was not easy to code, and tended to be buggy and difficult to control.
Summary
The “bad old days” of linear, procedural programming provided:
Pro’s:
- Relatively quick to develop.
- In many cases, easy to write with a beginner’s skills.
- Could be developed and used on-the-fly and often as a part of other applications (such as VBA inside Excel, etc.).
- In the case of C, could be extremely powerful and amazingly fast — though required expert skills.
Con’s:
- Linear methodology did not reflect how things occurred in real life scenarios.
- Virtually no type safety. Anything could be anything. No predictability. Poor contracts between parts of the program. The code itself was parsed at compile time, and much of it was late bound, meaning that the actual type was not known until the program actually ran. Many types of errors arose out of this loose construct.
- Redundant and verbose, so impossible to version or debug.
- Mostly weak editors would let you hang yourself while coding and find out later when the user was trying to run your program.
- Poor error-handling; most problems just crashed the program.
- No event-driven model, so no interaction between elements based on competing interests, as in real life.
The Arrival of Object Oriented “Behavioral” Languages
The high-water mark in the development of object-oriented programs came when slow-to-the-party Microsoft, after watching 16 years C++ and Java, decided to release its opus, a language called C#, which over the next decade, would bring extraordinary benefits to the programmer. C# filled the void in the need for a powerful, easy-to-learn-and-use language for the creation of applications. It restored faith that Microsoft was the world leader in programming languages, if not software development (sigh). (Note: an “application” is a file with an .exe suffix that you run from your computer. It does not reside inside a web browser).
C#’s only major weakness was speed. It still waddled along behind the hyper-fast C++ in real-time benchmarks. This is because C#, like Java, opted to produce a byte code that the operating system would run as a separate layer. The theory was that the compiled program would be independent of any given operating system. But in 11 years since, no company has been capable of writing an adapter to allow .NET to run completely and successfully inside a foreign OS. So the decision for byte code was grandiose and unnecessary. In C++, the entire output is already “pre-digested” and ready for the operating system. That’s why it’s so much faster. Microsoft never corrected the issue; even today, C# is hobbled by this approach.
Why Is Object Oriented Coding Better Than Old-Style Linear Scripting?
In “object-oriented” or “behavioral” programming, instead of trying to tell the program what to do, we create “objects” that behave much like human beings. They have their own information the store (as in our brains) and they also have things they do (behaviors), personal relationships (class derivation) and a means of communicating with each other (events).
Of course, this doesn’t guarantee that a programmer will always implement this concept properly. That is the art and science of professional coding. For instance, here are two ways to do the same thing: make animal noises based on some inputs. I’ll use C# as the language. Strangely, you can write both good and bad code inside C#, as with any editor/compiler. This is why we need to train programmers to think in a new way about what they do. Object coding is like chess; linear coding is like checkers. So first, the quick (wrong!) way, which is how 99% of the world’s so-called programmers would do it:
using System; namespace AnimalSoundApp { public class Program { private static void MakeAnimalSound(string[] animals) { // Check to see if there are any animals implicitly below (for safety). foreach (var animal in animals ?? new string[0]) { // Check for each animal by its name and issue the proper sound. switch (animal) { case "cat": Console.WriteLine("Meeeooowww..."); break; case"dog": Console.WriteLine("Bark! Bark!"); break; case"bird": Console.WriteLine("Chirp! Chirp!"); break; default: Console.WriteLine("{Shhhh…}"); break; } } } public static void Main(string[] args) { MakeAnimalSound(new [] {"cat", "dog", "bird"}); } } }
The console output looks like this.
Upon questioning, these so-called “programmers” would say:
They did what they were asked to do: make animal sounds based on an input.
They tested it. Works every time!
They wrote it in 10 minutes. What a savings! At this rate, they can write a million lines of code in their first year. What a value!
But under close analysis, all sorts of issues pop up. For instance, what happens if we misspell something? Maybe just once, like here:
public static void Main(string[] args) { MakeAnimalSound(new [] {"ct", "dog", "bird"}); }
The output would look like this:
That’s incorrect. The first line should have read, “Meeeooowww…”. But the program couldn’t find a “cat” because the input was misspelled as “ct”.
No programmer ever thinks they can make a mistake like this. But in every program I have ever reviewed, I have found lots of them.
What if we have to create a lot of animals? Maybe thousands? And what if they have hundreds of different behaviors, like how they move, and all of that has to be reflected in the program? Is that an exaggerated expectation? Modern programs must manage large enterprises. You can see that this would create a huge mess.
The code is also quite redundant. We define that as any same or similar code in the program that could easily be rewritten to prevent the redundancy.
The code is linear: crude and unsophisticated in its approach to the problem.
The Object-Oriented Solution
As an Object-Oriented Programmer (“OOP”), the first thing I ask about a new assignment is, “how can I best explore, comprehend and act upon all of the potential behaviors in this application?”
Don’t cats and dogs have an in-bred relationship? Especially when they don’t know each other? Dogs tend to fight with cats. The same applies to cats and birds. Cats pursue – and eat — birds.
If any of these critters got into a fight, wouldn’t they make different sounds than if they were unconcerned?
The program should remain uninvolved in the animals’ interactions. All it should provide is an open yard where the animals interact according to their innate behavior.
Finally, the program should be fun and easy to use. So the user must be involved in what happens.
Here is what I came up with. I’ll run you through the screen shots. Let’s see if you start getting a sense of what we mean by behavioral programming:
The program has only one screen. It’s a “yard” with three animals: a dog, a cat and a bird. Notice the circles around the animals. Those represent the distance they can see (outer blue) and the distance at which they feel confronted, or confront others – their “fighting range” (red). These circles are different sizes because each animal has unique capabilities.
Here’s the “user” part of the program. With the mouse, left-click on the cat and drag it closer to the bird. The bird reacts first because it has a wider “sight” range. It sees a superior enemy.
Then the cat reacts, as the bird enters its sight range. The bird is an inferior enemy / prey. So the cat starts getting aggressive.
As the cat gets into the bird’s “red” fighting range, the bird reacts with a new sound.
Finally, the cat gets the bird within its attack range, and makes its own new sound.
Now let’s bring the dog into the picture. As the dog approaches and gets the cat into its sight range, the dog sees an inferior enemy, so becomes more aggressive.
The cat quickly perceives this change, as the dog falls into its sight range. The cat now sees a superior enemy. This “trumps” the cat’s preoccupation with the bird. So the cat makes fear-based sounds.
The dog gets the cat into its fighting range and is ready to fight, so makes its angriest sound.
The cat sees the dog in its close range and forgets about the bird entirely, making its own fighting sound.
Conclusion: Linear vs. Behavioral Programming
Linear | Object-Oriented | |
Related Terminology | Scripting, Distributed Programming (writing code everywhere rather than I one place and then sharing it). Late-Bound (no type safety). | Behavioral Programing, Interface Programming, Centralized (Common) Code, Compile Time Type Safety, Multi-Dimensional Approach (think of “3-D chess”). |
Methodology | “Telling the program what to do” – Rigidly ordered, consecutive statements made up of hard-coded primitives. Classes define behaviors. | Interfaces declare class interactions. Events notify classes about other classes. Classes work independently from each other, mirroring real-life behaviors. |
Mind-Set, Massively Over-Simplified | How can I give more instructions so the program will do more things? | What is it? The program is an illusion created by independent interests, all of which know what they are. |
Attitude | More is better. Work is rewarded on how many lines of code a programmer can produce that can pass a unit test. | “The program shall be small”. Work is rewarded when it is centralized, concise, complete and fully compliant with philosophy. |
Mantra {Eastern Zen-Like Mission Statement} | If I copy the last guy’s code, I’ll fit in and won’t get into trouble. | The program shall always work perfectly. If it fails to work perfectly, then we will find the problem in a centralized location and will fix it. After that, the program shall always work perfectly. |
Scalability | Without concepts and organization, the code is a tightly-bound series of instructions that are hard to alter except by throwing everything away and starting all over again. | Although intensely analyzed and organized, the class/interface paradigm can grow in virtually any direction over time, without major effort. |
Confusing Nautical metaphor | Over-steered. Each instruction is mandatory, but at the same time excessive, robbing the program of its “oxygen”. | Slightly under-steered. Classes possess their own behaviors. Theoretically, we don’t actually know all of the things a program might do. |
Strengths | Quick to develop. Instant gratification. Low skill set required for basic coding. | Extremely well-organized and manageable. Almost zero redundancy. Easily changeable, debuggable and scalable. Very predictable results. |
Weaknesses | Easily broken; light-weight and not able to handle complex scenarios; code must grow at the same rate as the program’s requirements; hard to fix; almost impossible to scale elegantly; difficult to learn someone else’s work, as it is convoluted, verbose and messy; horridly redundant, with each area of duplicated code having its own logic, but inadvertently; unpredictable results. | Design and architecture take 3-6 months for most medium-sized programs, with very little to show for it. Difficult for amateur programmers to learn, since it is “three dimensional” vs. linear thinking. Requires conceptual brain, which, to technical programmers, is like asking them to attend art class. |
Can it Pass Intense Random Unit Testing? | Not a chance. The coders created slam-dunk unit test scenarios to “prove” their code. | Every part of the code is as robust as the next. |
Cost | Cheap initially, then heavier as reality sets in, and unbelievably expensive over time, usually resulting in tossing the entire project. | Expensive initially, and requiring very heavy analysis and planning. Catches up with scripting at the half-way point, but with robust initial results. Very cost-effective in the long term. |
How to Determine if this Approach Is Being Used | Loose primitives in the code. Poorly declared classes that contain scripts. No behaviors created or enforced. Very large code base chock-full of redundant elements. “Speed coding” is a 99% indicator. | No redundancy. Narrowly defined classes that only contain the code need to support what they “are”. By file count expressed as percent share, the program will contain 15-25% interfaces, 15-25% abstract classes, and the rest as regular classes. By line count, the abstract classes should contain 40-50% of the program code. |
Who’s Using This Approach | 99% of the world’s programmers, including those who think they are familiar with objects. | Programmers who are obsessed with fundamentals, and have the discipline to enforce them. |
I encourage you to download the ZIP file and run the “OOP” versions of the program (inside the zip file, \AnimalSoundApp\Program\AnimalSound_OOP.exe
). Important: The attachment is shown as AnimalSoundApp.txt because it is easier to download that way. Just copy it anywhere and rename it to AnimalSoundApp.zip so your ZIP program will be able to open it easily.
AnimalSoundApp
Notice how vastly different this source is versus the horrid batch-file script. It’s also open source. Enjoy.