Sometimes you get the most brilliant of ideas in the shower after your work day, and you just can't wait till you get back to work next day (also because you know you'll have a ton of meetings anyways).
I work very late into nights on the project I created. I hate myself sometimes for doing this because this now the company's cash cow and I get nothing more than any other engineer. I've contemplated quitting but I see no benefit to this, it's still one of the coolest projects I've worked on. It's not just legal ownership that can drive people.
Reading your comment and the parent gave me goosebumps, I might be guilty of being this type of engineer.
I created a side project that became its own very successful product, and now there are a couple of other engineers in the team and I'm the "tech lead". We have a front end and backend component, and I have another brilliant full stack taking full charge of the frontend. the other two engineers are _very_ mediocre at best. The code is complex partly because I (without formal training) wrote it all myself, but also because it's a very complex priduct, not just a CRUD. I'm Constantly stymied by the fact that on the backend, asking the mediocre engineer to do something means it will take a full Sprint instead of the two hours it'll take me. The other engineers are also not able to fully understand the PRs (because the code is still too complex to them after six months joining the project) so I feel minimal upside to wait for their code reviews (which I still do anyways). I've asked to staff with better engineers but given the complexity of the product (directly query very large datasets with very complex jobs from a clean frontend) and our small orgs inability to attract great talent, I'm not getting anyone.
I'm forced with two possibilities:
1. Ask for the mediocre engineers to be removed from the team, and continue working on the backend solo (but making it actively a job to document and make it as easy as possible for a good engineer to take over after me). This would actually boost productivity 2x from what we are now frankly.
2. I stop coding fully or slow down 5x and work primarily as just someone who asks others to code. It would probably slow us down 3-4x,but I suppose it'll match the pattern of a regular team, though to what end I don't know.
Is there any advice you can give? I'm sure I'm not seeing something obvious here that I'm doing wrong, and am fully open to honest input.
I think you're failing to prioritize the right things about your code.
The primary purpose of source code is to be understandable and manipulable by other engineers. No matter how well it accomplishes its goals, it's not "good code" unless it can be understood by other people.
I question whether you're actually working with a "very complex product" - it might just be that the way you're representing it is complex. If the code is still too complex to other engineers after 6 months, it's not the engineers who are wrong. At 6 months they should deeply understand some parts of the code and have confidence about diving into and understanding other parts with some ramp-up time.
I say this as someone who writes a lot of code that other people find hard to understand because it's "clever", and it's taken me a long time to fully internalize that, when someone else can't pick it up, it's not their problem, it's mine. Code is user interface, and good user interface meets the users where they are, not where you wish they would be.
Honestly, this aspect of software engineering is really the bottom line hardest part - it's not getting a working binary out of the compiler/interpreter, it's about getting a living system to evolve well. That means nomenclature and abstractions have to be top notch, not just the algorithms.
There's an old saw about "if it's twice as hard to debug code as to write it, never write code that's more than half as clever as you're capable of, otherwise you'll by-definition be unqualified to debug it", and I think there's a lot of truth there. One of my old director of operations used to say "If you can't run the playbook at 3am after being at the bar, it still needs work", and I think that's also true of non-ops related code.
Your next step is to reorient your role: your job is no longer to ship features, your job is to make the code easier for your coworkers to execute in. You're right that you'll "stop coding" as seen by management: your new bosses are your coworkers. Treat them as your customers, have them file tickets, the whole nine yards. When you reach the point that your coworkers are faster at getting things done than you are at the moment, then you can turn your sights back to production work, but until then, your job is technical debt remediation.
> The primary purpose of source code is to be understandable and manipulable by other engineers.
I've never worked in a fantastical position like this. The only purpose of the source code that I've been a part of was to provide a real solution to a real problem, in a limited amount of time, with too few resources. Technical debt always increased slowly until features are removed or break, forcing some dedicated work.
Can I ask what industry you're involved in where code quality is held higher than profit/deadlines/solutions? I would happily make the jump.
I've worked in a lot of industries from heavily-regulated healthcare, financial, core developer tooling, and a lot of YC startups. It always pays off in the end to consider code primarily for engineers, and every time I see people take those kinds of shortcuts in non-bet-the-company situations, they regret it. Especially in situations where you're handling large flows of cash or data, a percentage point can sink your entire business. Certainly a HIPAA violation can add zeros quickly.
I've actually been doing a lot of turnaround consulting with companies that took a short term mindset, got stuck, and had to step back and revamp their technical processes like you say. It's always more expensive to redo it after the fact, but I'm happy to take their money and fix their mistakes.
And that's not to say that it's not a tradeoff, but it's about being conscious of the tradeoffs involved and making reasonable choices.
I’ve worked on code that’s both ways. That is, either:
(1) spaghetti code that relies on the author having a great deal of it memorized. It uses opaque types that get passed through multiple modules. There is no hard separation of modules. Consequently it’s easy for someone who knows the system to reach into any part from one part and immediately get something done. However it’s a nightmare to make changes on otherwise. Unless you have an near-eidetic memory, it will likely negate any coding skills.
(2) Strongly typed and modularized code that takes advantage of advanced language features. In this case, it requires somebody of a certain proficiency in the language, but they only need to focus on one module at a time, and the compiler will stop them from violating architectural assumptions.
And these aren’t mutually exclusive, nor are they binary.
I'm guilty of that sort of thing as well (doing something complex without enough training to properly code it).
Story time to drive home my points: I started 7 years ago, fresh out of uni with a diploma, but not enough experience, and did something overly complex, with a lot of frankly bad code. Then, 5 years ago, we expanded the team (which means I was no longer the sole developer, but we were now 2).
At first, I was not satisfied with the other developer (fresh out of uni as well). Instead of trying to fire him, I bit the bullet and answered every question, took a lot of time to explain things to him. Yes it slowed me a lot. It also forced me to up my game to make our codebase readable (not MY code, our codebase), add comments etc...
In the end, he is now a valuable team member (we are still only 2 devs, with the occasional intern) who knows most of the codebase as well, if not better, than me. It has been the case since about 3 years (it took him 6 months to have a decent development speed, and about 2 year to develop at about the same speed as me). Neither of us consider himself a "rockstar" developer and that's fine. We work as a team, and as a result our code is better, faster, more readable and as less bugs. I couldn't achieve that level alone no matter how much I tried.
To sum up: train them relentlessly, without loosing patience, and use that as an opportunity to make the codebase more readable.
You didn't mention how much time those engineers have been working with you though. Common knowledge is that it takes at least about 3 months to be proficient with a codebase you are new to. More if you are not experienced.
Programming is a trainable pursuit. Perhaps they are mediocre, or perhaps they are even bad. So, the best thing you can do is spend a significant portion of the time pair programming and seeing the project through their eyes.
Second, you probably should be taking some of that time you are coding and instead extensively documenting how it works, the design methodology, and making sure the unit tests are covering the code. After all, there are many implicit decisions in the code that they have to re-discover.
If you don't have tests, it makes working on a project as a new engineer difficult because you have no guard rails to know if something broke, especially because the specification is only in your head.
If you invest in your other engineers and in the process, they will become much faster and that slow down is a temporary bump in the road.
In fact, I might say that pretty much every engineer will be guilty of this if they have been in the industry long enough.
It doesn't mean you're evil! It just means you're the one who created a bunch of stuff and naturally you can work with your own stuff more efficiently than others can.
In fact I actually was "this guy" with one section of the code at my old company; the one where we had the "faux 10x" architect-dictator. I did manage to achieve a fairly clean transition once my involvement in that bit of the code ended.
Ask for the mediocre engineers to be
removed from the team
It sounds like this codebase is significantly complicated that even above-average engineers might find it an uphill battle. Is this true? If so, perhaps the answers are the largely the same whether or not the mediocre engineers are replaced.
"asking the mediocre engineer to do something
means it will take a full Sprint instead of
the two hours it'll take me"
"[Transitioning from coder to mgmt/mentor]
would probably slow us down 3-4x"
How many hours of useful coding do you do per day? There are a lot of studies that suggest even great engineers don't code for more than a few hours per day. I don't think I'm great, but this definitely applies to me.
Maybe you could divide your time in a way that's not too painful. Perhaps you could spend a fixed 1-2 hours per day on knowledge transfer (pair programming, etc) and not impact your productivity.
Here's what I would say.
0. Get buy-in from the rest of the management/leadership team. They should fully support your efforts to get others up to speed. Tell them you are concerned about being the only one who can maintain the product effectively. They should NOT want you, personally, to remain an indispensible single point of failure. What if you leave? What if you are hit by a bus?
1. As I said above, if you can devote perhaps 25% of your week to full-time knowledge transfer, you might find that you accomplish a lot without sacrificing your other productivity unduly.
2. Pair programming is, I think, the fastest form of knowledge transfer. An hour or two of pairing with the newbie engineers at the outset of a task goes a LONG way and may save dozens of hours later in the sprint. It sounds like these engies should never, ever begin a task without this guidance from you. They will learn the code, they will learn the thought process that went into the code, and they will learn your problem-solving process.
3. Is your test suite awesome? Writing or improving tests can be an excellent way for folks to get up to speed on the code in a low risk way. And a strong test suite has long-lasting benefits. If you don't have a test suite at all, even a very rudimentary one will reap large rewards down the road.
4. I document my code (via inline code comments) more than most. My opinion is that if a bit of code represents a non-obvious technical kludge, or a bit of business logic, it should have an explanatory note. Theoretically this could be accomplished via diligent commit messages, but sifting through hundreds of commit messages is awfully tough.
5. YOUR ENGINEERS ARE PEOPLE. Working on your legacy hairball of code is... frustrating. Recognize their pain. Be sure to get them some "wins" on a regular basis so they can feel good. Praise their efforts in private, and in front of others in meetings.
Good luck to you! My email is john edmund rose "at" gmail if you want to correspond. I'd like that!
“Average” engineers manage to be productive with React, Spring, WPF[1]... These are not simple technologies. Why can’t “average” engineers be productive with my stuff?
Quite often it’s because these bigger, more complex, projects have far more comprehensive docs.
It sounds like this codebase has a fair few abstract concepts in it. Those things can be hard to understand without comments and docs explaining core concepts.
Sequence diagrams are also great. I like generating sequence diagrams from logs during automated testing so they never go out of date.
I also find it useful to have docs at the top of each class (or file) explaining 1. what its responsibilities are, and 2. what it collaborates with. Like the old CRC cards.
Obviously this stuff can drift out of date, but it’s less of a problem with the core bits of the system once they’ve settled a bit.
If they don’t exist already, it’s nice to write docs by pairing with new devs.
It is of course possible your engineers really aren’t up to the job, in which case the effort you put in to explaining things now will still make things easier for their eventual replacements.
I had all this wrong for so many years.
[1] whether these are “good” technologies is beside the point here
The telephone game taught me why there should be a “how the system works” runbook in writing. At 3 AM, I don’t want to try to remember the lecture I got from someone who was trying to remember the lecture they had gotten from Saint Paul or whomever.