Tuesday, September 14, 2010

Interfaces and behavior

This is a very simple post (easy to read), for the ones that know something about object oriented programming is quite stupid, but I want to talk about something annoying I usually find in code. One common mistake I see in software development is the confusion between an object interface and its behavior. Basically what I see is that developers don't understand polymorphism. I'll try to define polymorphism in a very simple way: "Polymorphism is the capability of an action or method to do different things based on the object that it is acting upon. "


With that being said, I'll present an example of what I commonly see:


The idea is quite simple, let's say that we want to calculate taxes based on the sale of a product. So we create a class called TaxesCalculator (for example) in order to calculate the taxes based on a sale (I'll simplify the domain model just to make the idea very simple is not my intention to give a real example).


So TaxesCalculator will have a method called calculate that receives a sale and returns a list of taxes


So far so good, the class seems to be OK and everyone is happy. But then we realized that there are to ways of calculate taxes (for example, based on the country), let's call them Reg1001 and Reg1002. It seems to be a problem where the use of polymorphism seems to be suitable. I don't know why but I do not often see this kind of problems fixed using polymorphism. I usually find something like this:

List calculate(Sale sale, boolean useReg1002)
or
                                                        List calculateUsingReg1001(Sale)
                                                                                         List calculateUsingReg1002(Sale)
or even worst
                                                        List calculate(Request)
where request has these methods:
                                                        Sale getSale()
                                                                                          boolean isReg1002()

Which is the main problem with these implementations?, well the it's quite obvious that we tied the implementation with the interface, and this is  a problem because the code of the TaxesCalculator is harder to maintain (too many ifs and conditionals, low code reutilization, etc). And we make the TaxesCalculator client harder to maintain also, this class needs to know how we need to compute our taxes (something the TaxesCalculator should know), why does it need to know that?, well, it's very easy, because it needs to know which method to call and how to call it.


For me the easiest way to do this is by having:



We need to differentiate the interface from the behavior of the class, the interface needs to represent a business behavior (the act of calculate taxes) by doing this we will be able to modify the code easily. With this implementation we have a very simple client code that we won't need to modify if we need to add a new way of calculate taxes.

On the other hand, If you need to modify the behavior of an existing class based on some configurations you can still maintain the same interface by configuring the class using its constructor (so you create the class with its configuration, so the class factory is aware of the implementation and not the client).


Well, I'm kind of tired of writing, it's a very simple idea and we learn it at school, but sometimes people follow their dark instincts and write some awful things that other people unfortunately need to read :-)

Thanks 



No comments:

Post a Comment