Universal Architecture

It seems that every somewhat-seasoned software architect I talk to has some concept of a “universal architecture”, a term whose definition will become clear after I give an example. For example, at NetDevil on the LEGO project our universal architecture was “interfaces”; that is, every major component of the program was a singleton which implemented this interface base class. Instead of these singletons calling methods on each other, instead they would pass “messages” (structs which were upcast to a generic message base) to an “interface manager” which then delegated them to whichever interface they belonged to, where they then had to be downcast. You’d have to see it to believe it, but it was essentially a poorly-typed equivalent to ordinary method calling.

And the quality of this architecture that makes me write about it today is the fact that it has nothing to do with the game we were writing, or even games in general. I can imagine this engineer saying “every program I write fits into this architecture”. I consider that statement to be the same as the axiom of limitation of size in NBG set theory—if you can say this about an architecture, then it is a worthless architecture (with some exceptions). And here’s why:

There’s a reason that they call the languages we use to write software general-purpose programming languages. They’re supposed to have all the language features you need to write any type of program, and none left over that are only suited to certain types of programs (this is an ideal, but most languages come pretty close). Therefore, any “universal architecture” into which every program fits is a witness to a flaw in the language you are using. But language designers are usually pretty good—they think of an awful lot of patterns and make sure that they fit into the language. So it’s very likely that by using a universal architecture you are either trying to stuff programs which don’t actually fit into it, creating lots of unnecessary engineering problems to cram it in, or you are just duplicating an already existing language feature (as was the case above).

There are some exceptions on both sides of the coin. For example, in C you might have a universal architecture, because C isn’t really a complete language as I see it. You might add an architecture for object-oriented inheritance which has some nice features using macros and whatnot. But then you should just be using C++; they already did it, and they did it pretty well (considering what they had to work with—C :-). Also, I think it’s reasonable for a universal architecture to handle garbage collection, because that’s a nice thing to have for all programs. And most general purpose programming languages have garbage collection these days. So really it’s the same coin: you’re using a language with missing features.

So the next time you write a universal architecture, ask yourself the question “what language feature would solve the problem that this architecture is solving?”. If none, then toss your architecture, and make one more specific to the problem you’re trying to solve right then (otherwise you’ll probably end up soft coding to some extent). If so, then hunt for a language which has that feature; there probably is one. If you can’t find one, look at Perl 6, the language with all possible features (it probably has a library routine which is your program already written—unfortunately, Perl 6 is not completely implemented yet, so join the project! :-). But seriously, there probably is some language with that feature. There may be other reasons that that language is unsuitable, but “I don’t know it” is not really a good reason. If there is a real reason that language is unsuitable, go ahead and design your architecture, but learn about the language that has the feature so you can benefit from the research done while developing that language.

Preach, preach, preach. Really it all comes back to my architectural philosophy: you have to identify the “fundamental algebra” of your program. What is the identifying feature of this problem, the feature that makes its solution nonroutine, the feature that makes me want to design an architecture instead of just using one? As soon as I started thinking in terms of this, my programming productivity skyrocketed, because I realized that there was no such feature, so I stopped designing architectures! “Oh, this program (like most) admits a straightforward OO design.” Unfortunately for the programmers who are so commonly also deep thinkers, most solutions are just routine. And that’s the best way to do them. I suppose that is a merit of Java: it restricts you so much that doing anything but a routine solution is grotesquely hard.

But there is some falsity to be gleaned here. I made it sound like all general purpose programming languages are the same. But, as usual, your solution will heavily depend on the language you’re using. My typical argumentitive antitheses are Java and Haskell, since they are both “pure” along different axes. A straightforward design in Java will bring out the OO essence in your problem, whereas a straightforward design in Haskell will bring out the mathematical essence in your program. When I first started writing in Haskell, I got extremely annoyed by its lack of polymorphism in the OO sense. Say you have this pseudo-C++ program:

    class Animal;   // all typical subclasses, Dog, etc.
    class Foo {
        virtual Animal* getAnimal() = 0;
    class Bar : public Foo {
        Animal* getAnimal() { return new Dog; }

This program has no obvious Haskell translation. As I got more experienced with the language, I realized that OO is not the One True paradigm, that most problems I want to solve have a natural OO solution and a natural functional solution, and they are very, very different. They solve the same problem, with comparable (but different) areas of modularity, etc.

After that long-winded digression, we can come back to Universal Architecture. I think we, as architects, should put more focus on finding the natural solution in the language we’re using, rather than trying to add a language feature to a language that doesn’t have it. Every time I’ve tried to do that (which is plenty; it seems each time I learn a new language I try to map the features I like about it into whichever language I happen to be using) I just end up with a mess. … Or worse yet, adding a language feature to a language that already does have it (see first example :-).


2 thoughts on “Universal Architecture

  1. Hey Luke,
    I found you on David Trowbridge’s blog. My name is Stacia and I work with a mature start-up located in downtown San Diego, SMS.ac. We are working on some of the most innovative products on the market; including a web-based application platform. We use cutting-edge technologies including ASP.NET and AJAX coding primarily in C#. And I can see you definitely have some opinions about programming languages. :)

    We need to find a community of men and women whose biggest passion in life is coding and programming.

    We are looking for entry level developers such as yourself or people you might know that are extremely smart and gifted. People you know that have a natural coding ability, and are looking for a professional environment that is both challenging and rewarding. We are talking about people who may not want to have ANYTHING to do with a

  2. “We need to find a community of men and women whose biggest passion in life is coding and programming.”

    Heeeelp, this woman needs help !!!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )


Connecting to %s