Table-Oriented Programming
Often enough in my daily job as a sysadmin, I create data-parsing tools that sort through logfiles, interrogate SNMP devices, or trawl through databases gathering data and statistics to generate reports that I need on a daily basis to ensure that I’m doing my job well. Systems and software that is malfunctioning because of an easily caught error is embarrassing at the least, and costly in time and materials at the worst for my users. Traditionally, my one-off scripts have utilized collections of arrays and lists to gather data. At worst, this makes reusability of data tougher on other scripts that need the same information. At best it allows me to simply create a tool, and not have to worry about it in the future. This is poor design however. Some recent tools I’ve developed revolve around a project at a client where I’m maintaining and improving a backup system (Veritas NetBackup). While the generic reporting in the base product is decent, the Advanced Reporting Option proved too expensive, and politically troublesome to deploy early in my tenure. I started building a small framework of shell and perl scripts that would do my job for me to generate reports management wanted to see to ensure that backups were being accomplished in a nominal fashion.
You may be asking why I think current interfaces around ActiveRecords or JDO are unacceptable. I believe the fundamental problem is the need to provide ActiveConnection models to support SQL or some custom query language. There is a benefit if our table implementations can be coupled with a database engine, if the associated SQL engine overhead isn’t required. s
There is a need for table-like collections inherent to every language we develop in.
ACE C++:
class ACE_Table; class ACE_Row;
class ACE_Row {
friend ACE_Table;
protected: ACE_Array _headerValues; ACE_Map< ACE_String, ACE_Variant > _rowData;
public:
ACE_Row();
ACE_Variant&amp;amp; column(const ACE_String&amp;amp;);
ACE_Variant&amp;amp; column(int colIx);
bool column(const ACE_String&amp;amp;, const ACE_Variant);
bool column(int colIDx, const ACE_Variant);
};
class ACE_Table { private: ACE_Array _values; ACE_Array _headerValues;
public: ACE_Table( const ACE_Array &amp;amp;headerValues ) : _headerValues(headerValues) { }
class row_iterator {
};
class col_iterator {
}; };
In general with a table, you want some mechanism to save and load the resultant table. The best choice is an abstract TableFactory interface. Two methods are present:
Table TableFactory::import(); TableFactory::export(Table);