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.
|