Friday, September 16, 2005

Object Oriented Design?

When Object oriented design first came on the scene there was a great deal of excitement. One of the early mantra's was that with the OO programming paradigm you can create complex data types which not only contains data but also the behaviour associated with that data.

The most obvious example of this is in the case of the Vector data structure. The standard vector consists of three scalars, x, y and z, and as my ever persistent matric science teacher was at pains to point out, "has magnitude and direction".

With OO you can create a data structure which contains the 3 scalars and a collection of methods in the same context as the scalars to allow the vector interact with other vectors. Addition, multiplication and dot product etc.

However, I'm not so sure if this is the key to the success of OO, nor that this paradigm should be ubiquitously applied.

It's probably fair to say that the majority of data types that are built in modern programming do not have such a tight coupling between their behaviour and their data and therefore this encapsulation should, in most circumstances, not take place.

In the case of the vector, it is in fact defined by its behaviour; the vector is an entity which has this set of data and behaves in this way. The same cannot be said about a Person object for instance.

Let's change tack for a second and look at what would happen if we do enapsulate the behaviour of an object with its data.

Consider a person object, it contains the name, surname, birthday etc of a Person. If we place behaviour for the person object into the person object it becomes prohibitively difficult to reuse that behaviour, for a different person object for instance. If we wish to use that behaviour we have go via the Person object itself. It also means that we cannot change the behaviour without affecting the data.

It is therefore better to create a data object which only contains the data associated with the Person and then another object which contains the behaviour associated with the person.

So then you might be asking, doesn't that make the data object little more than a struct, a concept which was part of the procedural programming paradigm? You would be right, but then that begs the question, why is the OO paradigm better?

The key to the OO paradigm is not that data can be associated with it's behaviour but that behaviour can be treated as a variable. The strength of a variable is that it is exactly that, it can change, it can be assigned and it can therefore be moved around. Now with the OO model we can pass behaviour around like a variable is passed around. With the introduction of objects, which have behaviour (methods), we can now treat behaviour like we would treat a string for example. We can pass it in as a parameter for a method, we can change the behaviour as easily as changing a variables value.

How is this achieved? It is achieved by something that was formally introduced in Java, the "interface". C++ fully supported interfaces in their "abstract classes with no implemented methods" guise, java however, created a new class type. Interfaces are exactly that, abstract classes with no implemented methods. In java, though it does not have multiple inheritance, there is no limit on the number of interfaces a class can implement.

If you write an object which contains functionality associated with a Person object then you would create an interface with which this behaviour would know how to talk. Your person object would then implement that interface, and by so doing, would be able to be acted upon by the functionality you have created.

Whether to separate behaviour from data is a decision that should always be looked at. Conjoining behaviour with data should only be done when the behaviour and data are tightly coupled. Making behaviour mobile is arguably the key advantage of the OO approach, and one that should be leveraged as much as possible.

Thursday, September 01, 2005

Only do it once...

When it comes to programming, one of my most recent mantras is to "only do it once".

Whenever I solve a problem, whatever that problem might be, I must only solve the problem once and then re-use that solution in future. By doing this you programs become many mini programs.

I can remember one of the first things I learnt, even when I still at school, about computer programs is that it's input, process, output. By employing this approach you are configuring alreaday written components, supplying them with input data and then firing them off.

A naive example would be, you have a square root to solve, you write a square route method, make it statically available (it is a stateless algorithm) and you never have to solve the square route problem again.

It has input - the input parameter you want to find the square root, it has processing, calculate the square root and it has result, the calculated square root.

Now on my current project, we receive data from a back end stored in a Map. We have to move that data into a data object. The populate mechanism for doing this would be to write something like...
vo.setStartDate((String)map.get("START_DATE"));
vo.setAmount((String)map.get("AMOUNT"));
vo.setDuration((String)map.get("DURATION"));
vo.setElecTransID((String)map.get("ELEC_TRANS_ID"));
vo.setInitialSequence((String)map.get("INITIAL_SUB_SEQ"));
vo.setNodeName((String)map.get("NODE_NAME"));
vo.setProviderID((String)map.get("PROVIDER_ID"));
vo.setRechargeMethod((String)map.get("RECHARGE_METHOD"));
vo.setTransactionID((String)map.get("TRANSACTION_ID"));
vo.setValueAddedInformation((String)map.get("VALUE_ADD_INFO"));
vo.setVoucherBatchNumber((String)map.get("VOUCHER_BATCH_NO"));
vo.setVoucherEndDate((String)map.get("VOUNCHER_END_DATE"));
vo.setVoucherNumber((String)map.get("VOUCHER_NO"));
vo.setVoucherPin((String)map.get("VOUCHER_PIN"));

Now, as you can see, for every different data object I receive from the back end, I have to do something similar to this.

However, that means I have to solve the same problem many times. If I apply the "only do it once, input process output" paradigm then I write a re-usable utility that will do the work for me. I supply it input parameters and configuration parameters, and it does the work of copying the data from the map to the data object.

In this case the input parameter is the map. The configuration parameter (this is a kind of input parameter) is the mapping between the key names in the map and the property names in the data object. The other input parameter would be the data object.

funkyMechanism(map, <ObjecToMapMapper> , dataObject)
So map to data object would contain...
START_DATE = startDate
AMOUNT = amount
etc...
In order to solve this problem in this way, reflection was used. There are ways to solve it using a similar input processing output paradigm, they're just not as elegant.

When programming try your best to only ever solve a problem once, and then re-use that solution. Think of instances where you can encapsulate a solution into input - processing - output. You'll find you code a lot less, your programs will be more robust and will have more of a Wow factor!