Downwardly Scalable Systems

David N. Welton

davidw@dedasys.com

2004-11-14

A lot of thought has been dedicated to scalability in computer systems. However, outside of the embedded systems arena, most of this effort has gone into making systems ever larger and faster. I would like to take the opposite approach, and discuss the implications of programming languages that "scale down". I choose programming languages because it's a subject I take a great deal of interest in, but I believe that the basic ideas here are applicable to many complex systems that require human interaction.

Good systems should be able to scale down as well as up. They should run on slower computers that don't have as much memory or disk storage as the latest models. Likewise, from the human point of view, downwardly scalable systems should also be small enough to learn and use without being an expert programmer. It's not always possible to have all of these things. Engineering is often the art of balancing several compromises, after all, and at times, it's necessary to add computing power in order to attain simplicity. However, it is always a good idea to keep all these targets in mind, even if design dictates that one or the other of them may be less important.

Naturally, we can't forget the "scalability" part of the equation while focusing on "simple". It's not that hard to make something small and easy to use. The trick is that it's also got to be extensible, in order to grow. The system should be easy to pick up, but it should also be easy to add to, and should also provide tools to modularize and otherwise compartmentalize the growing system in order to not end up with what is known in technical terms as a "godawful mess". And of course it should still be fun to work with for the more experienced programmer.

Another part of the balancing act is that often times "simple" equates to hidden complexity. For example programming languages like Tcl or Python are "simpler" than C, but this is a result of the implementation hiding a lot of the complexity from the programmer. In this case, scaling down from a human point of view conflicts with scaling down resource usage to some degree, in that these languages require a bigger runtime, and more processor power to accomplish similar tasks.

Why scale down?

Systems that scale down are not just nice in theory, but have many benefits. To start with, they have the potential to create more value. By being accessible to people with less experience and talent, they allow more people to get more things done than a system requiring more advanced skills would. The nicest tool in the world is of no use to you if cannot figure out how make use of it in the time you have. You may object, saying that not everyone should be able to use every tool, and of course that's true. We don't all expect to be able to fly airplanes, and yet they are still valuable to us. The point is, however, that where two systems are capable of doing the same job equally well, the more accessible tool is more valuable in that more people are productive with it.

It's especially important to realize that in some cases, this is more than just a matter of degree - there is actually a cutoff point, meaning that some people will be able to do no work with a tool that is too difficult. So to these people, the complex, hard to use option is simply not an option at all!

Of course, having more users isn't necessarily a benefit in and of itself, but if you have a reasonably good user community, it often is [1].

Disruptive Technologies

In some ways, systems that scale down may be winners in the long term even if they don't scale up as well as others. Consider the definition of "disruptive technology":

A disruptive technology is a new technological innovation, product, or service that eventually overturns the existing dominant technology in the market, despite the fact that the disruptive technology is both radically different than the leading technology and that it often initially performs worse than the leading technology according to existing measures of performance. [2]

In short: when the programming technology that scales down is "good enough", it may open up a field of programming to people who previously were not able to accomplish anything at all - and give many more people the chance to write "good enough" code much faster.

Perhaps experienced programmers are grumbling about "the right tool for the job", and complaining about putting sharp tools in the hands of novices.

To a degree, they're right. It's best to use hammers for nails, and saws to cut boards, and to know something about them before taking them to a board. Computer systems, especially programming languages, are very complex tools though, and take a lot longer to learn for many people than learning to hit nails with a hammer. What this means is that many people find it valuable to be able to do more things with the tools they know how to use. Maybe the tool isn't perfect, but if it does a reasonable job of solving the problem at hand, it's probably a net gain to be able to write the code in the first place. For example, I once did some work for a client who was, at heart, a marketing guy who came up with a clever idea for a product. He wrote the initial code that made it work, and...frankly, it was pretty obvious that he was a marketing guy rather than a programmer. But - and this is crucial - he was able to make it work with the scripting language he used. If he'd had to use something like Java or C that was over his head, he might not have got his product to the point where he was making enough money to hire me to clean up his code.

Scaling down doesn't necessarily equate to a disruptive technology, of course. In many cases it's easy to rejig things just a bit, or create a better, clearer interface without revolutionizing either your product or the market in which it resides. Truly disruptive technologies often create new markets where none existed.

"Case Studies"

Let's look at some real-world examples:

Dr. John Ousterhout, author of the Tcl programming language and the Tk GUI toolkit realized that scripting languages were a winning proposition early on, creating a revolutionary way to easily write graphical applications. This made Tcl and Tk a big success, and they continue to be very widely used, long after complex, proprietary rivals such as Motif have fallen by the wayside. Tcl has had some struggles with scaling up, but in general hasn't managed too badly. Perhaps Tk isn't well suited to writing a huge, complex application like an office suite, however the speed of a scripting language is perfectly adequate for many GUI's. After all, the time it takes you to move the mouse and click is an eternity in computer cycles.

