As a child I watched Sesame Street, and remember the "One of These Things" song.
"One of these things is not like the others,
One of these things just doesn't belong,
Can you tell which thing is not like the others
By the time I finish my song?"
When spending time in legacy and recent code you are going to find code that mimics that song.
When developing code it is best separate out distinct functionality into different units.
Our system contains 80+ console applications. Each runs on a unique schedule. Such as Nightly, Monthly, Quarterly, and Annually.
In our GUI application we have a factory that creates some of our screens. The factory then knows about those screens. Using this unit in one of our console applications is not needed.
One day someone on my team noticed several of our console applications had dramatically increased in size. Looking at the code it was because several method were added to an existing unit that required access to the factory, although none of the console applications actually needed that code. We had to move that new method to where it belonged.
When working with an existing piece of code, and you are adding functionality you need to ask does it belong. One clue to help is if you need to change the uses clause you must be aware of what you are linking not only to your unit but all the other units that use your unit. When designing new code care should be put into keeping the visual interface out of the underlying business rules. Functionality should be grouped it a way that when using unit X you are not linking code for units A, B, and C that will never be used.
But now comes the problem with legacy code. You are not adding new code, your modifying the spaghetti mess that was left for you by someone else. What should you do?
- Attempt to understand the existing code... Sometimes this is the most difficult part.
- If the code can be separated into two different units without changing the actual implementation details then it's far less risky to separate the units. Then all your doing is adding the new unit to the uses clause of the units that used that code where needed. Beware if your code uses RTTI this can still break things, depending on how the RTTI was used, specifically since the unit name could have been used as text either in code or an external file.
- If separation of code can not occur without changing implementation details greater well then you need decide if it's worth it. Unlike the Matrix movie you get to find out how deep the rabbit hole goes before you take the red or blue pill. The deeper hole, the bigger the problem. Key factors I use in determining if it's worth changing the design to separate the implementation.
- How many places is the unit used...
- How many places is the unit used, directly. (i.e. in the uses clause of another unit)
- How many places is the unit used, indirectly. (i.e. In another class you inherit from a class that was in the prior unit, then you need to find out how many places the new unit is used. This search will continue on recursively until the unit is no longer indirectly used.
- This allows you to answer some of these questions...
- How critical is this piece of code to my application?
- How much of the application will have to be retested if I change this code?
- What benefits do I get from changing this code?
- Sometimes going through this exercise I have determined what I thought was a small problem has turned into a very large problem.
Great post. I noticed that many Delphi developers don't think about this much or just ignore it.
ReplyDeleteWhen someone showed his library and talked about how easy it all is and that you only have to add that one unit and then just write this 1 line of code to do things I noticed how much code it sucked into the application in the end which he totally ignored.
You should also be concerned about how the code is coupled to initialization sections. Because that means that just adding that unit because you want to use that tiny little function in there that has no dependency sucks in a bunch of things just because some code in the initialization section of that unit.
P.S. Its the red or the *blue* pill.