The part1 of the series, on real life class design using C++, established our requirement

– we require a framework for collecting data easily from network devices –

The act of collecting network data is popularly termed as Inventory collection in the NMS (Network Management System) space. Now that we have a requirement, how do we implement this in C++?

It does make a difference who you learn it from


When i started out with C++, I learned the language mostly by reading multiple text books on the topic. My assumption was that if I went through at least 4-5 texts, i would encounter the most number of facts (tid-bits really) that any one author could not cover in a single book.

Unfortunately I was right about this assumption, because that was what i remained for a long time – tid-bit person. I could quote clever tricks with the type system., quote reams of in-compatibilities and feature comparisons between compilers and put my finger on many such clever sounding facts.

Ideal Learning

Alas, this my dear reader, while definitely good to know for practicing programmers, is not the MOST important piece of  knowledge you need from C++. The thing that really matters is how you would use C++ in controlling the complexity or making maintenance easier, which in reality is the most important reason why you should be using C++ compared to say C or FORTRAN or something else.
The Swiss Army Design Methodology

Instead most C++ text books i encountered in local publications, start out with a SINGLE chapter to impress the power of C++ on you, giving an example of a CWindow class, which reduced the entire WinMain to 3 or 4 lines or a CEmployee class, which could do everything relating to employee related details.

Many in one

Many in one

All that was required of you was to stick more and more functions into these super class and you had all the benefits of C++, much like the swiss army knifes which come with 5,10,15 different functions from your basic knife to a basic lens.

If you learned C++ in this manner, and read similar crappy text books, this would be the way in which you might start out your design of the Inventory Collection Framework.

Swiss Army Inventory Class


class CInventory()
    {
    Collect (MetaData *) ;
    PollData (MetaData *) ;

    InspectData (MetaData *);

    SaveData (MetaData *);
   };

This single class would be THE framework if you are from the swiss army design school. It could do everything related to Inventory collection and all that your users would have to do, would be to invoke this class and its member functions. I wish using C++ to control complexity is as simple as this.

Whats Wrong with Swiss Army Classes

Swiss army is the easiest way to get off the design ground and start coding. In fact that’s just what people do when they try to design as they code. Soon you would see that this one big class has many smells

1. Way too many unique functions ( > 10?)
2. Way too many member variables ( > 10?)
3. Too many lines of code in class source ( > 300 ?)

Think of what you would have done without the BIG class you just “designed”. All the individual functions that are a part of this class would have existed outside of this class, say in the main.cpp and supposedly this is bad for program maintenance and getting complexity under control.

All that you have achieved by putting together this one big class is to transfer all of this complexity into CInventory.cpp from main.cpp, such that your main function looks much more neater. So get this into you – cleaning up main() is not the reason why you write classes.

Separation of Concerns

The little tools that come with the swiss army knife are just that – tiny little tools that can be used in an emergency but never as good as the real big carving knife or the real lens or the big scissors. So that’s we will do with our big Inventory class –  break them up into proper classes that will handle one responsibility and do that well.

The Broken up CInventory Class

  1. class DataSave; // Reads metaData and saves the data
  2. class Inspect;    // Reads MetaData and allows data processing functions to be invoked
  3. class SnmpCollect // Reads MetaData & performs DataCollection
  4. class CInventory(); // Central class to integrate all the above

Once you have done the breakup of functionality, more possibilities open up.

Possibilities

  1. Why not make the SnmpCollector class an instance of ICollect, such that later on i can have a SOAP data collectionframework that implements ICOllect and it might just plugin into this framework and truly make multiplke data sources a possibility.
  2. MetaData is being read again and again by all the different classes. Why not make this a single class such that no other classes needs to understand how to do this ? Additionally if i change my metadata format from structures in .h files tosay XML, i need not worry about the wave of changes in other areas of my program
  3. Do i need to make DataSave an instance of IDataSave such that i have different classes for say talking to SQL-Server / PostGres ?

After further breakup –

  1. class CMetaData; //Knows how to interpret MetaData and translate them into generic data specs of row/table
  2. class CRow,CColumn, CTable,CAttribute, CScalars – Common classes to represent the interpreted MetaData
  3. class CDataSave; // saves the data, given an in-memory data spec
  4. class CAdoDbase; // Provides implementation of data persistence for all ADO compatible data sources in windows
  5. class CDataCollectionConductor; // Interprets the data spec and invokes the required ICollector functions
  6. interface ICollector;
  7. class SnmpCollector; // Implements ICollector and performs SNMP;
  8. class CDataInspect; //Provided way to inspect your data before after data collection and modify the same
  9. class CDataCollectorBucket; // Provides ways to put together multiple instances of data conductors and save them

Benefits

  1. The entire program and its associated complexity is divided into nice little pieces that you can understand
  2. The pieces can be improved without affecting others
  3. Maybe the naming of the little pieces would be good enough to add more meaning to the program.
  4. Easier to split work between different developers.
  5. Better chances of reuse
  6. Flexibility – Its easy to use pieces of the framework without swallowing the whole design.

The most important benefit of distributing the scope and different responsibilities amongst multiple classes was that new patterns began to emerge. We could find further commonalities that where ideal to be spun off into their own individual classes and using new interfaces to break dependencies. Only when you get to this stage do you, start seeing the benefits of other features of C++, like virtual classes, interfaces, inheritance and such.

So the guide to beginning on the track to good design, is to start splitting your classes into smaller ones, with specific responsibilities and specific NAMES (Your class names are an important smell as to how good the design is.)