DevPinoy.org
A Filipino Developers Community
   
Keeping code close to the data -- how I love refactoring
I've been doing too much OOP that I've "forgotten" already what makes it different from procedural programming. It was funny when my up-and-coming employer asked me that question during my job interview. :) I kept on saying other things but eventually the interviewer told me that the answer he was waiting for was that "OOP = code + data." How could I have forgotten that basic principle!?

Working on one of the (e-commerce) projects with my current employer, I decided to remove the code that calculates taxes and state recycling fees from the Order class and put it in separate classes that implement a particular interface. My line of reasoning was that in the event that a new way/method of calculating these fees was to be adopted, there would be no need to rip out code from the Order class. Instead, the developer can just create a new class that performs the (new) calculations and inject it into the Order class via dependency injection. The Order class can then simply iterate through the calculator objects to perform those calculations. Sort of like the observer  pattern err, I mean the strategy pattern. (Thanks to Paul who pointed this out to me; actually I got confused because I also used the observer pattern here, in making sure that updates to the ShoppingCart object cascade to the Order object, which has a reference to the ShoppingCart.)

Now in the class that performs tax calculation, I came to need a way to stop the calculation if a shipping address has not yet been selected by the shopper. My first approach was to create a NoShippingAddressIn(Order order) method that returned a bool value. Ok, it worked great. Then I realized that the state recycling fee class also needs the same check. Rather than duplicating that method in the state recycling fee class, my knee-jerk reaction was to make NoShippingAddressIn(Order order) a static helper method in some static class, like make it AddressUtil.NoShippingAddressIn(Order order). That's when I realized...why don't I just put it in the Order class itself? So now I have a HasNoShippingAddress() method in my Order class that returns a bool value. As a side effect of that refactoring, I think my code just became a bit more readable. :)

So coming from something like (ugh!!!):
Address shipAddress = order.ShippingAddress;
if (shipAddress == null) return;
if (shipAddress.StateCode == null) return;
if (shipAddress.PostalCode == null) return;
if (shipAddress.City == null) return;
it became:

if (NoShippingAddressIn(order)) return;

I wanted to make it this way but good thing I didn't:

if (AddressUtil.NoShippingAddressIn(order)) return;

So now it's just:

if (order.HasNoShippingAddress()) return;

So there...that's when it struck me that indeed, one should keep code as close to the data as possible. How I love refactoring! And I love unit tests too :) All the while, I just made sure that my unit tests end in green after all those refactoring moves. That way, I'm pretty sure that the changed code does not come with any unwanted side effects.

Posted 12-07-2006 4:49 PM by cruizer
Filed under: , , ,

Comments

lamia wrote re: Keeping code close to the data -- how I love refactoring
on 12-07-2006 9:01 PM

Interesting! Currently, our code is bloated with bond-aid solutions. This is due to the many bugs that were found out.

I got a question!

Where should calculations take place?

for example, you have a class

class SomeClass

{

   int a;

   int b;

   //accessors and mutators here

}

what we did is have a method that calculates, say

getSum()

{

   return a+b;

}

I thought we didn't have a need for a third variable called "sum" but then, somewhere in our code we had problems. So what we did is put  the calculations in our database classes while we retrieve the values for a and b. We put that in a variable called sum. Hmmmm... Now our design has been torn! This is due to "no documentation" given to us by the client!

cruizer wrote re: Keeping code close to the data -- how I love refactoring
on 12-07-2006 9:39 PM

keep the code close to the data. for something as trivial as adding two numbers, you should just keep it in the same class that contains the data. if you wish the code to be changeable, that's when you use something like the Strategy pattern.

cruizer wrote re: Keeping code close to the data -- how I love refactoring
on 12-07-2006 9:41 PM

by the way, putting those calculations in the database classes -- it's a clear violation of SRP or "single responsibility principle." let your database code focus on getting data in and out of the database, and let your domain classes focus on stuff like calculations. :)

Virtual Genius wrote re: Keeping code close to the data -- how I love refactoring
on 12-09-2006 8:48 PM

I have an application with a complex calculation as a CLR function in the SQL Server 2005 database - mainly to utilize the speed of the DB server for large #'s of records. I have struggled with where best to locate this calculation. If I put it in the client then all the data must be loaded down to the client, which could scale out to hundreds of thousands of records and kill the performance (client and network). Thoughts? Comments?

Thanks,

Paul.

cruizer wrote re: Keeping code close to the data -- how I love refactoring
on 12-10-2006 1:50 AM

i guess you made the right decision. sometimes we have to "break" the accepted "rules" because of certain considerations, performance being one of them.

Copyright DevPinoy 2005-2008