PHP is another example. While PHP is not a particularly elegant system, and suffers from some flaws in its approach to simplicity (it's too tied to the web world, which has limited its uptake for other uses), it has done a phenomenal job of making dynamic web programming available to many people who would otherwise not be able to, or would have to spend much more time to make their code work. "But what about all the bad PHP code out there?!". Sure - it's there, but consider that the people doing the ugly programming are almost certainly not trained programmers. Perhaps they are doctors, businessmen, artists with deep knowledge of other fields. PHP is therefore the tool that, through its approachability, makes it possible for them to do something that they otherwise could not do. If they are successful in their endeavors, maybe they will attract "real" programmers who will help them out either because it's a successful business venture, or because it's a popular open source idea. In any case, they are better off with an ugly program they wrote to do the job than an elegant programming language that they can't make heads nor tails of.

Contrast these languages with Java. Java isn't a bad language, particularly. It's easier than C in some ways, and certainly safer for the average programmer, who has to worry less about memory issues, walking off then end of arrays, and things of that ilk that in C, not only crash the system, but may create security risks. Java is fairly resource intensive - it requires lots of disk space, memory. Worse, it's not something that is easy to pick up quickly for the 'average guy'. It has a verbose syntax that is unpleasant to use if you don't know your tools well, or even if you just want to whip up something quickly. The target for "downwardly scalable languages" that we're talking about are the individuals who, due to their lack of experience, are more likely to have bad tools than a veteran programmer who can play emacs like a piano. Java also makes it difficult to do easy things. To even get started, you have to have some notions of object oriented programming, you have to split your code up into lots of little files that must be properly named, and you must have a few ideas about packages to even print something to the screen, with System.out.println("hello world"); Of course, if you are writing thousands upon thousands of lines of code, some of these language features that initially seem like annoyances turn into advantages, and would be sensible rules to follow for any programming team wishing to keep their sanity. While it's fine to say "it just wasn't meant for that", perhaps Java could have been made easier for the casual user. Java scales up to projects with multiple teams and many programmers better than other systems do. So they have done something right, but haven't been able (or willing) to make the system downwardly scalable.

Ok, but how?

Making systems that are easy to use is an art in and of itself, and high quality code doesn't necessarily translate into something that automatically scales down. Here are some ideas on how to make your product scale down.

Make it small, and make it easy to extend. This way, you don't have a lot of luggage to carry around, and yet you can extend the system to do more things later. The C programming language is a pretty good example of this. The Scheme language got the small part right, but until more recently has had trouble with the 'extend it easily' bit.

Make it simple and coherent. Don't give it too many fancy rules. Make it internally coherent in the way it's used, so that people can make reasonable assumptions when they see a new extension or library. They will see patterns in your system which will enhance their comprehension. Tcl and Python show these qualities (despite having grown some warts over time). C++ and Perl tend toward the opposite pole: big and complex, with many rules to remember. You can always choose to use a subset, but when you think about communicating functionality to other people, perhaps in terms of source code, it means that in the wider world, you can't stick to a simpler set of rules to keep in mind.

Make it do something "out of the box". It should be easy to get set up and doing productive things with the system. Complex configurations with thousands of options are useless if it's impossible to get a basic configuration working. The Apache web server requires little configuration to make it serve web pages, so while it is in some ways complex (configuring it from scratch might prove quite difficult, infact), it scales down by being useful right away.

Given several options, make the common one the default, and the others a possibility. As programmers, we tend to think that we should give the user all kinds of clever options. However, most people are going to use one of the options most of the time, so in reality, it's often best to make that easy, and add a means of performing the less frequently used options when they are desired. Tcl, when it gets things right, does a great job of this. For instance, its socket command is very easy to use. The default is to open a socket to a given hostname and port. Then, if you need to configure things further, such as setting the character encoding, blocking or non-blocking, and so forth, Tcl provides a command to configure options. So people who just want a socket get it very simply, with no clutter: set sk [socket www.google.com 80]

Use simple, open protocols. If you have to transmit data, or have configuration files, make them easy to understand, and simple to write - by hand or via other programs. This lets people interact with your system in new and interesting ways, as well as keeping it accessible to the newcomer.

Always keep on eye on the future, when you may need to scale up, to large groups of programmers, for work that requires speed and the ability to work with large quantities of data. Design the system so that scaling up is easy, or at least possible.

Conclusions

Naturally, it's not always a good idea to scale down. There are systems that really do need to be as fast as possible, or to deal with very complex problems, and trying to broaden the user base is a secondary consideration compared with these other goals. However, in many cases these goals are not incompatible, and the simplicity and clarity involved in scaling down will make for a larger, more vibrant market for your product.

References