Programming for Information Architects

Written by: Andrew Otwell
“You might have more in common with programmers than you think. Both programming and IA are mindsets oriented towards abstraction. We both generally want to find patterns and rules that describe and predict.”Have you ever been sitting in a meeting that takes a sudden turn for the incomprehensible? “I’ll subclass the DataProvider class to add an array of names, then you can override the sort method on that.” Yep, that’s a programmer talking. Nothing to do with information architecture, right? Well, not really.

You might have more in common with programmers than you think. Both programming and IA are mindsets oriented towards abstraction. We both generally want to find patterns and rules that describe and predict. We both appreciate the value of modular parts and components. We both are often concerned with handling structured content and metadata. But more often than not, IAs don’t know what’s going on with code. In this article, I’ll introduce you to some of the basic building blocks of programming.

I should make it clear right away that I’m not proposing a new method of doing IA or a better way of thinking about content, users, or context. But a better understanding of the programmers’ work might inspire your own. It’s important to focus on users during research and design, but to explain our ideas, IAs need to be able to create design documents that show some awareness of systems, programs, and other nuts and bolts. And of course, shared vocabularies and common understandings can go a long way in fostering better team communication.

What is programming?
Programming means giving instructions to a computer in a language it understands. It’s design in that it is organized, creative problem-solving. Like IA, it’s ideally both an art and a craft, combining learned techniques, creativity and an understanding of material restrictions.

The actual act of programming is almost always writing text, and programs are often written as one or more (often many more) text files and some associated assets, like images. (It’s only when the program is compiled that it’s bundled up into a software application, like the double-clickable software that sits on your desktop. Programs in some languages, like PHP or Perl, aren’t ever compiled into single entities, and always remain text files. Web-based applications are good examples of applications that aren’t compiled.) Except for some programming software that lets you program by dragging and dropping or filling out dialog boxes, coding usually means writing lines of text statements that together make up sets of rules and instructions for how a program should work.

There are “high-level” languages like Java or Perl which let programmers write in an English-like syntax, and “low-level” languages like machine language that aren’t really meant for humans to interact with. A Java programmer relies on several layers of interpretation and translation software to translate her Java instructions into an efficient low-level machine language optimized for the computer’s abilities and needs; in other words, silicon chips cannot flip bits on and off by directly carrying out Java code. Programming languages are, in fact, layers of increasing abstraction built upon each other, each written on top of lower-level languages: Flash’s ActionScript language is part of a program written in C++, which itself is a language written in Assembly language.

But the basic nuts and bolts of most contemporary high-level programming languages aren’t really that different. The rest of this article will look at these common building blocks: variables, conditional structures, loops and functions. In the next article, we’ll look at Object-Oriented Programming, a design and coding methodology used in most projects.

Variables
Like IA work, the problems programmers solve tend to be focused on how to represent and access data in efficient, scalable ways, and how to break a problem into its component parts and instructions. This is a process of abstraction, and the fundamental component of it is the variable.
It’s a lot easier to worry about data that changes, like my age, or the set of books currently in my Amazon shopping cart, by giving those concepts defined names, like myAge or itemsInCart. These names are variables. Variables are named containers for data; they’re like boxes with labels written on the outside. By putting a piece of data inside the box and referring to it by the label, the programmer has created an abstraction of that data which is easy to manipulate with code. You can also think of a variable as a placeholder for data, just like a box on a wireframe can be a placeholder for the information that will eventually appear there.

A programmer can create a variable pretty much any time he wants, simply by declaring it exists. This line of code creates a variable called myName with the value of “Andrew”:

      myName = “Andrew”;

Your name probably isn’t the same as mine, so this variable, myName, lets the programmer write code that handles any name. The variable could have any name, although a descriptive name like “myName” is more explanatory and useful than “x.” There are certain words that are not allowed to be used as variable names in each programming language (“new” is a common one), but naming is mostly a matter of personal preference and informal standards among collaborators. Variables are amazingly flexible things; you can put strings of text (like “Boxes & Arrows”), numbers, lists of things (usually called Arrays), or even complicated types of structured data into them.

Whenever the programmer wants to use the value in the variable, he simply calls it by its name:

      print(myName);

