> For my sins, and for lack of new work, I've been on maintenance (gaack!)
> for the last year or so.
On the threads asking "where'd the jobs go?" I have been been pointing out
they are in maintenance. The surviving companies these days must often
support code bases whose quality is not related to their companies'
Pride yourself in doing a good job. Yes, writing your own code from scratch
is fun and satisfying, but don't kid yourself that you know how to perform
activities that are sustainable as a project scales, either. You yourself
could have become the "original author" that made someone else's job
Mike Feathers is writing a book on legacy code, here:
I suspect it's worth a read.
Quote:> The original authors of the C++ code I've been
> debugging and/or enhancing have not only left the company, but have also
> left the COUNTRY. In the worst stuff, everything seems to have been
> "reified" to a fare-thee-well, with incredibly long (deep?) inheritance
> trees. The whole system of framework and application SEEMS to follow
> "correct" object design with information hiding, etc., but the end
> result is a nightmare to trace and debug.
It's probably quite >incorrect<, because it probably has parts that could be
removed, and duplication that could be folded together.
If you had tests that covered every statement, and approach covering every
path, and if the tests were hierarchical - such that some test a small unit
and others test a large module - then you could have a party deleting lines
and refactoring. But the odds you have tests are very low. Not many
programmers have absorbed the ideal that tests help them code faster.
> For example, to enter an item
> into a memory store, the sequence runs something like:
> 1. The item stores itself into the store.
> 2. The act of storing triggers an event in the store.
> 3. On triggering, each indexing object in the store creates a key
> object from the item and in turn creates an entry in itself.
> This is a simplification of a couple of KLOC, and with the conceptual
> callbacks actually looks more like spaghetti than structure.
> The kind of stuff that I've written in the past (and hopefully will
> write again in the future) goes something like:
> 1. The store pushes the item into the first free slot.
> 2. The store adds the key (instance variable) and slot to the
> indexing object(s).
> This comes out to about a tenth of the "objective" code.
What is "objective" about that crappy first code? If we actually needed all
that behavior, then we could conceivably exploit a situation where "the
item stores itself in the store", and then something different happens.
Quote:> I'd like some feedback on the concepts - is either way "wrong"? How
> objective or reified should designers make their software?
You need to learn more about OO - more than these authors did - before
asking if a program with "lots and lots of objects and methods" is somehow
"more" object oriented than one with the minimum statements between any two
Without tests, you can't take that cruft out. "cruft" means "fluff", because
the actual relevant functionality is a thin trace of operations within all
that code, and "crust", because the useless code between the useful code
has simply accumulated, gotten stuck, and dried hard. Separating the fluff
from the crust is now impossible. In some situations one simply re-writes.
Your goal is not to learn good OO from original programmers who obviously
did not know it. Your goal is not to refactor all this *mercilessly.
The code has a ponderous investment in debugging, manually testing, and
field testing. Whatever its sins, improving its structure will not make
your life easier. Preserve its investment, and only tiptoe thru this mine
field waiting to explode into lots of bugs.
Your goal is to learn to add automated tests to it, only to pin down
existing behaviors. A test on the system that saves would create an object,
save it, and assert that it is in the persistent store.
Then, for each bug report, ensure you can write a test that only fails if
the bug's alive, and only passes if it's dead.
Your work product is not beautiful new minimal classes. Your work product is
minimal changes that improve behavior, and a steadily growing test suite.
Read all the literature around CppUnit to learn what good tests look like.
But yours will not look good, because this code was not designed for
testing, and is probably completely coupled. Configure a Debug Mode version
of the program that executes its main() and start-up code normally. That
will set up all these coupled objects. Then your Debug Mode will use
conditional compilation to call a Test Suite. Start by testing the
lowest-level dirt-simple functions, to learn to test. Then test mid-level
objects, to see if they and their collaborators can actually re-use all
those allegedly re-usable bogus methods.
This strategy ensures, if a test breaks, you have no idea which module broke
it. Just hit Undo until the tests pass again, and try the change again.
Next, for each change request, treat it as a bug, and write a test that will
force the code to perform the new way.
-- Will the bailiff please remove the juror who started the wave --