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:
{ case found AcGenral.x32.dll cookie and scope record information after a ret }
{ }
{ 755E22C8 E8 73 00 00 00 call __SEH_epilog4 }
{ 755E22CD C2 0C 00 retn 0Ch }
{ 755E22CD }
{ 755E22D0 FE FF FF FF 00 00 00 00 D4 FF FF FF 00 00 00+stru_755E22D0 dd 0FFFFFFFEh ; GSCookieOffset }
{ 755E22D0 00 FE FF FF FF 74 97 5E 75 85 97 5E 75 FE FF+ }
{ 755E22D0 FF FF 8F 97 5E 75 A0 97 5E 75 FE FF FF FF B0+ dd 0 ; GSCookieXOROffset }
{ 755E22D0 97 5E 75 C1 97 5E 75 FE FF FF FF E7 97 5E 75+ dd 0FFFFFFD4h ; EHCookieOffset }
{ 755E22D0 F8 97 5E 75 FE FF FF FF 19 98 5E 75 2A 98 5E+ dd 0 ; EHCookieXOROffset }
{ }
{ 755E22D0 75 FE FF FF FF 58 98 5E 75 69 98 5E 75 FE FF+ dd 0FFFFFFFEh ; ScopeRecord.EnclosingLevel }
{ 755E22D0 FF FF 79 98 5E 75 8A 98 5E 75 FE FF FF FF C3+ dd offset loc_755E9774 ; ScopeRecord.FilterFunc }
{ 755E22D0 98 5E 75 D4 98 5E 75 dd offset loc_755E9785 ; ScopeRecord.HandlerFunc }
{ 755E22D0 dd 0FFFFFFFEh ; ScopeRecord.EnclosingLevel }
{ 755E22D0 dd offset loc_755E978F ; ScopeRecord.FilterFunc }
{ 755E22D0 dd offset loc_755E97A0 ; ScopeRecord.HandlerFunc }
{ 755E22D0 dd 0FFFFFFFEh ; ScopeRecord.EnclosingLevel }
{ 755E22D0 dd offset loc_755E97B0 ; ScopeRecord.FilterFunc }
{ 755E22D0 dd offset loc_755E97C1 ; ScopeRecord.HandlerFunc }
{ 755E22D0 dd 0FFFFFFFEh ; ScopeRecord.EnclosingLevel }
{ 755E22D0 dd offset loc_755E97E7 ; ScopeRecord.FilterFunc }
{ 755E22D0 dd offset loc_755E97F8 ; ScopeRecord.HandlerFunc }
{ 755E22D0 dd 0FFFFFFFEh ; ScopeRecord.EnclosingLevel }
{ 755E22D0 dd offset loc_755E9819 ; ScopeRecord.FilterFunc }
{ 755E22D0 dd offset loc_755E982A ; ScopeRecord.HandlerFunc }
{ 755E22D0 dd 0FFFFFFFEh ; ScopeRecord.EnclosingLevel }
{ 755E22D0 dd offset loc_755E9858 ; ScopeRecord.FilterFunc }
{ 755E22D0 dd offset loc_755E9869 ; ScopeRecord.HandlerFunc }
{ 755E22D0 dd 0FFFFFFFEh ; ScopeRecord.EnclosingLevel }
{ 755E22D0 dd offset loc_755E9879 ; ScopeRecord.FilterFunc }
{ 755E22D0 dd offset loc_755E988A ; ScopeRecord.HandlerFunc }
{ 755E22D0 dd 0FFFFFFFEh ; ScopeRecord.EnclosingLevel }
{ 755E22D0 dd offset loc_755E98C3 ; ScopeRecord.FilterFunc }
{ 755E22D0 dd offset loc_755E98D4 ; ScopeRecord.HandlerFunc }
{ 755E2340 }
{ 755E2340 8B 4D F0 mov ecx, [ebp-10h] }
{ 755E2343 64 89 0D 00 00 00 00 mov large fs:0, ecx }
{ 755E234A 59 pop ecx }
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:
if <some condition> then
{$if defined test_some_condition} ; {$endif}
begin
< statements executed when "some condition" is true >
end;
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:
{$define BREAK_ScanForInt3sequences_Enter}
{$define BREAK_ScanForInt3sequences_AddressValue}
{$define BREAK_ScanForInt3sequences_ScanAbandoned}
{$define BREAK_ScanForInt3sequences_Int3IsJmpArgument}
{$define BREAK_ScanForInt3sequences_Int3InAddress}
{$define BREAK_ScanForInt3sequences_Exit}
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.