Wednesday, February 22, 2006

Do you really need that RDBMS?
I think relational databases are used in more systems than they should be. In many systems the database is the very essence of the system, without a database it wouldn't make any sense. This isn't true for all systems, though. There are classes of systems which don't primarily exist to retrieve, process and store data in a database. Real-time systems which control hardware, games, communications software and graphics software are some examples. Often these systems still need persistent storage, for example to read configuration data and to write usage statistics. But does that storage have to be a relational database? The strengths of relational databases (flexible query language, security, ...) are not of much use in these applications but we still have to pay the costs: performance overhead, installation/administration issues and perhaps even financial costs.
So what to use instead? Files!
Text files for easy debugging, integration and portability or binary files for performance.
Should these files be XML files? Wait for the exciting answer in a future blog entry...

Monday, February 20, 2006

Security vs usability
If you go for a walk or a drive through central Stockholm with a WiFi device in your pocket, you'll discover many wireless networks called "NETGEAR", "linkys", "Apple Network" or other default names, and no security turned on. Not having to worry about passwords is convenient when you set up you home network, it makes the system more usable, but it's obviously not secure.
To an architect, security and usability are examples of quality attributes, non-functional aspects that need to be considered when designing a system. You usually can't have everything, trade-offs have to be made.
In the case of home networking, the architect seems to have decided that usability is more important than security. But who would this architect be?
The author(s) of IEEE 802.11b?
The architect of the access point?
The architect of the connecting device, usually from a different vendor than the access point?

None of the above have architected the actual system you are using, since the system of interest consists of both access point and device. The authors of the standard could have mandated a solution, but didn't as far as I know. So the result we're seeing is a kind of emergent behavior.
Emergent behavior is a powerful concept, but in most systems you want more control over the result.
So if you want to avoid surprising emergent behaviors in the systems you develop, make sure each system (and a system can consist of systems which consist of systems, etc) has an architect who makes conscious trade-offs between quality attributes based on collected requirements.

Thursday, February 16, 2006

More on Functors

Yesterday I wrote about Functors. The power of Functors comes not only from being able to store and call them, we can do that with functions pointers, but from the fact that they are function objects instantiated from classes. Classes can use encapsulation and inheritance, which isn't available with function pointers. Functor class templates allow further generalization.

In Lisp we can do even more interesting things with functions, in particular with Lisp's macro facility. A macro in Lisp is like a little program which writes a program, a very powerful concept. Lisp macros have very little in common with C/C++ macros.
Anonymous functions ("lambdas") and passing functions as arguments to other functions are common techniques in Lisp.

Once you are comfortable using these concepts, treating functions as data, you'll have a powerful tool available to make your designs more elegant and flexible.

Wednesday, February 15, 2006

Functions and citizenship
In traditional structured languages like Pascal, functions and data are distinct. This is often inconvenient, so in C we got functions pointers and in C# we have delegates. These constructs go some way towards granting functions citizenship, in that we can treat functions as data in some limited ways.
In C++ there is another opportunity: Functors. A Functor is something that can be used as a function. Since C++ allows overloading operator(), this includes objects. Any class which overloads operator() is a Functor, since objects of that class can be called with function syntax.
Representing functions as objects opens up possibilities to store functions, pass them as arguments, etc. It also allows us to do something even more interesting: composing and sequencing Functors with generic algorithms where you pass in the concrete functions/Functors to be called.

Tuesday, February 14, 2006

Singleton considered harmful
If you've worked on an object-oriented system you've probably encountered singleton classes, classes which can have only one instance. Sometimes also known as "Highlander classes", as in "there can be only one".
Singletons are the gotos of data and should be avoided just like goto. The "convenience" of the standard singleton pattern, that you can acess them from anywhere within your code, breaks locality just like goto does. Worse actually, since goto usually can jump only within a function.

One particularly insidious way to create a kind of singleton is available in C++: the static variable declared in a function. This kind of variable will be initialized only the first time the function is called and all instances of the class will share the same variable instance. This is nasty because it's hidden: there is no hint in the class declaration what's going on and even a casual inspection of the implementation may not reveal that subtle static.

So how should you avoid unnecessary singletons? The problem you're trying to solve with a singleton is often to make some kind of global state accessible. Pass around references to the state object instead, preferrably as an argument in the constructor. This also has the benefit of making it possible to supply an object of another class, conforming to the same interface; e.g. when you want to isolate a part of the system for testing you can pass a stub object (always returning the same answers) instead of the real live object which accesses a database or the internet or whatever.
Avoiding singletons is just one aspect of avoiding to be concrete. Using interfaces and factories rather than concrete classes and instances makes your system flexible and testable; which in the end translates to profitable.

