« December 1997 | Main | April 1998 »
February 01, 1998
Overload 24 Editorial
Managing Complexity
As Ada is to Pascal, as C++ is to C; these large scale languages are for managing the complexity of building large scale projects. You can implement anything in C that you can implement with C++, but C++ gives you a hand in many ways. It imposes conventions for naming, defining state, execution context, scope management, object lifetime, encapsulation, and interface definition. All features that lead to software which can be easily maintained, documented, and extended.
When faced with an aging mass (or is that a mess) of C, which must be maintained and enhanced, there's little choice but to step back and invest some time in reorganisation. A software system with poor structure breeds poor structure. Engineers tend to follow the style of the code they're working with. When there are few functions that can be reused, all new code will be a cut, paste and modification of something else. I've witnessed one project that pushed hard for a year without any restructuring of the previous version. The product shipped, late, and the next year was spent maintaining the bugs of the shipped binaries.
So, in order to repair the 'badness' I see I'm adopting an iterative rewriting approach, to apply the aspects of 'goodness' that I listed above.
Naming Conventions: Often, with many engineers on a project, a common naming scheme will be defined, and slowly diverged from. Something of the form <module>_<action> is common. I'm trying to move towards <structure>_<method>. Similar to <class>::<method>, huh? The simple benefit this provides is to help engineers find the code they need quickly. The secondary benefit is a change in state of mind. The function is a method on an object of well defined type.
Well Defined State: For each structure I create a <structure>_new and <structure>_delete function, and replace the splattering of calls to malloc and free. This single point of construction ensures that every instantiation will be initialised correctly and consistently. I assess how often each structure member is referenced, and if manageable, impose accessor functions. Often these can be upgraded to include code to maintain the well defined state of the object, and to provide some higher order of functionality. This benefits, and simplifies its callers.
Execution Context: Renaming each function within this new scheme forces each function to be identified with some structure. The first parameter then becomes a pointer to an instance of that structure (this).
Encapsulation: When a function can't be readily assigned to some structure it's usually because it embodies a number of intertwined concepts. It may have private knowledge of a number of structures, and have access to static level data. These kitchen sink functions can rarely be reused so must be carefully teased into composite parts. Moving the functional details of each structure into accessor functions simplifies the function and clarifies where its functionality belongs.
Well Defined Interfaces: I've been ensuring that internal functions are declared static (private), and that global ones are published in header files (public). I recently found a module which imported some functions from another with a cunning cut and paste of the function prototypes (friend). Definitely bad practice.
Motivation
I'm not imposing an object oriented design onto this software just because that's the way I like things. That's the way I see things, so that's the way I like them. The motivation is to reduce maintenance costs, the lead time of new engineers, and to ease the implementation of new features. With poorly encapsulated design an engineer must understand the entirety of the system before any useful work can be achieved. These few aspects of an object oriented approach to software development that I've described above should help move us towards this goal. Ultimately I hope that new features will be designed as components, making use of the newly repackaged and finally reusable existing code.
John Merrells
February 1998
Posted by John at 12:00 PM