Minimize side effects (ideally have none)
A function that causes 3 changes to states outside of its own scope is much more difficult to reason about and maintain than one just which just inputs something and outputs something else. You can't just know what the function does, you have to remember what it did and how that effects all other relevant functions.
For OOP minimizing side effects also means classes with fewer members, and especially fewer members that can modify the class's state, since member functions can modify states beyond their own and have side effects (they can manipulate the class's internals, e.g.). It also means classes with fewer data members of their own so that there's less state for those methods to tamper with and fewer side effects they can cause.
As a simple example, imagine trying to design a fancy data structure which can maintain a sorted
state which it uses to determine whether to perform binary or linear searches. In such a case, it might be useful to separate the design into two classes. Calling sorted
on the unsorted class might then return a data structure of another class which always keeps its contents sorted. Now you have less side effects (therefore less error-prone and easier to comprehend code) as well as more widely applicable code (the former design would be wasteful both in processing and human intellectual efficiency for small arrays that never need to be sorted).
Avoid Superfluous External Dependencies
You might be able to implement the most terse code imaginable with maximum code reuse by using 13 different libraries to accomplish a relatively simple task. However, that transfers intellectual overhead to your readers by then having to make them understand at least parts of 13 different libraries. This inherent complexity should be immediately appreciated by anyone who tried to build and comprehend a third party library which required pulling in and building a dozen other libraries to function.
This is probably a very controversial view but I would prefer some modest code duplication to the opposite extreme provided the end result is well-tested (nothing worse than untested faulty code duplicated many times over). If the choice is between 3-lines of duplicated code to compute a vector cross product or pulling in an epic math library just to shave off 3 lines of code, I'd suggest the former unless your entire team is on board with this math library, at which point you might still consider just writing 3 lines of code instead of 1 if it's trivial enough in exchange for the decoupling benefits.
Code reuse is a balancing act. Reuse too much and you transfer intellectual complexity in a one-to-many kind of way, as in those 3 lines of simple code you saved above comes at the cost of requiring the readers and maintainers to understand far more information than 3 lines of code. It also makes your code less stable, since if the math library changes, so too might your code. Reuse too little and you also multiply the intellectual overhead and your code ceases to benefit from central improvements, so it's a balancing act, but the idea that it's a balancing act is worth mentioning since trying to stamp out every little form of modest duplication can lead to a result that's as difficult to maintain, if not more, than the opposite extreme.
Test the Crap Out of It
This is a given but if your code doesn't handle all input cases and misses some edge cases, then how can you expect others to maintain code you wrote that you didn't even get right before it transferred to their eyes and hands? It's difficult enough to make changes to code that works perfectly let alone code which was never quite right in the first place.
On top of that, code that passes thorough tests is generally going to find fewer reasons to change. That relates to stability which is even more of a holy grail to achieve than maintainability, since stable code that never needs to be changed incurs no maintenance cost.
Interface Documentation
Prioritize "what things do" over "how things do them" if you can't devote equal time to documenting both. A clear interface that is obvious in its intentions about what it will do (or at the very least, what it's supposed to do) in all possible input cases will yield a clarity of context to its own implementation which will guide in understanding not only how to use the code, but also how it works.
Meanwhile code that lacks these qualities where people don't even know what it's supposed to do is SOL no matter how well-documented its implementation details are. A 20-page manual on how source code is implemented is worthless to people who can't even figure out exactly how it's supposed to be used in the first place and what it's even supposed to do in all possible scenarios.
For the implementation side, prioritize documenting what you do differently from everyone else. As an example, Intel has a bounding volume hierarchy for their raytracing kernels. Since I work in this field, I can recognize the bulk of what their code is doing at a glance without sifting through documentation. However, they do something unique which is the idea of traversing the BVH and performing intersections in parallel using ray packets. That's where I want them to prioritize their documentation because those parts of the code are exotic and unusual from most historical BVH implementations.
Readability
This part's very subjective. I don't really care that much about readability of a kind that's close to human thought processes. The most well-documented code describing things at the highest level is still difficult for me to follow if the author uses bizarre and convoluted thought processes to solve a problem. Meanwhile terse code using 2 or 3 character names can often be easier for me to understand if the logic is very straightforward. I guess you could peer review and see what other people prefer.
I'm mostly interested in maintainability and, even more importantly, stability. Code that finds no reasons to change is one that has zero maintenance costs.