Monday, February 13, 2006

The architect's tool chest
Yesterday I wrote about design decisions and cultures, and today I'll continue on a similar theme.
I've worked on at least four systems having large sets of parameters; i.e. values that depend on each other. One common reason to have a set of interdependent parameters may be that you want your system to be configurable to accomodate the needs of different customers, another may be that your system measures a number of values and computes other values from combinations of them. In each of these systems the solution to this problem was an object-oriented framework that holds the parameters and propagates value changes, triggering the computations of new values, etc.
This is a perfectly reasonable solution. In each case these frameworks were redesigned before they felt right. Nothing wrong with that, learning from experience is fine. These systems are all fairly successful. So, what is there to write about?
Well, there is another approach to the parameter problem: Constraint Logic Programming. Never heard of it? Neither had the designers of the parameter frameworks I mentioned. CLP has never been very fashionable and it's not backed by any major vendor, but it's been around for almost 20 years.
After evaluating the pros and cons of an OO framework and CLP, you might still go with the OO solution, but if you haven't even heard of CLP your range of choices is obviously more limited. An architect who wants to deliver business value needs to have a large tool chest and not be limited to what's in fashion at the moment or what the biggest vendors are pushing.

For an introduction to CLP, you can visit this site: http://clip.dia.fi.upm.es/~vocal/public_info/seminar_notes/node6.html

Sunday, February 12, 2006

The accidental language designer

When I studied Computer Science at Uppsala University I was required to take a course in Program and Machine Semantics. A very theoretical course and during a particularly difficult lecture our professor tried to motivate us by saying: "In your professional lives you will all design programming languages. To make them successful you'll need to understand the content of this course."
I thought he was nuts. Language design was the domain of geniuses and committees. I didn't feel like a genius and I had no desire to be on a standardization committe, so what did this have to do with me?
On my first job, I began to understand what he meant. The project was to build a test engine for a communication protocol. Tests were to be specified in a simple language that test engineers without a programming background could use, and guess what? We had to come up with the language. We threw together something that seemed reasonable, the lectures on formal semantics seemed far away. Our language turned out to be difficult to use, in situations we hadn't anticipated noone knew what would happen. It didn't have any defined semantics. The system testers eventually learned what worked and what didn't, and used working code as templates for new code. For this problem I think a small language probably was a good idea, but we should have been more careful specifying it.

At another company, a colleague was given a very open-ended optimization problem. He was a great fan of Lisp (so am I, by the way), but company policy mandated C++ as the development language. My colleague despised C++ and object-orientation, he thought it was to "strict". He solved his dilemma by implementing his own "Lisp" in C++ (and then I'm insulting Lisp): everything was represented as arrays of arrays of chars, and all functions worked on arrays of arrays of chars. And, of course, you could also represent code the same way and there was an eval function to run code.
Very flexible. Way too flexible actually, my colleague was the only one who could understand the resulting system. Designing a language is not always the right idea.

Another example, from a third company: a system needs to handle workflows. The workflows are to be specified by domain experts. Now wiser from experience, I suggest that we need to define a language to express these workflows in and document what the constructs of the language mean. But the culture in this company makes this idea impossible. The idea that you can design your own language is just too far-fetched, somewhat like my own reaction many years ago. "The domain experts are supposed to do data entry, not programming!". With time, it turned out the data got more and more complex, and in the end became a sort of language anyway, albeit an odd and undefined one.
Defining a language from the beginning would have been a great idea in this cse, but the organization wasn't ready for it.

So, Professor Barklund, wherever you are these days (Microsoft last I heard): you were right. It's no accident that I have come across language design issues in many of the systems I've worked on: software engineers design programming languages all the time and it's important to understand the semantics of programming languages.
Even more important is to understand when to design a language and when not to. That's harder to teach in a university course, that kind of judgement requires good taste. While an education can be a great help, experience in building systems is what really develops your taste. Design decisions aren't all technical either, the culture you work in is also important. A brilliant solution (in your own not so humble opinion) that your co-workers won't be comfortable with is not a good solution.
Hi and welcome to my blog!
I'm Jan Mattsson, a software architect and developer in Stockholm, Sweden. I also have some management responsibilities in the consultancy company in which I'm a partner; IT-Huset (www.it-huset.se).
My interests are broad, and I'll be writing on technical topics as well as organization and business aspects of software development.