That line of code uses a function to print whatever the current value of myName is. (Let’s assume for now that “printing” is a built-in function of this programming language. There is more on functions below.) Again, this is a type of abstraction. This line of code will print the current value of myName, no matter what name’s been put in the variable.

Conditional structures
Conditional structures (sometimes called branching structures) are chunks of code that can examine a situation and determine how to respond to it. Assessing conditions and reacting appropriately is what makes software flexible and powerful.

Conditional structures have lots of obvious parallels in IA work, since this is how people think as well as computers: ifI have the time, then I’ll call my parents; if I’m signed in as a member, then I can access the archived articles; if the gas gauge in my car is lower than a quarter-tank AND if I have some cash AND if I’ll still have enough money left over for lunch, then I’ll get some fuel.

Checking a condition and responding to it is typically done with an if/then statement, and most programming languages let you write these in pretty much plain English.

Here, an if/then conditional statement checks to see if the variable myAge is greater than or equal to 18, and prints a message if it is:

      if (myAge >= 18) then {
        print (“You’re old enough to vote!”);
      }

Why is the “myAge >= 18” inside parentheses? That’s the condition that’s checked when the program arrives at that line of code. If the condition evaluates as “true,” (here, if myAge is equal to or greater than 18, the overall condition is true) the computer will carry out the instructions between the { } brackets, otherwise those statements are ignored and the program skips to the next line of code after the closing bracket.

Loops
Computers are good at doing things fast. They’re really good at doing the same thing, or the same thing with slight predictable variations each time, over and over again. You might not enjoy searching through a list of ten thousand names looking for a particular one, but your computer will do it happily and quickly, thanks to the power of loops. Whenever a program needs to count a quantity, or sort things, or find something specific in a mass of information, it relies on some sort of loop.

Programming languages usually provide several ways to set up loops depending on what the programmer needs to do. Usually this means an action can be carried out a specific number of times or carried out repeatedly as long as a certain condition exists.

It’s common to use a “counter” variable to set up loops that run a specific number of times. Here’s an example of a “for” loop:

      for (n=1; n <= 10; n++) {         print(“The current value of n is” n);       } Let’s read this closely. “for” is a keyword that means “do something for this many times.” The three statements separated by semicolons inside the parentheses are the instructions for how to carry out the loop.

  1. First, we’re creating a counter variable called n with an initial value of 1 (n=1;). The counter will tell us where we are in the loop.
  2. We want the loop to keep running as long as n is less than or equal to 10 (n <= 10;).
  3. With each pass through the loop, we increment n by 1 using a shorthand (n++;) that means “add one to the current value of n.” (By the way, this shorthand is where the C++ language gets its name. It’s based on the older C programming language, but it’s “c+1”.)

Just like in conditional structures, the brackets { } contain instructions that are carried out as long as the stated condition is true, in this case as long as n is less than or equal to 10. Here we just print the current value of n. The key is that n will be different each time through the loop. The result would look like this:

The current value of n is 1
The current value of n is 2

The current value of n is 9
The current value of n is 10

Why not just type ten single print() commands and get the identical result? In this case we knew how many times we wanted to loop, but what if our code had to handle a set of search results? How many results are there? There’s no way to know in advance. A search could result in 1, 37, or any number of hits. To display and format those results on the screen, a programmer must use a loop. Why? Because the instructions for handling one search result are the same as those for five, or fifty, or an unknown number, it’s just a question of how many times they’re carried out. Code must be able to handle both predictable and unpredictable situations, or else it will fail. Let’s improve our code with a variable called “totalNumber.”:

        for(n=1; n < totalNumber; n++)           print (“The current value of n is” n);         } Our code will still just print a list of numbers, but now it can handle whatever amount we throw at it as long as we set the variable totalNumber beforehand. We’ve actually done something very powerful here by using abstraction. We could set totalNumber to the number of times the user clicks the mouse in 5 seconds, or the digit the user types in a form field, or the number of results in a search query. Since we’ve successfully abstracted our code by removing the specific value of 10, it doesn’t matter what totalNumber is. You should see a clear parallel with common information architecture components in loops. Besides lists of search results, loops show up when you list “the five most recent entries in the Resources category,” or “all authors in the system, grouped by Department,” or just “links to our most popular articles.” Object-Oriented Programming
