Thursday, November 8, 2012

Keep adding types use Polymorphism, keep adding functionalities use Struct

If we set minimize the changes as a goal, object-oriented programming people tend to agree that conditionals are bad smell, we should consider refactor them to types and use Polymorphism mechanism instead so that when we have a new type of data we can have a small change just to create a new types. But there is a good point in the early part of this podcast Something Else Was Smellier stated that if we are working on the problem that number of types are likely to be stable but what always changes are the behavior, we should consider keep behaviors separate(Separate function) from those types and leave the types as plain data structures(Struct).

For Polymorphism, if we are adding a new functionality to a class hierarchy we have to add it to every class in that hierarchy otherwise you will get no method error. In the opposite, if you just create a separate function to hold that new functionality while you know that you are not likely to have a new data type, you can just handle those types with case statement which each case response to each type. You can also simply ignore the data types that you don't interested in for that new functionality by fall it back to default case. If you have an another new functionality, just add a new function. If you follow this direction, all changes you have to add will rest in one place, you don't have to modify multiple places(types) as in Polymorphism approach, which leads to the goal of minimize the changes.

More visual example I can give is cards for card game. For example, you try to transform 52-cards deck(Type/Struct) to magic game card deck. You want to add attacking power(behavior) to those cards(Polymorphism), you have to draw value of attacking power on to every cards, which is quite a lot of work. Instead, you can draw a separate attacking power mapping table in a paper(Separate function) then you don't have to modify those cards. You changes will always in the table. And if you want to add defensive power you can have another mapping table. You can always have a new mapping table for every new functionality without touching those cards. The pain will occur when you need to add a new card(Type) because you have to go and modify every tables. If you always have a new card(Type), don't use a mapping table approach step back and go for modifying the card approach (Polymorphism).

One downside of emphasizing the struct is that you will have a hard dependency on that struct and you have to adapt the functionality to be match with that structure. When the struct get modified, your functionalities that rely on that struct are likely to change. For example the same 52-cards deck(Struct), which is a stable type never change structure, you can apply as many kind of games(behavior) you want on it easily but your game have to be sufficient of using only these 52 cards. When one of those 52 cards is modified, your games are screwed up.

No comments:

Config number of file descriptors on Linux

Check file descriptor limit for a process. Vary depending on owner of the process $ cat /proc/{process-id}/limits Check current number of...