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.