Variables, conditions, and loops are the basic building blocks of a programming language. You could write a simple program using just these, although it would be pretty inflexible, and it would be very hard to translate any real-world program requirements into code. Luckily in the early 1960’s some Norwegian programmers addressed these problems by inventing object-oriented programming.

What is Object-Oriented Programming?
Object-Oriented Programming (OOP) isn’t a programming language, it’s an approach to designing and building software. Before object-oriented programming, many programs were written as systematic sets of procedural instructions, often with lots of small subsections. Everything depended on everything else, so problems could creep in anywhere and have far-reaching consequences. This approach didn’t scale well, and as software got more complex, a new methodology was created.

Object-oriented programming turns out to be a very reasonable, common sense way of thinking about programming problems, because it breaks those problems down into their component parts and sets out rules for how those components can interact. Using code that’s built out of components means it’s easier to isolate problems and to reuse working components in other situations. If you’ve ever designed a page out of architectural components (like category lists, search box widgets, or “most popular topics” lists), you know how effective this approach can be.

How is it done?
Design using OOP is actually a lot like a top-down IA process: programmers break a large problem down into smaller discrete parts and arrange those parts in a parent-child hierarchy. Each component has a few specialized abilities and probably knows how to communicate with a few other objects in the system. Think about your car as an example: there’s an engine, an electrical system, a steering system, and several others. Your car’s exhaust system and electrical system don’t really have too much to do with each other, though they work together in an overall way to make the car run. Each of these interacting components is itself made up of smaller, replaceable components, like an ignition switch or a muffler. Some of these smaller components are themselves made up of standardized component parts bolted or wired together. This is the essence of OOP: a hierarchical system of independent component objects communicating though predictable ways to achieve an overall goal.

Programmers create classes to define each of the parts of the hierarchy. A class definition is a template from which individual objects can be generated. Typically not much more than a page or so of code, each class definition describes all the things a type of object knows how to do and the data it needs to carry out its functions.

Properties
To write a class definition for an Engine, for instance, we would first identify the crucial properties an engine has, such as having some number of cylinders, some amount of horsepower, running on either unleaded or diesel fuel, and so on.

Notice that our Engine class didn’t describe a specific “six-cylinder, 250 horsepower, unleaded fuel, Ford engine.” That would be one possible object that our class definition would permit. It would also permit a “four-cylinder, 130 horsepower, unleaded fuel, Toyota engine.” The power of the class definition is that it allows a programmer to create any number of objects with lots of variations. It’s only when an object is created (or instantiated) with these kinds of specific details that the programmer has something to work with.

Creating an object from an existing class definition is done by simply creating a variable:

        var fordEngine = new Engine(6, 250, “unleaded”);

I’m glossing over some details here, but that line of code would create a variable named fordEngine that is a new object derived from the Engine class, with 6 cylinders, 250 horsepower, and using unleaded fuel. “new” is a command meaning “create a new object.”

Functions
So far, objects aren’t that different from the content objects you might define as an IA. For example, a document might have properties like Author Name, Last Modified Date, Keywords, or User Rating. But full-blown objects aren’t just a collection of properties like “horsepower” or “fuel type.” Their real power is that they also know how to do things. A phone “knows” how to ring when it gets an incoming call, a CD player “knows” how to play, stop, fast-forward, and pause discs in response to buttons on the remote control. A programmer would call these behaviors functions (or methods) of the phone and CD player objects. (You might think of properties as nouns and adjectives, and functions as verbs.) The functions in our Engine class definition would describe in detail the actions that all engines can perform, such as starting, stopping, or responding to changes in the amount of gasoline.

Functions are small sections of code that usually describe a single action. Like variables, they’re named, so print(), sortItems(), or cancelYesterdaysOrderList() could all be functions. The parentheses are used to indicate these are functions, not variable names. Functions can be used (or called) from other places in your program by referring to them by name. For instance, you could define a reusable function for the Engine class called start() that might handle the details of starting an engine. This function has comments instead of real code:

        function start() {
            // all the actual details of starting would be
            // spelled out here, like specifying how electricity
            // goes from the battery to the starter motor
        }

