Goals

In the world of software engineering, many tasks are performed over and over again that really don't need to be. One of the main ones, but one that is not often talked about, is frameworks. These days, it seems that every library out there provides its own framework for certain tasks. For example, I recently downloaded an XML parser which contained an extensive I/O framework, including support for files, sockets, and even http communications. In my opinion, such functionality is far outside the scope of an XML parser.

But what if there were one -- or perhaps a few -- good framework that everyone could start from? What if, by using the same framework, one group could write an http client while another wrote an XML parser, and then these could be combined trivially to form a larger application? This is the ideal that GUF is striving to achieve.

To that end, GUF has many sub-goals, including:

  • Good Design: The number one priority in the GUF project is design. GUF is object oriented to the extreme. When designing an object oriented system, it is easy to make mistakes that lead to messy, hard-to-understand code. We are being very careful to avoid such situations, and to keep GUF as clean and clear as possible. Of course, it is hard to judge one's own code in this respect. If you are experienced in object design, take a look at GUF and tell me what you think needs improvement, and what is being done right.

  • Portability: Porting a GUF-based program to multiple operating systems and hardware platforms will often take no more than a mouse-click. All of GUF's functionality is designed with portability in mind -- so much so, that a pure GUF program will ideally require no changes at all when compiling it on a different platform. Of course, such an ideal is not completely realistic, but GUF will come as close as possible to this goal.

  • Modularity: GUF makes it easy to write modular, reusable code. Imagine, for example, the task of writing a music player. As we have learned from such programs as WinAmp and XMMS, such programs can contain many independent components, and it is useful to be able to mix and match these components to accomplish certain tasks. You may want to output an MP3 to your sound card, or you may want to decode an OGG and output it as a WAV. You may want to add all sorts of different effects in the middle, like reverb or echo. The possibilities are endless.

    There are two ways to design such a program: You can write it as one massive program that supports every file format, every effect, every output format, and makes julien fries on the side; or, you can write a modular program that uses a well-defined "plug-in" interface, and then let other people write modules to do whatever needs to be done. Clearly, the latter choice is ideal.

    Furthermore, if you design things right, the modules written for your music player could be used in other software. For example, a game might use the MP3 decoder to play background music. If the mp3 decoder is not written to be modular, however, the authors of that game may have to write their own decoder, wasting time (and possibly money) that could have better been spent on creating a better game.

    Almost every large-scale program could benifit from an extremely modular design, and most software is designed this way already. GUF just makes it easier to do, and easier to integrate modules written for completely different programs.

  • Event-Driven: Quite often, a single program will need to perform many tasks simultaneously. One way to accomplish this is by using threads, in which several discrete tasks can be performed as if they were each being carried out by a separate program. This seems like a good way to do it, and indeed many programmers today have been misled into thinking that this is the only way.

    Threads have problems, however. Thread-safe code can be difficult to write and test, leading to buggier software. Worse, though, is the hidden inefficiency. Spawning and destroying threads can be slow, and a program which uses too many threads can quickly run out of memory if it is not careful. It is not uncommon for server software to have to handle hundreds or even thousands of connections at one time -- this can not be done using threads.

    Many multi-threaded programs leave most of their threads waiting for certain events to occur most of the time. Although waiting takes no CPU time, the threads still take up memory for their stack space and other data associated with them. Why not instead have one thread which waits on multiple events simultaneously, but handling them one-at-a-time? This is the way efficient servers are written. However, such software has traditionally been harder to write, and many programmers have thus shied away from it. GUF makes it easy.

    Of course, threads aren't useless. On multiprocessor systems, threads are required if you want to make use of all processors. Thus, GUF provides support for threads, and even strives to make thread synchronization easier to accomplish. However, because of the way GUF is designed, threads are virtually worthless for any reason other than multiprocessing.

  • Bug-Resistant: Although bugs will always be a problem for programmers, GUF code tends to avoid many of the more common bugs that plague C++ programmers today. Memory management, for example, is handled automatically through reference counting smart pointers. Although it is not true garbage collection, reference counting is just as good in any well-designed program, while providing accuracy that no garbage collector can.