Over the years, I'm able to help onboard junior marketers & junior designers to be productive by the 3rd month. Enough that they get fantastic results for our clients and they also get better career opportunities by the 3rd or 4th year (1.5x-2x pay than what I can afford as a self-funded company). While this is somewhat a problem for me, I'm confident with our marketing & design training program.
But for the life of me, I can't figure junior devs. I've been training this one guy for 2 years and still can't keep up. I've also hired another guy and he's a bit better, but he doesn't follow coding standards and still cannot ship good code. For the SaaS that we are building, while I thought that we have a junior-friendly stack, I ended up coding 98% of it. For now, they do some minor & less critical tasks (tasks which should take imo a day to finish -- but they end up finishing it in 7-14 days).
I thought I have good training program (i.e. I have an internal course on ruby & javascript that will need about 2 months to finish), but it seems that there's still something missing here.
While hiring better is an option, as a self-funded company, I don't have the luxury of talent as FAANG. Any advice on how to help & train the average or below average junior developer be decent would be appreciated. I'm quite frustrated but I do genuinely want to help, but I'm tempted to judge that some junior devs are just too talentless and too socially awkward to ever make it. I hope I can be proven wrong.
Stop doing that.
If you are trying to get a new team to take over your part of your coding work, you need to let go. Talk them through how you would do it, let them then give it a try... and then accept how they actually do it (as long as it works). When one person does all the work, it ends up being written in just the way that one person understands it and likes it. Which often leads to a lack of acceptance that different devs will accomplish the same task in different ways, and the original coder falls into this habit of "That isn't how I would have coded it, so it must be wrong."
Maybe I'm getting the wrong impression. Maybe you really are brilliant and 100% correct and you have hired nothing but duds. But... the odds are against that.
After that, the best place to continue learning is on code reviews in PRs. As @half0wl mentioned, it's importat to do it in both directions: you review their code, they review your code. This feedback loop will help your junior developers learn best practices and gain a better understanding of the codebase.
To facilitate these code review conversations, I recommend utilizing a tool like Pullpo.io (https://pullpo.io/products/channels), It allows you to have more enriching code reviews quickly on Slack, without wasting much time and being able to merge the PR sooner.
That said, learning curves can vary for individuals, and it's crucial to foster an environment of continuous learning and growth. But if after two years they can't keep up, i think it may not be the right person
I've found that code reviews are the best way to mentor and transfer knowledge. And it goes both ways: you review their code, they review your code. When I'm explicitly training someone, I get them to review my code and I occasionally throw in some minor curveballs that I expect them to pick up on in the first few rounds (e.g. obviously incorrect conditionals, some convoluted loop, leaky interfaces, etc.) If they stamp the PR without picking up on those items, I highlight it using a "do you think this is correct/is there a better way for us to do this" line of questioning. 5-10 or so PRs later, they become the first to spot those issues :-)
2. Be a leader. Listen to their concerns (really listen). Simultaneously be firm, direct, and honest. Don't let their insecurity drive the train. If you are in charge then be in charge, because you are trying to help improve them.
3. Set left and right limits. This is best done with automation, because the automation will either be without bias or at least equivalent to everybody. Automation can be test automation, compile checks, lint checks, and even vanity checks. Vanity (code style) is highly subjective and should only be applied via static analysis.
4. Document. Write down the learner's current learning and progress at each mentoring. That documentation will be used as positive evidence of their growth and progress for their manager evaluations.
5. Keep them accountable. Impose some minor amount of ownership and liability onto the learner. This will impose the need for the learned material. Simultaneously reassure the learner that this is a friendly environment with minor tolerance for failure. If it really is a safe environment then you as a manager have taken additional steps to increase internal automation to mitigate away as much risk as possible.
---
If after a good training structure the material is not sinking in one of two things are happening:
1) You are a bad teacher, probably due to your own biases. You have likely redefined reality in a way that reaffirms your own strength and fail to see the difference.
2) The current work is either not of interest to the junior or the junior is not intelligent enough. That is why you document at each mentoring for trajectory.
In my experience most of these training failures occur from the trainer not seriously taking ownership of the training (absence of leadership) and a complete failure to identify internal risks. When internal risk is high nobody cares about what you care about.
So 1) make sure you split big tickets into small tasks. 2) I encourage juniors to split largish tasks into multiple PRs.
Maybe a controversial answer, but tell the junior dev to use ChatGPT.
It probably all starts right there.