Once defined, you could call your start() function on any Engine object and they’ll all work the same way. Typically, a function of an object is called by appending it after the object’s name and a dot. We’ll use our fordEngine object:

        fordEngine.start();

Functions can also accept values to work with called parameters. Parameters allow functions to work as general-purpose tools that take some raw materials, perform some predictable action on them, and hand back a result in a predetermined form. For our Engine class, regulating the current speed is a function that depends on how much gas the driver’s giving:

        function regulateSpeed(gasAmount) {
          newEngineSpeed = currentEngineSpeed + gasAmount;
        }

Ok, that’s a bit oversimplified, but you get the point. This function regulateSpeed expects a value (gasAmount) to work with and adjusts the speed of the Engine based on that number. You’d call this function just like the start() function, but with some number for gasAmount:

        fordEngine.regulateSpeed(5.13);

There are a couple more key ideas to understand about OOP: inheritance and encapsulation.

Inheritance
In any object-oriented system, some classes will be variations on parent classes in a top-down hierarchy. This is called inheritance. The concept of inheritance means that a programmer can create a child class that adds to the abilities of a parent class without affecting existing abilities or data the child learned from its parent. In other words, child objects are born knowing everything their parents know, and more.

That sounds complex, but we can easily state this in a way that will be familiar to IAs. Imagine some information with a general class of content types called “Product Documents” that are different from “Forms” and “Presentations.” “Product Documents” might have metadata properties associated with them that might not be relevant for “Forms” such as “product name,” “author”, “department”, “last updated date” or others.

Perhaps each Product Document could be “subclassed” into more specific sub-types, such as “Technical Documents,” “White Papers” and “Marketing Reports.” As “children” of the Product Document type, these all inherit their parent’s metadata fields, but might also in addition specify metadata fields exclusive to their own uses. For example, Technical Documents might need to keep track of an associated “version number” field. To an IA, these documents are content types with metadata, organized in a meaningful hierarchy. To a programmer, these are custom data types and good candidates for class definitions. They’re objects, each with a set of properties, hierarchically organized according to the principle of inheritance. One big difference is that information architects don’t typically add functions to content types; what does a Product Document “know” how to do, for example?

Encapsulation
Objects are “black boxes.” Do you know how your digital clock works inside? Neither do I, and why should we? It’s basically an enclosed unit that hides its inner workings and exposes a few useful functions to me in an interface, such as the buttons for setting the time and turning the alarm on and off. As long as it keeps time and wakes me up, I don’t need to know much else about it. The concept of encapsulation says that objects should also be “black boxes” that hide the details of how they work, while exposing a few functions in an interface. Since they’re not physical objects, their interfaces aren’t buttons and dials, but specific “public” functions that are available for other programmers and objects to interact with.

If a programmer wants to put a clock into a piece of software, he doesn’t spend time writing a bunch of logic to add 60-second units into minutes and 60-minute units into hours. Instead, he would use an existing object that provided a simple interface to the most useful functions such as showCurrentTime(), setAlarmTime(), snoozeButton() and so on. To the programmer, these functions work exactly like a physical interface. I don’t really know what happens when I smash the Snooze button on my clock except that it stops ringing for 10 minutes. The principle of encapsulation means that the programmer using the digital clock object can confidently write code that uses its snoozeButton() function, without worrying about how that function is implemented.

Conclusion
There’s sometimes a tendency among IAs and designers in general to distance ourselves from the details of programming work. But as we’ve seen, there’s no reason for it to be puzzling or mysterious. I hope this article has cleared up at least some of the terms used in programming and introduced you to some of the basics. We’ve looked at variables, conditional structures, loops, and objects, and seen that these concepts have direct parallels in information architecture. Maybe you’re not ready to take on coding your next project yourself, but I hope you’re better equipped for your next meeting with a programmer.


Andrew Otwell is an information architect and interaction designer living in Austin, Texas. Andrew earned a Master’s degree in Art History at the University of Texas, where he studied Surrealist and Dada art. In 1997, he finally admitted his real interests were with digital design and the web, and so left academia. Fortunately, it turned out that the analysis of visual culture and the analysis of information for the web weren’t so very incompatible, so Andrew found himself doing and teaching information architecture and interaction design in Austin and Berlin. His website is heyotwell.com