Showing posts with label programming language. Show all posts
Showing posts with label programming language. Show all posts

Tuesday, August 7, 2012

Good Code

No one appreciates good coding, because only coders understand what coding is to begin with. For anyone else, if the thing works then you only did your job - that doesn't make you a good coder. Well, it does, but to anyone who doesn't understand it, computer code that works the first time is just normal, not great. If anything, it only reflects badly on the quality of the testing that was done.

On the other hand, bugs are high visibility and high priority, unlike coding. Only when it's broken do people seem entirely willing to acknowledge that code actually does exist. If you fix a lot of bugs in a few hours (despite it being far simpler than the actual coding, in most cases) then people understand that you've done a great deal of work. Coding nearly always goes unnoticed and unappreciated. If the code works fine, then it's just ignored, like it doesn't even exist.

To get some perspective, apply the same argument to writing in general. Writing software is in many respects very similar to writing prose or poetry. Programming languages have nearly the same semantics and syntax as spoken languages, it's just that their purposes are quite different.

Computers never use programming languages to communicate with us; it's only us communicating to them the instructions that we want performed, the order we want them performed in, and the logic that holds the rules together and the system in place.

With writing, absolutely no one expects you to get the first draft right. What makes you a great writer is being as good at revising (or better) than you are at writing.

The same applies to coding, only the underlying purpose gives the revisions a different purpose as well. In both cases, you are revising in order to make the written medium (words, code) better. Better writing is hard to define, since writing is a little more of an art form than computer programming. Better code, by contrast, is well defined - if it doesn't work, it's not good code. I will now go through some of the differences between good writing and good code, and how the writing systems themselves differ.

Prose writing is more about the context than the actual words, though being a good wordsmith certainly earns you extra points. The context is normally the story elements (plot) which includes character development, something that takes a good deal of time to do outside of the actual writing. The characters must be alive in your head and have their own motives, goals, aspirations, and personality, before you can plug them into the time frame and particular circumstances of your actual story and have it come out sounding realistic. In the case of non-fiction, the context is your particular topic or subject, and the structure of your argument or points. You remember this from high school English class: the first sentence of each paragraph should be the theme or thesis of that paragraph, followed by support, evidence, and further argument about that same point. The first paragraph is normally an introduction and the last is normally a conclusion, with at least three body paragraphs between them.

Poetry, on the other hand, is all about word selection, diction, and imagery. Poetic devices, such as rhyme, alliteration, meter, and various other tools, are of paramount importance. The actual message is usually only a result of the deeper themes and moods created by the specific words and their connotations. I find that rhyme is often a quite underestimated tool, not used as often as you might think in poetry. It can be used to emphasize - the words involved in the rhyme are usually the focal point of the entire phrase or sentence. Thus, it is also important to choose which words are going to rhyme, and as such, this often requires some grammatical flexibility to rearrange the parts of the sentence in a way that doesn't sound archaic or confusing.

