#1 2010-12-17 08:12:04

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,207
Website

Don't weep, take a breath, and maintain

In a message posted in the EMB forum, Anthony wrote that he "inherited this stuff"... Maintaining a Delphi application pays the bills, but... is sometimes frustrating.

Here are some advices or experiment sharing.

Spaghetti coding, or copypasta are good cooking, but programming bad practice.

Another bad practice is the abuse of properties:

  for i := 0 to MyComp.Other.Array.Count-1 do
    for j := 0 to MyComp.Other.Array[i].List.Count-1 do
    begin
      MyComp.Other.Array[i].List[j].Prop := MyComp.Other.Array[i].List[0].Prop;
      MyComp.Other.Array[i].List[j].Prop2 := MyComp.Other.Array[i].List[j].Prop;
    end;

By using some local variables, or even the "with" keyword (with caution) code could be much easier to read and faster to execute.

Another awful problem, due to the RAD approach of Delphi, is the mixing of UI, database and logic in some quick-written applications. UI components are used to store data. UI components are used to manage data. And so... Quick to write. Hell to maintain! I really love the MVC or multi-tier architecture.

So let's stop weeping.

Here are perhaps some advices:

1) Don't get frustrated. You didn't write this.

2) Don't blame the one how wrote this. Remember your first program. Remember the first code you wrote in a new language.

3) Make some sport, play music, mow, or whatever: I'm running miles and miles, just to let the bad code pressure go away.

4) Don't start modifying the code. Since I guess there is no unitary testing, you could introduce regressions. Sometimes, there is some border effect which makes the application run...

5) First read, read, read, take a breath and read again. Try to guess how it works. If there is some technical documentation (but I'm quite sure there is none), try to find it, even if it's a deprecated old version. Take a pen and write diagrams, make a to-do list.

6) For the first modifications/fixes to introduce, try to use existing functions or classes. Add some methods.

7) But don't continue using globals, spaghetti code, copypasta and such in your code.

8) Comment your modifications inside the code.

9) Use some reverse-engineering tool, like our open source SynProject which is able to parse the units and retrieve some logic.

9) If you can modify heavily the code (if you are the only programmer, and you don't rely on a locking SCM), add comments

to existing code, as you're writing it.

10) If you can't modify the code, use external comments (we introduced it in our SynProject utility).

11) Write external documentation about what you did, which units you modified, and such. There is so many info to remember when you discover such a big application. Don't trust your memory, even for what you're writing. Start documenting everything.

12) The time you're spending commenting and documenting now will help you later. It's no wasted time. Whatever the project manager is telling you.

13) Try to figure out how you could make it better, changing the architecture into multi-tier, and so on.

14) After some successful fixes, try to get the green light to start a rewriting of the application. You can reuse some part of the existing code, but rely on "cleaner" approach, like ORM or MVC.

15) If you're cleared to rewrite the application, don't change to DotNet or Java. You can do anything in Delphi.

Offline

#2 2010-12-18 10:18:07

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,207
Website

Re: Don't weep, take a breath, and maintain

Kenneth Cochran wrote:

Ah yes. Train wrecks. One of the most blatant violations of
encapsulation. 'A' calls 'B' to get direct access to 'C'. If you ever
change the implementation of 'B' you have to perform shotgun surgery.

By using some local variables, or even the "with" keyword (with caution) code could be much easier to read and faster to execute.

Shudders at the mention of the word "with". Introducing ambiguous
context to save a few key strokes just isn't a good trade off.

Another awful problem, due to the RAD approach of Delphi, is the mixing of UI, database and logic in some quick-written applications. UI components are used to store data. UI components are used to manage data. And so... Quick to write. Hell to maintain! I really love the MVC or multi-tier architecture.

Couldn't agree more. Business logic shouldn't know or care anything
about the UI or data persistence.

4) Don't start modifying the code. Since I guess there is no unitary testing, you could introduce regressions. Sometimes, there is some border effect which makes the application run...

I would suggest getting a copy of "Working Effectively with Legacy Code"
by Michael Feathers. Its a treasure trove of techniques for massaging
untestable code into a test harness

8) Comment your modifications inside the code.
9) If you can modify heavily the code (if you are the only programmer, and you don't rely on a locking SCM), add comments
to existing code, as you're writing it.

Comments should be a last resort. Focus on making your code as easy to
understand as possible. If it still needs explanation after that go
ahead and add comments. Delete comments that are irrelevant or
misleading. And resist the urge to use comments as a journal of changes.
That's what version control logs are for.

10) If you can't modify the code, use external comments (we introduced it in our SynProject utility).
11) Write external documentation about what you did, which units you modified, and such. There is so many info to remember when you discover such a big application. Don't trust your memory, even for what you're writing. Start documenting everything.
12) The time you're spending commenting and documenting now will help you later. It's no wasted time. Whatever the project manager is telling you.

Just remember the code is the only documentation that stays accurate.
Everything else is temporal and grows more inaccurate as you make
changes to the code.

13) Try to figure out how you could make it better, changing the architecture into multi-tier, and so on.
14) After some successful fixes, try to get the green light to start a rewriting of the application. You can reuse some part of the existing code, but rely on "cleaner" approach, like ORM or MVC.
15) If you're cleared to rewrite the application, don't change to DotNet or Java. You can do anything in Delphi.

I must warn against a complete rewrite. Along with all the crap
spaghetti code is a ton of user requirements being met. Complex software
started as simple software and grew over time. Its very difficult to
re-implement an existing product and get every feature and nuance
correct. I have first hand experience with this. Having to tell your
boss the product is going to ship late and with fewer features than it
use to have is not a pleasant task.

I would suggest incremental rewrites one class at a time. And remember
everything you do should add business value. Refactoring to make it
easier to maintain adds value. Adding a new feature at the user's
request adds value. Making changes on a whim does not.

Offline

#3 2010-12-18 10:19:24

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,207
Website

Re: Don't weep, take a breath, and maintain

Thanks for sharing!
My comments/proposals were part of experiment, part of regulation needs (I worked in the pharmaceutical business, and FDA and IEC requirements are mandatory about documentation).

I would suggest getting a copy of "Working Effectively with Legacy Code"
by Michael Feathers. Its a treasure trove of techniques for massaging
untestable code into a test harness

Nothing matters but experiment.

Comments should be a last resort. Focus on making your code as easy to
understand as possible. If it still needs explanation after that go
ahead and add comments. Delete comments that are irrelevant or
misleading. And resist the urge to use comments as a journal of changes.
That's what version control logs are for.

Of course, comments are not a journal of changes. But sometimes version control logs are... not usable at all (if you've to maintain an old project, the associated SCM is probably a deprecated one, with deprecated log/review capabilities)...

Just remember the code is the only documentation that stays accurate.
Everything else is temporal and grows more inaccurate as you make
changes to the code.

Here is what I meant:
1) Include a system-wide and FMEA risk analysis to your documentation;
2) Use one document version per SW release;
3) Use some reverse-engineering parser (like the one included in SynProject) to create the documentation FROM the code;
4) Document your modifications using plain English, diagrams, and some code snippets;
5) For general/architecture layout (in plain English), just copy and paste the previous release version, then update it to be accurate;
6) Write in English, even if it's not your native language: I had to maintain a SW commented in dutch... You really feel sorry in such cases.

Therefore, the documentation will reflect the state of a particular release.
AND it will be available to reflect the exact changes made to the code, including a risk analysis.

Documentation is not evil. It could be a pain to write it, but it's useful, and sometimes mandatory - for regulation purpose.
Even if this documentation is never read by anyone. That's why I wrote SynProject: to make it easier to write and maintain.

I must warn against a complete rewrite. Along with all the crap
spaghetti code is a ton of user requirements being met. Complex software
started as simple software and grew over time. Its very difficult to
re-implement an existing product and get every feature and nuance
correct. I have first hand experience with this. Having to tell your
boss the product is going to ship late and with fewer features than it
use to have is not a pleasant task.

Of course, that's why staying to Delphi, and trying to reuse the reusable does make sense.
You'll have to stick to the time frame. This is priority one.

I would suggest incremental rewrites one class at a time. And remember
everything you do should add business value. Refactoring to make it
easier to maintain adds value. Adding a new feature at the user's
request adds value. Making changes on a whim does not.

If classes are bad written, from the architectural POV, it's sometimes pointless to rewrite one class a time.
Create a new class hierarchy, preserving as much "business" code as possible, but encapsulating it in a "fresh" hierarchy, could make sense.
I mean: kill globals, change the interfaces, re-factor the code by using small dedicated methods instead of plain spaghetti code.

Couldn't agree more about "everything you do should add business value".
We aren't here to make ourselves happy coders, but to have happy customers (and perhaps richer boss).
But maintainable and open minded code help adding new features. So makes your customer happy. wink

Offline

Board footer

Powered by FluxBB