not so Object Oriented OODA
March 28, 2008
so here’s the story, i got an interview at a consulting firm. since i already passed the preliminary technological interview this time around i was told that the interview is going to be focused on object-oriented design. so, i met the interviewer and he gave me a problem for me to solve. here’s the initial problem.
“suppose we have a class of Animal. because this is Animal class it can have much variety of Animal in the future. but for starters, let say if we have four different animals: Cat, Dog, Horse, and an Elephant. now, these animals have some behaviors such as sleep, run and carry. the rule for implementing the behaviors is to prevent any duplication of code, copy-and-paste is not good. i have defined several behaviors to you, but there will be more additional behaviors in the future. here’s the specific behaviors for the animals. all animals will be able to sleep and use the same sleep function. all animals can run, but each animal runs differently. only Elephant and Horse can carry things. remember, because we may have gazillions of classes in the future, any additions should have minimal impact to the module. build me your design.”
so I did.. here it is:
now, maybe it is not the best design in the world, but it is enough to satisfy his scenario. but i found out that the he is kind of have mixed reaction about my design. mostly he is kind of expected this design and kind of bored to my solution. however, how i separate the behavior to interfaces seems to surprised him a bit.
i cant really call this design is good, especially if we have a thousand of behaviors to implement, then this might not be the best. everything that describe the animal behaviors should probably best implemented in the animal class, but implementing abbilities like ‘carry’ using interface is often preferable.
going back to the interview, he then said that this design have a problem. he then asked me to add another premise: “now, suppose that I want to have a big dog. but this big dog can carry things around. this carry will be the same with the Horse and Elephant carry. and I do not want you to copy paste your code.”
this premise sounds fishy, and indeed it is strange. the while concept itself is strange. however, trying to meet his demand, i revised the design to this:
i just put a dog inside the big dog and then add a Run() method to be forwarded to the Dog instance. no, it is not a good design. this design is driven by a premise that i can’t use the same code twice, which is in this case Carry() or so he presume (later on this).
seeing that I overcome his tricks, he said again that this design still have problems. he then added another premise: “now, i want for the Elephant and Dog to be able to Play(). the same play should be used for both of the class.” at this point i understand, that he’ll just keep adding methods until i forfeit. he then says that this is the problem with my design, is that my design can’t cope with new methods without affecting the whole system. of course i suggest on doing refactoring, but he said that refactoring will affect the system too much even if it have unit tests.
so we did debate a little bit for more and i think, think and think, how to create a composible function that can be reflected on the interface of the classes. i suggest using a command-mapped interfaces, designed a series of chained commands (but that involves lots of casting = ugl. you might think of chain of command here, but chain of command works if you have one same virtual method, while in this case we have run, sleep, play…. doesn’t work right?). he then criticized my CarriableAnimal and said that this is only one behavior if you have lots of behaviors, like i said before, we’re going to add a lot of numbers of behaviors in the future, you’d add these classes around?
so I was forced to redesign my code again. one of my suggestion came out like this:
of course this is just a desperate attempt to probe what he wants me to do. he pointed out if i were to add new behavior, i’d have to write exceptions for all the class that doesn’t implement the behavior. another is to implement the strategy pattern but there are problems with that, so i ruled it out.
after much struggling we ran out of time, and so he said he’ll give me the correct answer:
i almost fell off my seat…
it is basically the strategy pattern. and he explained it that this solves everything. what he didnt realize is that this very very much violates what he’s been asserting the whole time, this is also very wrong in software designs, and this design has almost zero usability, and implementation-wise problematic.
lets start with the false assertions. in order to implement this, then all the classes that’s going to have a new behavior added will need a code to hold the new behavior instance and to create the proxy method (= copy-pasting the same code through all the classes because the behavior can only exists selected classes only and no apparent hierarcy. eventhough it exists, i suspect to be insignificant based on his scenario). he did managed to isolate the problem within the class all the time though, given there’s no effective hierarcy. second, if there were hundreds of classes to be added this behavior, then the modification would be made hundreds of times as well.
now, let see from software design. what on earth have he made? the notion of object abstraction is not even apparent inhis design. he is abusing inheritance just to write less code. while he is trying to reuse code, but this is not the way to reuse code.
the fact that I can’t use a Horse from it’s abstract form Animal already poses question. the fact that Run() behavior is separated from Horse poses another question. what does Run do? It is completely independent from Horse. it can’t change any Horse state, so, what’s the use? put it in another term, if i have a behavior that doesn’t effect the owner of that behavior, is that behavior appropriate for the entity? it is useless. it might have as well as good as implementing it as static helper method. of course, if we want to change some detail implementation then strategy pattern is good.
from usability point of view, this is a dud. think about how you’d use these classes? you can’t do anything with the Animal base class, so you’d have to access the concrete class directly. now, suppose a controller have a method that process every animal that can play, how’d you do that? overloading the method parameter with everyknown class that implement the play method? what an absurd!
so that is my experience interviewing with a person who claims to be expert in OODA (he even calls everyone who wrote book on OODA doesn’t know what the real world and their books are rubbish), but doesn’t really know what he’s talking about. this is just some of my arguments, i still have a lot more, but you can see how bad this not-so-of-a-solution solution is.
i’m not trying to say that he’s a bad guy or anything, it just that he doesn’t really understand the real deal while pretending and saying he does. at least he knows about OODA, unlike most programmer that i’ve been working with. (now you know how sucks my job is right now).