> If you aren't constantly trying to make 90% of the tasks simple enough for a boring team member to do then I don't know how you prevent the overall complexity of the system from eventually swamping you all.
One has to keep in mind that the things should be as simple as possible, but no simpler. Otherwise, you risk ending up with the stereotypical low-skill Java Enterprise shop, where inexperienced and not particularly skilled developers end up writing (or autogenerating) code by kilolines, where if someone better trained were to stop and think for an hour, it could all be done in 100-1000x less code, and with similar improvement in maintainability.
Yes, and for me the happy ratio is around a 90:10 split.
There is a time and place for really sophisticated code, and people will just have to expend some effort to understand its behavior at least, if not in fact how it accomplishes it. If that's leaking throughout the system then it's likely a code smell.
I'd like to reiterate that the statement you quoted was made in the active voice. It's a process. As you add things to the system you should be looking at all of the pain points around it and amortizing the cost of addressing those issues. If you don't arrive there around the time the system begins to gel, but before calcification, you will never arrive. But if you try to get there from day one, you'll pick the wrong priorities and you'll certainly end up in that Enterprise hell you mention.
What I see happen is that people grow with the project, memorizing one thing after another without ever appreciating the weight of it all, and then one day they have to hire more people because someone left, and all of a sudden they're terrified of letting that person do any real work. Because how could they know? Absolutely no effort has been expended setting new people up for success, and the token efforts feel more like sabotage than help. Then it takes years of their lives to memorize all the same stuff and really, I believe you should be investing that time in something more worthwhile. I'm living through that again and it's every bit as bad as I remembered.
Thank you for elaborating. What you wrote resonates very strongly, it's essentially the way it's been in every job I worked on. Hell, I'm guilty of it myself - once I have my own fiefdom in the codebase, I feel terrified of letting someone else work in it. In my mind, I have the vision of them struggling unproductively because they lack the knowledge about all the tiny little idiosyncrasies, of various design decisions that were never documented, etc. I recognize this is a wrong state of things, but it's hard to fix.
I feel like a step towards a solution to this problem (which I likewise observe), is to document these idiosyncrasies in the code. My rule of thumb is that when I write or read weird code that's necessarily weird (to avoid idiosyncrasies in downstream/upstream systems), I try to add a very concise clarifying comment that acknowledges the code as weird, and points in the direction of both the problem we're avoiding and some potential solutions to make the code less weird in the future.
For example, when reading an old codebase, if I invest 20 minutes in determining why the code differs from the documentation, I add a comment saying `NOTE(gen220): the code does not match the comment. The reason appears to be X. We might resolve this with Y or Z`. That, or update one of either the code or the comment, whichever makes the most sense in the situation.
That way, a new team member (or myself, but 2 years older) won't have to stumble in the same places, and are empowered to take a stab at fixing the problem, which has been documented for them.
Personally, when my idiosyncrasies are so-documented, I feel much safer handing things off.
Myself, recently I've been more often producing fresh code than working on someone else's, so I ended up aggressively documenting design decisions in code - most of them in top-level file comments, and the more local/tactical decisions within the scope they affect. I try to do that simultaneously with writing the code, because unless I write things down immediately, there's a good chance I'll never go back to put them in.
In my old age I use comments to write my code before I write the code. The comments explain in pseudo code what Im trying to accomplish.
# check to see if the user has a cart. The default state for
# users is to not have a cart. The original implementation
#created a cart for every visitor which resulted in 10s of
#thousands of unused carts.
# if the cart does not exist only create a new one because
# they are adding an item. You can never assume the user has
# a cart.
as I read code that isnt mine and figure out what it does, I write comments like the above about why I think it works that way. I will sometimes date the comments. You can do that with your own code as you make modifications or additions. It adds minimal overhead and is tremendous for when you go back later.
For a check like if i > 5 then do something I have seen comments like "check for i>5" which is obvious. I would want something like
# Im hardcoding a 5 here because <bad reason> so that when
#<whatever I represents is > 5 then we do <some stuff>
One has to keep in mind that the things should be as simple as possible, but no simpler. Otherwise, you risk ending up with the stereotypical low-skill Java Enterprise shop, where inexperienced and not particularly skilled developers end up writing (or autogenerating) code by kilolines, where if someone better trained were to stop and think for an hour, it could all be done in 100-1000x less code, and with similar improvement in maintainability.