Well, the measure I use, or like to think I use, is this:
For each independent, single, one-line, take-it-or-leave-it functional requirement, snapshot the code base before implementing it. Then implement it, including finding and fixing any bugs introduced in the process. Then run a diff
between the code base before and after. The diff
will show you a list of all the insertions, deletions, and modifications that implemented the change. (Like inserting 10 consecutive lines of code is one change.) How many changes were there? The smaller that number is, typically, the more maintainable the code is.
I call that the redundancy of the source code, because it's like the redundancy of an error-correcting code. The information was contained in 1 chunk, but was encoded as N chunks, which all have to be done together, to be consistent.
I think this is the idea behind DRY, but it's a little more general. The reason it's good for that count to be low is, if it takes N changes to implement a typical requirement, and as a fallible programmer you only get N-1 or N-2 of them done correctly at first, you've put in 1 or 2 bugs.
On top of the O(N) programming effort, those bugs have to be discovered, located, and repaired. That's why small N is good.
Maintainable does not necessarily mean readable, to a programmer who has not learned how the code works.
Optimizing N may require doing some things that create a learning curve for programmers.
Here's an example.
One thing that helps is if the programmer tries to anticipate future changes and leaves how-to directions in the program's commentary.
I think when N is reduced far enough (the optimum is 1) the source code reads more like a domain-specific-language (DSL). The program doesn't so much "solve" the problem as it "states" the problem, because ideally each requirement is just restated as a single piece of code.
Unfortunately, I don't see people learning how to do this very much. Rather they seem to think that mental nouns should become classes, and verbs become methods, and all they gotta do is turn the crank. That results in code with N of 30 or more, in my experience.