Lastly, computer code is like neither. The entire purpose of computer code is logic - that is both its foundation and its end. The building blocks are simply logical constructs, such as a loop that executes a portion of the code over and over (to avoid having to write many instructions that do mostly the same thing). Most logic boils down to conditions - if this, do that, or if this other condition is true, do this other thing. If this condition is false, skip this part of the code. This logic tells computers how, when, and what to do, in a way that bears no interpretation (heh, at least not the kind you're probably thinking!) Here is where we get into the revision.

At this point, I'd like to mention one minor historical anecdote: the first computer bug actually was a bug! A moth had been electrocuted while chewing on some circuitry in one of the first mainframe (room-sized) computers, and was causing a short in the circuitry. What then constituted the 'software' was actually hardware, in the form of vacuum tubes and switches. The switches would be set to input the instructions, and the computer would run through whatever instructions had been set in these switches. A programmer's job back then would have been to manually go to each switch and move it to the right setting, according to a long (and probably quite boring) sheet of numbers. This bug probably took a while to find, as the chances of a programmer losing his focus and mis-setting even a single switch were quite high!

Revising computer code is simple, yet not straightforward. This is because most often, you don't know what specifically is wrong with the code and how the problem is being caused. If you had, you wouldn't have written the wrong code in the first place! The first step is called 'debugging' which means going through the code, one instruction at a time, and watching the computer perform it, then examining the current state of the computer and the resulting output at that point. Once the problem is seen, the instruction last executed is most likely to be the one causing the problem. Now that this is known, it is normally a simple matter to determine where the error in the logic lies, and rewrite the code accordingly. Therefore, until programmers can code perfectly, we are stuck with bugs for the time being.

Now, the existence of bugs is no reason to knock computers themselves! The great thing about computers is that they are seldom at fault for the problems we face. It is normally operator error, either on the programming side or the user side. If the programming is wrong, we call it buggy or glitchy. If the user is wrong, it is known as a PEBKAC (problem exists between keyboard and chair). Computers execute their instructions correctly 99.9 % of the time. Whether those instructions are right or wrong is a different matter. Readers more interested in the subject of computers writing their own instructions should have a look into aspect-oriented programming. It is the newest programming paradigm, a step up from object-oriented (warning for the non-techies: highly advanced technical terms may cause head to explode). See my other post for more information about the different programming paradigms.

Tuesday, July 3, 2012

Will Program For Twenty Cents

The subject of this post is actually programming, and another word after it which makes the post title a geeky pun. Bonus points for those who can figure it out! (Hint: You won't find the word anywhere in this post. I took extra effort not to use it).

From the first time I looked at computer code, I was fascinated by it. Ironically, during elementary school, I didn't think I'd ever be smart enough to program computers. This may have been because I wasn't smart enough at that point - the only intellectual limit of childhood seems to be one's inability to think farther than a week ahead. Better understanding your own potential for growth is part of maturing into an adult, I have found.

When personal computers first became available, their use was not widespread. Rather, the internet was simply a network of the major computers that existed at that time, and primarily between research facilities. Programming at that time would have been a headache compared to what it is today. Since binary (or more generally, anything digital) is nearly the opposite of how the human brain works (everything is analog), computer instructions then were written in hexadecimal, a number system on the other end of the scale from binary. Binary uses two digits; hexadecimal uses sixteen. In comparison, the number system we write with uses ten digits, and is simply called decimal.

Even in hexadecimal, computer code is all just numbers, but in a form more easily usable by humans. This is because, due to having eight times more digits than binary, a very long number in binary becomes a very short number in hexadecimal, meaning a lot more code can be shown with very few digits. This was the first form of software programming; hardware programming previously used switches that had to be set by hand.

Next came spaghetti code. The mental picture is fairly accurate - instructions just thrown in wherever they were deemed necessary. There was no real structure or organization at all. Each instruction was directly mapped to an address; the address was actually part of the programming code. The addresses had to be in order, but you could skip ones you didn't need, or decided not to use. You can see how it got its name with this kind of ad-hoc arrangement! However, the one improvement was that actual words could be used instead of codes. This introduced the need for another program, called a compiler, to come along after you write the code and turn the words into the hexadecimal and/or binary instructions that the computer can execute.

The first real structure came with the invention of - you guessed it - 'structured' code. The new idea here was to cut up the spaghetti into logical segments. Each segment, also known as a 'routine' or 'subroutine' was given a name, usually one that described what that portion of the instructions did. For instance, you might have a routine to display text on the screen, and another one to ask the user for input. In this way, instructions were organized by function, rather than being all thrown together in one big monolithic mess. In addition, this introduced the idea of parameters. In the case of a routine that displayed text on the screen, a parameter could be the text to be displayed. Whenever you invoke or call the routine (so that it performs the instructions contained therein) these parameters are given. This way, you need not reinvent the wheel and write the same code over and over each time you want to display text on the screen. You just call the routine that does it for you, and pass the text you want displayed as a parameter. This is also known as functional or procedural programming, because it is organized by function (routines are also known as functions or procedures).

This phase lasted quite a while until the next revolution: object-oriented programming. This provided not only further structure, but also several important, new concepts that would change the way programming was thought of, and what it was capable of doing. These powerful new tools created quite a stir and made computer code far more elegant and interesting. The three primary concepts are: encapsulation, inheritance, and polymorphism. All three fall under the umbrella term "abstraction" since they all give us new ways to represent abstract ideas (or objects) such as bank accounts, transactions, and other such things managed by computers, using computer code. This means the code is structured in a way that more accurately represents these objects, and therefore, more accurately handles and manages them.

Encapsulation is the idea of the black box. Think of a car engine, for instance. Many people haven't the foggiest notion of how a combustion engine works (perhaps a better example is how an airplane stays up in the air, since even fewer seem to understand that secret). However, that isn't a very big problem, unless of course, your car breaks down (or the airplane crashes). As you drive the car, it doesn't (and shouldn't) concern you what happens when you press the gas pedal, or the brakes. When you turn the steering wheel, you don't care how the engine responds and decides which way to turn the car. It doesn't matter to you, because it's a black box system. As long as it does its job, the black box can remain a mystery, and there is absolutely no problem with that.

We can do precisely this same thing with computer software. We can now write a portion of code that can interact in a well-defined way (known as an API) with other code. We can bundle up the code we wrote, sell it to someone else, and then they can write code on top of it that turns the steering wheel and pushes the pedals, so to speak. They don't care how our code works; it just works. When they turn the steering wheel, the car turns, and when they push the gas pedal, the car moves forward.

Encapsulation is accomplished in the software world by defining the scope of program elements. The scope tells us where in the program (and outside) we can see those elements. Functions, as mentioned earlier, are one such element. Stored data is the other primary element. We can define something as public (viewable by everyone, everywhere) or private (viewable only within the black box). This allows us to share the information we want, and protect the information that shouldn't be shared within the black box.

Inheritance is a lot simpler; you are already familiar with one form of it - genetics. In programming, inheritance works exactly the same way. We can write generic code that acts like an Animal - it has behaviors (defined by functions) such as speak, play, sleep, and so on. Then, we can write more specific code that acts like a Dog, but inherits the more generic aspects that it shares with all Animals. All animals can speak, but when a Dog speaks, the behavior can be defined specifically as "Bark." We could then write a Cat which inherits this same behavior (speaking) but again, when we invoke the Cat's 'speak' function, instead we receive a "Meow" in response.

Finally, polymorphism is the most complex of the three. It's quite a difficult concept to wrap your mind around, even if you're a programmer. However, the simplest way to explain it was already done in the last paragraph. It is closely related to inheritance. When a Cat speaks and we hear a "Meow" then a Dog speaks and we hear a "Bark," this is an example of polymorphism. In either case, we are simply invoking the inherited "speak" function - but the behavior is different depending on the subclass (Cat or Dog). This is polymorphism - the ability to define a specific response to a generic behavior.

In essence, these abstractions give us two dimensions in which to program. With structured design, a function always does the same thing every time you call it. With object-oriented design, polymorphism gives us a different response based on both the function/behavior and the object/idea. Invoking the same function on a different object normally produces different results.

Now, prepare your mind for some extreme warping - we are now in the age of subject-oriented programming, where we can wield three such dimensions. The result or response we get from a function can now be defined by the name of the function, the object on which it is invoked, and the subject related to the invocation. For instance, my Dog might have a different bark depending on whether he was happy to see me, or whether he was trying to fend off an intruder. This constitutes the subject, or aspect, in which the behavior is invoked.

Aspect-oriented programming is very similar to subject-oriented, but to spare your mind further warpage, I won't go into any detail on the differences between the two. Instead, I will just say that programming has come a long way from using hexadecimal codes and command line interfaces. We now have the power to determine the software's behavior based on the desired function, the object performing the action, and the context in which the interaction occurs. This gives incredible potential even just for artificial intelligence. Computer code that can update and edit itself is now just around the corner.

And yet, DNA has been doing exactly that for thousands of years. Is that something that occurred by random chance? I think it's about as likely as computers assembling and programming themselves out of thin air. It takes a mind more intelligent than a computer to design and build a computer. By the same token, it takes a mind more intelligent than a human mind to create such an incomprehensibly vast universe, and to populate it with beings whose bodies themselves contain technology far more advanced than computers; least of all, the human mind itself.