1. Entwork

There are two ways we could try pitch at a basic definition of programming. We can say it is :

  1. programming a computer; or it is
  2. writing a program.

This is an interesting starting point because, while both of these definitions appear to be more or less tautological, in fact neither of them is really true. Not false, but not really true.

Take a very simple program. The UI consists of a single button that, when pressed, prints a document called ‘foo’. Here is the entire code for the program, written in an imaginary language called fop (‘foo-only-printer’) that consists entirely of this one command.

fop::print!

When the foo document successfully prints, it cannot be denied that we have programmed the computer and have written a program. But. How did our tiny ‘one-liner’ actually do all that? How did the computer we just programmed know how to do what it just did — to print a document?

The answer, of course, is that we are standing on the shoulders of giants. We have written a program that sits on top of a host of other programs. In other words, we did write a program, but ours was a little program, as little as a program can possibly be. The giants wrote all the big bits, all the good stuff. The code that actually does stuff.

For our UI we used a designer to plunk a button on our main screen. We also wrote the fop code (fop::print!) that runs when the button is clicked. Our click handler.

That’s what we did.

Here’s (very very roughly) what the giants of the screen code did. Our screen is a rectangular region (a ‘window’) within the main display. The main display is in itself more or less dumb. It paints pictures. It is filled with regions just like our own screen — with ‘windows’. Our monitor refreshes the display maybe sixty times a second and at each refresh each window is painted at its current pixel position. As the user, say, moves windows around the screen, each refresh updates each window to its new position, so it appears to move. Of course, one window can cover another, so the giants have to make sure in their code that hidden regions are hidden and visible ones stay seen. Within each window, or rectangular region, there is a complex layout of controls, our button just for example. These need to be painted onto the display, each in its current state. Buttons, for example, ought to look different when they are pressed.

Worse yet for the giants, windows have interrelationships with each other. A program (like our ‘foo’ one) is a process and each window in it belongs to that process. Even this one-liner foo doc program pops up a window informing the user all is well after a successful print. Even ‘Foo’, then, has a main window and a secondary window. Other more complex programs will have many more windows. The giants must ensure that, when a process (that is, a program) exits (that is, the program is shut down) all its windows correctly disappear. Finally, user input has to be tracked (mouse or keyboard or, nowadays, fingers). The system needs to know — and right now — what window what user input is directed at. Each window must send a message as soon as it has anything to react to. “I’m clicked!”, says our foo print button. Why then, fop::print! replies our little program.

This is kernel stuff that lies deep within the heart of the computer operating system. The kernel though needs much more than a dumb windowing display. Windows are sparked off by processes and the giants need to manage these. Processes can launch lightweight versions of themselves called threads. Managing processes and their threads is a complex task.

Windows and processes are nothing without memory. Processes must be loaded into memory as soon as they are started, and the system must allocate each program (that is, its root process) a set amount of memory (that is, within the available RAM). In turn, RAM is merely short-term memory. What use is a computer that forgets everything? A running program exists in RAM, but the source code needs to be hard-stored, usually on a HDD. The giants have to include that in their shuffle, the shuffle between window, process, quick-memory and long-memory.

Finally, let us mention peripherals that exist outside the computer box, and in particular draw attention to the printer which, after all, is what our little foo program is all about. Printers come in a whole array of shapes and sizes. To deal with each on an individual basis would require an enormous amount of unnecessary effort. So the giants devised a generic blueprint called a driver. To the system all drivers have the same shape. It is the properties that differ from implementation to implementation. Each printer has a driver written for it and the system interfaces with the driver, not the printer itself.

In this foo-scenario, of course, the real action takes place beyond even the system printer driver. The driver sends the print instructions and data (that is, the foo document) and the printer carries out the instructions on the data. The actual code-to-print resides in the printer itself. It is this code, the sleeping giant beyond even the giants of the system, that makes the foo document print.

Our little one-liner, then, is a program within a program that makes a call to the peripheral program that actually does the printing. We therefore cannot really say to ourself that we have programmed a computer or that we have written a program, though in a sense these statements are true. If we do claim we’ve written the program that prints the doc, we might as well say we have built a house just because we rang its doorbell. For that is our foo program. It rings the bell that summons the giant’s code that wakes the sleeping peripheral giant.

Frameworks

So, that is the system; the peripheral. Developers, generally, do not do close encounters of such a kind. In between the system and the developer there lies the framework. These days, you would not use a fop method but a fop framework to take care of printing stuff for you. If you used the new ffs framework (said to stand for ‘foo framework services’), you would write something like this :

#foosing fooprint

// Print out the Foo doc.
FooDoc foodoc = few FooDoc()!
foodoc.prefoomat()!
foodoc.confoogurePrinter("Foo!")!
ifoo (foodoc.sendToPrinter() == fue) {
    infoom("The document was printed successfoolly.")!
    }

Now the path to the giants runs basically like this :

your-code > framework (ffs) > system > peripheral

Another layer of giants — the framework giants — has been interpolated! In fact, these days, the monolithic do-it-all framework seems to be in retreat to be replaced by patchworks of littler entwork (as the old Anglo-Saxons called the work of giants). Here we have DI (‘dependency injection’), plugins, services (including microservices), containers, libraries, components, etc. What used to be a whole body is now a composite of artificial limbs and iron lungs and glass eyes. The giants have shrunk! Still, all the same, these little patches of entwork do in the end add up to the equivalent of a framework.

So we see that the framework sits on the shoulders of the system and the modern developer sits on the shoulders of the framework. Programming is therefore not writing a program or programming a computer, it is interpolating code into a system. Be it Cloud or API or Android or PC or .NET Core or any of the other jargons.

I think, then, that programming is not to create the garden, it is to lay a flower bed, or plant a peony. For some — the support team — it more of a case of digging up weeds. The computer does not run your program, your program runs on the computer placed on top of the entwork.

That is what a programmer of a computer does and what programming a computer is. In the next chapter, however, we will see that even the notion of ‘programming a computer’ is an increasingly outmoded one, for nowadays a single program runs on many computers. In fact it does not so much run on your computer, rather it arrives at your computer.


Posted

in

by

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *