Recent

Author Topic: How do you maintain your code?  (Read 1291 times)

TBMan

  • New Member
  • *
  • Posts: 47
How do you maintain your code?
« on: January 21, 2025, 06:10:56 pm »
I try to do the following for all of my projects that I'm coding. It really helps when I'm debugging and trying to trace a problem. When I go back to
look at code I wrote 30 years ago I shake my head and wonder why I didn't leave myself a road map. I don't use a lot of comments in my code
as I try to write with the intent being clear by how I name my procedures, functions and variables. I'm thinking though maybe a bit more commenting in my code could be helpful.

Here's my "content header" for the sprite editor that I'm working on. Naming the section allows me to search for the section easily.
Code: Pascal  [Select][+][-]
  1. {
  2.   SprEd - sprite editor  Started 1/20/25
  3.   Edits up to 20x20 sprites. Can be made to go with
  4.   bigger sprites if the graph mode size is increased.
  5.   It is currently using 800x600
  6.  
  7. 1/20/25
  8.   Started project
  9.   Got up to the width/depth dialog box, but without
  10.   the width bottons and with no functionality.
  11.  
  12. 1/21/25
  13.   Finished width/depth dialog, fully functional
  14.  
  15. ******************************
  16.  Section0 Initilization
  17. ******************************
  18.  Procedure InitProgram;
  19.  Procedure InitialGrid;
  20. ******************************
  21.  
  22. ******************************
  23.   Section1 Grid maintenance
  24. ******************************
  25. Procedure SetRectPositions(GridDepth,GridWidth:integer);
  26. Procedure drawGrid(Depth,width:integer);
  27. Procedure SetColorGrid;
  28. Procedure drawColorGrid;
  29. Procedure ClearGrid(depth,width:integer);
  30. Procedure DrawSpriteGrid(s:lg_spriteclass);
  31.  
  32.  
  33. *************************************
  34. Section2 Push button Event management
  35. *************************************
  36. Procedure CheckGrid(Wx,Wy:longint);
  37. Procedure GetColor(Wx,Wy:Longint);
  38. Procedure SaveSprite; fixed file name for now
  39. procedure LoadSprite; fixed file name for now
  40. Procedure Export;
  41.  
  42. *********************************************
  43. Section3 Graphics and function of pushbuttons
  44. *********************************************
  45. Procedure DrawButtonUp(Item:Integer);
  46. Procedure DrawButtonDown(Item:Integer);
  47. Procedure AddButton(x,y,xx,yy:integer;Id:Integer;Ts:string);
  48. Procedure MenuButtons; (Initializes all of the menu buttons)
  49.  
  50. *********************************************
  51. Section4 Graphics and function of checkboxes
  52. *********************************************
  53. Procedure DrawCheckBox(CheckBox:CheckBoxType);
  54. Procedure AddDepthCheckBox(x,y,Id:integer;Ts:String;default:boolean);
  55. Procedure AddWidthCheckBox(x,y,Id:integer;Ts:String;default:boolean);
  56. Procedure ChangeSize;   (Executes the Change size dialog with local event handler)
  57. }
  58.                                

cdbc

  • Hero Member
  • *****
  • Posts: 1847
    • http://www.cdbc.dk
Re: How do you maintain your code?
« Reply #1 on: January 21, 2025, 06:21:11 pm »
Hi
I do it like this and sometimes I comment more, but never less...  ;D
Regards Benny
If it ain't broke, don't fix it ;)
PCLinuxOS(rolling release) 64bit -> KDE5 -> FPC 3.2.2 -> Lazarus 2.2.6 up until Jan 2024 from then on it's: KDE5/QT5 -> FPC 3.3.1 -> Lazarus 3.0

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 10812
  • Debugger - SynEdit - and more
    • wiki
Re: How do you maintain your code?
« Reply #2 on: January 21, 2025, 06:44:19 pm »
As for the "changelog" => what was added/changed when and in which order: I use git.

Even on private projects, even on small projects. I can always create a local git repository in the project folder (no remote needed).
If I want a backup, remote to either a different disk, or to a private repo at one of the common hosts. (Or a remote computer of my own, if the source must stay 100% private)

The advantage is, that not only can I see what (and why) I have done, but
- I can also see each line that changed, and how it changed
- I can search at what time a line was last changed (search by line, instead by time / blame)
- I can undo (for testing) any change I made and go back to any previous version
- I can do micro commits (every few minutes) while making changes, once they work I rebase them into just one commit (never again, I broke 5 hours of work in the last 5 minutes and don't know exactly where)
- I can keep "gone wrong" attempts in a branch in case I want to use any part of them later.


MarkMLl

  • Hero Member
  • *****
  • Posts: 8221
Re: How do you maintain your code?
« Reply #3 on: January 21, 2025, 06:52:10 pm »
Subversion locally (iff doing something collaborative I'd consider Git). A large number of carefully-phrased comments. A .project file in each main directory which tells me where I'm at.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Logitech, TopSpeed & FTL Modula-2 on bare metal (Z80, '286 protected mode).
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

440bx

  • Hero Member
  • *****
  • Posts: 5002
Re: How do you maintain your code?
« Reply #4 on: January 21, 2025, 07:45:59 pm »
One thing I learned the hard way is that what often seems to be totally obvious when writing the code is rarely obvious just a few months later.

My solution is to comment the code as if I were writing the program as a tutorial for an intermediate level programmer (IOW, some basic stuff isn't explained.)  This means a totally _lavish_ number of comments that _explain_ the "big picture" and how it is going to be implemented.

For non throw-away programs, I pay particular attention to the structure of the program.  I want the mainline to reflect the _entire_ program structure,  This is a bit hard to explain but, if a program consists of 50 logical steps then there should be a function/procedure that consists of 50 steps, ideally properly commented.

The other thing I have found extremely useful in the maintenance of code is to associate a particular test case with a particular sequence of code.  This way you know why the code is there and what problem it solves.  For instance, imagine you're implementing a dis-assembler (which needs to find and process many binary patterns),  it's good to place a comment such as:
Code: Pascal  [Select][+][-]
  1. { case found AcGenral.x32.dll cookie and scope record information after a ret }
  2. {                                                                                                                            }
  3. { 755E22C8 E8 73 00 00 00                                               call    __SEH_epilog4                                }
  4. { 755E22CD C2 0C 00                                                     retn    0Ch                                          }
  5. { 755E22CD                                                                                                                   }
  6. { 755E22D0 FE FF FF FF 00 00 00 00 D4 FF FF FF 00 00 00+stru_755E22D0   dd 0FFFFFFFEh           ; GSCookieOffset             }
  7. { 755E22D0 00 FE FF FF FF 74 97 5E 75 85 97 5E 75 FE FF+                                                                     }
  8. { 755E22D0 FF FF 8F 97 5E 75 A0 97 5E 75 FE FF FF FF B0+                dd 0                    ; GSCookieXOROffset          }
  9. { 755E22D0 97 5E 75 C1 97 5E 75 FE FF FF FF E7 97 5E 75+                dd 0FFFFFFD4h           ; EHCookieOffset             }
  10. { 755E22D0 F8 97 5E 75 FE FF FF FF 19 98 5E 75 2A 98 5E+                dd 0                    ; EHCookieXOROffset          }
  11. {                                                                                                                            }
  12. { 755E22D0 75 FE FF FF FF 58 98 5E 75 69 98 5E 75 FE FF+                dd 0FFFFFFFEh           ; ScopeRecord.EnclosingLevel }
  13. { 755E22D0 FF FF 79 98 5E 75 8A 98 5E 75 FE FF FF FF C3+                dd offset loc_755E9774  ; ScopeRecord.FilterFunc     }
  14. { 755E22D0 98 5E 75 D4 98 5E 75                                         dd offset loc_755E9785  ; ScopeRecord.HandlerFunc    }
  15. { 755E22D0                                                              dd 0FFFFFFFEh           ; ScopeRecord.EnclosingLevel }
  16. { 755E22D0                                                              dd offset loc_755E978F  ; ScopeRecord.FilterFunc     }
  17. { 755E22D0                                                              dd offset loc_755E97A0  ; ScopeRecord.HandlerFunc    }
  18. { 755E22D0                                                              dd 0FFFFFFFEh           ; ScopeRecord.EnclosingLevel }
  19. { 755E22D0                                                              dd offset loc_755E97B0  ; ScopeRecord.FilterFunc     }
  20. { 755E22D0                                                              dd offset loc_755E97C1  ; ScopeRecord.HandlerFunc    }
  21. { 755E22D0                                                              dd 0FFFFFFFEh           ; ScopeRecord.EnclosingLevel }
  22. { 755E22D0                                                              dd offset loc_755E97E7  ; ScopeRecord.FilterFunc     }
  23. { 755E22D0                                                              dd offset loc_755E97F8  ; ScopeRecord.HandlerFunc    }
  24. { 755E22D0                                                              dd 0FFFFFFFEh           ; ScopeRecord.EnclosingLevel }
  25. { 755E22D0                                                              dd offset loc_755E9819  ; ScopeRecord.FilterFunc     }
  26. { 755E22D0                                                              dd offset loc_755E982A  ; ScopeRecord.HandlerFunc    }
  27. { 755E22D0                                                              dd 0FFFFFFFEh           ; ScopeRecord.EnclosingLevel }
  28. { 755E22D0                                                              dd offset loc_755E9858  ; ScopeRecord.FilterFunc     }
  29. { 755E22D0                                                              dd offset loc_755E9869  ; ScopeRecord.HandlerFunc    }
  30. { 755E22D0                                                              dd 0FFFFFFFEh           ; ScopeRecord.EnclosingLevel }
  31. { 755E22D0                                                              dd offset loc_755E9879  ; ScopeRecord.FilterFunc     }
  32. { 755E22D0                                                              dd offset loc_755E988A  ; ScopeRecord.HandlerFunc    }
  33. { 755E22D0                                                              dd 0FFFFFFFEh           ; ScopeRecord.EnclosingLevel }
  34. { 755E22D0                                                              dd offset loc_755E98C3  ; ScopeRecord.FilterFunc     }
  35. { 755E22D0                                                              dd offset loc_755E98D4  ; ScopeRecord.HandlerFunc    }
  36. { 755E2340                                                                                                                   }
  37. { 755E2340 8B 4D F0                                                     mov     ecx, [ebp-10h]                               }
  38. { 755E2343 64 89 0D 00 00 00 00                                         mov     large fs:0, ecx                              }
  39. { 755E234A 59                                                           pop     ecx                                          }
  40.  
  41.  
above the code that takes care of detecting and handling that pattern.

Another important characteristic of a well written program is that every path is individually tested during development.  One method that is quite useful is to force if statements to execute an empty statement thereby forcing the code that is normally conditionally executed to execute.  Here is what I mean:
Code: Pascal  [Select][+][-]
  1. if <some condition> then
  2.   {$if defined test_some_condition} ; {$endif}
  3. begin
  4.   < statements executed when "some condition" is true >
  5. end;
  6.  
This way, all you need to do to figure out if the statements deal with the condition correctly is to define "test_some_condition".

As a consequence of the above, there should be one include file in the project that list _every single one_ of these cases along with an informative comment giving details of what is being tested and what the intended result of the test is expected to be.

Another thing that makes a substantial difference after a few months (or a few years) is to have hard coded breakpoints that are conditionally executed in the code.  Those breakpoints should exists in places that are _important_, for instance, if an assert condition fails during testing and development.  Also convenient is to place them in important/critical functions.  For instance, using the dis-assembly example, imagine there is a function that scans and detects int 3 sequences (compilers commonly generate those for one reason or another), the dis-assembler can have a set of defines such as:
Code: Pascal  [Select][+][-]
  1. {$define BREAK_ScanForInt3sequences_Enter}
  2.  
  3.   {$define BREAK_ScanForInt3sequences_AddressValue}
  4.   {$define BREAK_ScanForInt3sequences_ScanAbandoned}
  5.  
  6.   {$define BREAK_ScanForInt3sequences_Int3IsJmpArgument}
  7.  
  8.   {$define BREAK_ScanForInt3sequences_Int3InAddress}
  9.  
  10. {$define BREAK_ScanForInt3sequences_Exit}
  11.  
activating the first define causes a break when the function is entered.  The indented defines are additional breakpoints in the function that are triggered only when specific cases occur.

That way, it's easy to "reload" in your mind what the function does.

A "corollary" of all this is that a good debugger is an _essential_ tool in the analysis and maintenance of a program.

Those are just a few things (less than 10%) about writing maintainable code.  It is very, very rare to find a program that is written with maintainability in mind.  It's amazing some programs can be maintained at all.  What's _not_ amazing is the presence of bugs in them (because often code is added or modified with only a _partial_ understanding of how the code work (presuming it works at all.)

For a lot of programmers, the above is way too much work.  IMO, that reflects how "valuable" the code is.

For the record, many decades ago, I spent about 5 years developing an algorithm to solve a problem.  It was pure research.  I threw code at the computer for 5+ years and one day, lo and behold, I found the solution to the problem (to this day, it's only known solution to the problem), I was ecstatic, wearing a smile from ear to ear. 

Now the sad part, I never commented any of the algorithms in the program because I didn't know if they were part of the solution of not and it didn't cross my mind that I would forget how the solution works.

Every algorithm was just "another thing to try".  To make a long story short,  the program consists of hundreds of different algorithms, a _subset_ of them, executed in a _specific_ sequence, solves the problem.  Now the problem is, I eventually _forgot_ which functions and their sequence solve the problem and, since there are no comments, I'd have to figure it out all over again (it wouldn't take 5 years but, it would still be a fair amount of time.)

As a result of that, now, every program that is of intermediate complexity or above, I write it as a tutorial to myself.  Now, I can look at code I wrote 15 years ago and, usually, in less than 30 minutes I have the whole thing back in my mind.

HTH.

(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

lainz

  • Hero Member
  • *****
  • Posts: 4689
  • Web, Desktop & Android developer
    • https://lainz.github.io/
Re: How do you maintain your code?
« Reply #5 on: January 21, 2025, 08:13:35 pm »
That shows a bit of how old are you If you coded more than 15 years...

I personally use git, and is a time saver when finding bugs, because one can search the logs and find specifically modified files in a timeline. To see if a change was made or not, possible bug sources...

440bx

  • Hero Member
  • *****
  • Posts: 5002
Re: How do you maintain your code?
« Reply #6 on: January 21, 2025, 08:20:25 pm »
That shows a bit of how old are you If you coded more than 15 years...
I've been coding for 48 years... I started young... live and learn (sometimes the easy way and sometimes the hard way... oh well.)
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

lainz

  • Hero Member
  • *****
  • Posts: 4689
  • Web, Desktop & Android developer
    • https://lainz.github.io/
Re: How do you maintain your code?
« Reply #7 on: January 21, 2025, 08:23:38 pm »
That shows a bit of how old are you If you coded more than 15 years...
I've been coding for 48 years... I started young... live and learn (sometimes the easy way and sometimes the hard way... oh well.)

You coded for more years than my actual age, 35, I started coding at 17, but in a company since 2018.

MarkMLl

  • Hero Member
  • *****
  • Posts: 8221
Re: How do you maintain your code?
« Reply #8 on: January 21, 2025, 09:20:55 pm »
I've been coding for 48 years... I started young... live and learn (sometimes the easy way and sometimes the hard way... oh well.)

48 or 49... sounds about right if you include my student FORTRAN.

Fun fact: on the day I joined Burroughs, the site to which I was told to report was upgrading its mainframe from core to semiconductor memory.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Logitech, TopSpeed & FTL Modula-2 on bare metal (Z80, '286 protected mode).
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

dbannon

  • Hero Member
  • *****
  • Posts: 3219
    • tomboy-ng, a rewrite of the classic Tomboy
Re: How do you maintain your code?
« Reply #9 on: January 22, 2025, 01:23:24 am »
Fun fact: on the day I joined Burroughs, the site to which I was told to report was upgrading its mainframe from core to semiconductor memory.

semiconductor memory ? Just a passing fad. At least with magcore, you can see where your data is being kept !

Davo
Lazarus 3, Linux (and reluctantly Win10/11, OSX Monterey)
My Project - https://github.com/tomboy-notes/tomboy-ng and my github - https://github.com/davidbannon

Wesbat

  • New Member
  • *
  • Posts: 37
    • engrams.dev
Re: How do you maintain your code?
« Reply #10 on: January 22, 2025, 09:03:46 am »
For the past year I decided to try write more idiomatic code: break large pieces of work into smaller routines, each has its own job. I name them sensibly to describe their function. This negates the need for comments most of the time.

There are always exceptions. If a routine can't be reduced to simplicity then I add comments to demarcate notable logic, I try describe why something is done this way, not just what is happening.

On the back-end I use git locally. Been writing code for 30 years. Magic times!

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 10812
  • Debugger - SynEdit - and more
    • wiki
Re: How do you maintain your code?
« Reply #11 on: January 22, 2025, 12:21:29 pm »
About documentation and comments.

"assert" is a good way to do that.

It may not be as verbose as a whole paragraph of comment, but it can still be quite verbose. The good thing however is, it protects itself from being outdated. That is, assuming the code is regularly run with assertions enabled. And, if needed, there can be whole blocks/groups of asserts.

Also it is a slightly different way of documentation.
Code: Pascal  [Select][+][-]
  1. assert(SearchIdx>LastResult, 'Function-Name: SearchIdx>LastResult / Description why that must be');

Does give 2 vital bits of info.

1) Any further use of SearchIdx is safe. If I placed the assert there, then I have checked (considering all possible code-paths that could lead to this line) that the condition must be true. The assert documents this. I can read any code below this, with the knowledge, that the code above does ensure this.

2) Whatever I put in the description. If I added description.

If the code changes, so the condition does not hold any more, then I am forced to update it. Had that just been a comment, it might be overlooked and become false info.

 

TinyPortal © 2005-2018