The design from the part 2 of the series demonstrated the flexibility arising from the capability to mix and match framework class or roll custom classes. In this section let us check out another aspect of design, arising from a very common paradigm, but frequently ignored.

Check out, how our current design addresses multiple collectors used as part of the framework

class UserClass::UserClass()
{
ICollector * pSoap = new CSoapCollector(SoapMeataData);
ICollector * pSnmp = new CSnmpCollector(SnmpMetaData);
}

UserClass::Collect()
{
pSoap -> Collect()) + error checking / logging / storing data pointers etc
pSnmp -> Collect()) + error checking / logging / storing data pointers etc
}

UserClass::Save()
{
pSoap -> GetData();
//Loop tables and save data / check errors using DataSave Class.

pSnmp->getData();
//Loop tables and save data / check errors using DataSave Class.
}

AVOID CODE DUPLICATION

The more the number of collectors used, the more the amount of code that is duplicated and this gets multiplied across the number of user classes that are created. Imagine the amount of changes that has to be made, in case one were to change even a simple thing like an error code. Hiving off such common functionality across to a helper class would be useful.

class CCollectorBasket()

{
AddCollector(ICollector *);
// adds the collector instance to a list of collectors present in the basket
CCollectorBasket::Collect()
{
/* loops over all collectors
Invokes Collect()
Do error checks */

}

CCollectorBasket::Poll()
{
/* loops over all collectors
invokes poll()
Do error checks etc */

}

CCollectorBasket:: Inspect()
{
/* loops over all Collectors
loops over data collected from the collectors
Hands them to inspection class */

}

}

After employing the helper class in our design, the user classes would now look like this, unless of-course any custom mixing is required.

class UserClass

{
CCCollectorBasket oBasket;UserClass::UserClass()
{
oBasket.AddCollector(new CSnmpCollector(MetaData));
oBasket.AddCollector(new CSoapCollector(MetaData));
}

UserClass::Poll()
{
oBasket.Poll()
}

UserClass::Save()
{
oBasket.Save()
}

}

ps : Note that the user does not have to use the CCollectorBasket if not required and retains all freedom to create a custom mix of collectors and the work done using them.

OO theory states that if you have a class Fly(), next time you require flight, you could reuse Fly(). That class would get an A+ for reuse – right? However experience will teach you that you will never ever require the exact Fly() capability ever again. What might be useful though are methods like Find-Co-ordinates() / GetRadioSignal() / GetFlyingTime() / GetTimeZon() / ConvertToTimeZone() / GetDestinationCoordinates() / GetWeatherForeCast() and such. Even these might require to be customized, neverthless you will find this type of minute reuse more plausible rather than wholesale reuse like those countless books on 24 hrs C++ would like you to believe.

PARANOID DE-DUPLICATION

Knowing that reuse is good is one thing. Knowing which code can be reused is another. It is likely that the original Fly() author would never have, in his wildest dreams, dreamed that the system that was created will be a modest success (aka makes profits) and will form the basis of two or three other implementations based on the same base code. Therefore the chances of the system being designed for reuse as a base library are remote. But what might help here is a paranoid fear of duplication that, if followed religiously will lead to creation of countless small pockets of code that can be reused and adds value to the overall system.

It is not just concrete action functions like ConvertToTimeZone() that should be de-duplicated but just about ANY code fits this bill. Even if they might not make sense in another context these blocks of de-duplicated code makes sense from a maintainability and extensibility point of view. Once factored out, like fractals that grow on its own, these peices of functionality slowly starts to make sense on their own and useful reasons for extending them keep emerging as the code base grows. Frameworks are all about value add, and any additional value keeps adding to the overall usability, to finally reach that tipping point which makes a product or code valuable enough to be purchased.

In the next part of the series we shall look at another piece of code that got factored into its own small class to aid in reuse.

Advertisements