Bitwise Operator
by Matt Slot


Probably the most important thing a programmer can do to improve his code is to structure it better. It's not
only a matter of convenience, it means faster implementation of new features, simpler debugging, long term
maintainability, and portable code. It requires a bit of forethought, and an awareness of each portion of the
whole project as it's constructed.

I'd like to discuss 3 different places to improve the structure of new and revised code: interface,
implementation, and incremental changes.

Interface

When designing a new application or library, it's important to understand how each portion will interface
with each other. I'm not talking about USER interfaces, but PROGRAMMER interfaces. Each service that an
application uses or provides should be modular -- well-defined requirements and promised features.

The infrastructure routines should provide memory, string, and data storage (lists, trees, tables). Additional
"modules" should provide file, database, and network access. The core application will then provide a layer
between the low level services and the actual user interface (if there is one).

For many of the well-advertised reasons, object-oriented programming can simplify the programmer
interfaces between various service modules and the application itself. Even without OOP techniques,
modularized code makes it much easier to update, change, or even port such services because it "abstracts"
these services and hides their implementation behind a simplified set of functions.

With this method, the library provide a consistent interface to the caller and the programmer is free to modify
or replace the code that actually implements the promised features.

Implementation

The next suggestion for improving code structure promotes the use of "bottleneck" routines. These routines
perform a narrowly defined service for the caller, such as sending commands over a network or reading an
arbitrary data chunk from disk and dispatching it to the correct handler.

The term bottleneck derives from the fact that many functions will call this one particular routine, and this
routine will dispatch the desired behavior to the appropriate implementation. Bottleneck routines are typically
key programmer interfaces to a specific library or functional module, and either consists of the exact sequence
of calls to provide the functionality or they provide a large switch/case statement that dispatches to multiple
handlers.

The primary advantage to such routines is that they provide a single access point for a whole suite of related
functionality. For example, what if the programmer wants to track exactly what data is being written to disk
for debugging or just counting bytes. Consider an application that, each time it needs to write to disk, it
opens the file, scans to the right location, writes the data, closes the disk, and checks for errors. It's pretty
hard to debug the file saving code because it's spread all over the application.

On the other hand the programmer should write single routine that performs the entire sequence of steps, and
then call the bottleneck each time data needs to be saved to disk. Later, it becomes trivial to set a debugger
breakpoint to trace exactly which data is being written to disk (and from where in the project). It's also the
perfect place to extend functionality, such as a byte counter or an option to save to the system clipboard.

Object oriented programmers often have some language support for writing bottleneck functions using
"polymorphism". In the application, a number of classes can provide a "draw" member function that
performs a slight variation of the same drawing functionality appropriate to the desired object. Adding a call
to the draw member of the base class let's that function act as a bottleneck, to provide common drawing
functionality such as coloring the pen or enabling/disabling drawing at a global level.

Incremental Changes

In the early stages of design and development, the programmer will try to bottleneck the code in as many
places as possible for the reasons indicated above. This is typically planned at a very high level for the key
functional and data structures. On the other hand, there are often many opportunities to improve the structure
of the code as development progresses and more patterns become evident in the code.

Invariably, as existing features are fleshed and new features are added, certain elements or functional
sequences tend to be reappear -- especially in "copy and paste" code. As a good rule of thumb, when I find
myself writing basically the same sequence of code for the third time, I step back and try to find a way to
bottleneck the code.

As I become aquainted with new library routines or write code to interact with something written by another
programmer, it often turns out that the interface was written in a rather general purpose manner. This is often
fine because there are often different ways or reasons to use a given piece of code, but when I start using that
code I have a specific use or platform in mind.

Each time I program to that library's interface, I must write a bit of glue code to convert from my internal data
format to the general purpose parameters that it expects. As my code depends more upon the new library, it
becomes useful to create wrapper functions that simplify the conversion to reduce code bloat and bottleneck
the functionality. Later, for example, if my code were to change it's internal data units or format, it would be
straightforward to revise just the wrappers themselves and not every place they are used.

None of these techniques are well-defined rules for success, but they do provide a certain measure of
structure and stability to code. Using descriptive names for the bottleneck and wrapper routines supplement
programmer comments as a way to improve code readability and maintenance. Writing small utility functions
not only aids debugging, but also saves from problems when writing similar code and missing a +1 in a
certain case.

Well-structured application software and programmer libraries are often much more usable and stable than
those that sort of accumulate new features without much forethought. It's also a sign that the programmer
intends to maintain the code in the future, and didn't write it as a weekend hack.

Matt Slot, Bitwise Operator

Page 3