Breaking Up is Hard To Do

Recently, I broke up a very large unit I had been working on for some time.  The unit contained objects that referenced each other in their type declaration.  This was possible since the declarations were resolved by the compiler in the same Type section, and the compiler allowed for this by way of forward declarations.

I started working on this unit long before I really understood the ‘circular references problem’.  I had read complaints about circular references before including a QC request to get rid of them altogether.  My answer at the time was simple; put them all in the same unit and use forward declarations.  The problem with this approach is as follows:

a) The unit grows to the point where you need GExperts, CodeRush or some other tool that provides rapid navigation to the class declaration and implementation.  Otherwise you spend more time finding stuff than writing code.

b) It becomes impossible to re-use one class in a different project.  The dependancies grow over time, and become very difficult to unravel at a later date.  Relying on dead code elimination is not advisable and compile times can increase dramatically for a little project if you start including some mammoth units.

c) More units, means easier group development.  If you’re using a CheckOut - Modify - CheckIn process, it will dramatically increase your ability to make changes.  In a Modify - Commit - Merge model, it will make merging changes easier.

d) fixing the problem is just plain painful.  I had to change numerous type declarations to use TObject and then cast the object reference to the appropriate type in the implementation.  This meant lots of compile cycles to find all the places I missed, and correct the uses clauses in all the new units.  On top of this grief was the fact I references private fields of other objects, so when I broke them apart, I had to add properties on some objects and resolve all the ‘undeclared identifier’ compiler errors.  It reminded me how much I hated the loose scoping rules Delphi originally had.  The earlier I had done this, the less painful it would have been, but I never stuck it out to the end before (about 10 hours worth of work).

What I re/learned?

The value of a simple principle.  One Class Per Unit.  Think of it as the Single Responsibility Principle for Units.  If you start developing using this mantra, you can never go wrong.  It will force better class design, and reduce class coupling giving you more re-usability in the process.

Leave a Reply