As a junior who previously got thrown into the deep end on one project, where I have been essentially useless for way too long, but now am having actual guidance, and do one part at a time: I can only second that.
Also: train your juniors, please. Getting thrown into the deep end REALLY hurts the speed of learning.
Juniors should not be learning the same things as senior developers. Imagining juniors as "mini-seniors" is IMO wrong.
There needs to be a progression and you go from focus on low level stuff to focus on high level stuff.
For any single thing, at least at the beginning of the career, you first start with copying, then you imitate, then you get proficient, then you hopefully go to understand it on a deep level -- mastery.
Junior devs -- learn to use the tools. The focus of juniors should be on getting productive within the team and this means being able to do a significant volume of tasks that require least high level knowledge -- repetitive/routine tasks, low level tasks, localised changes. As far as the high level concepts, juniors are not expected to contribute or even understand them -- they are expected to be able to work within the the project structure. It is the tech leadership job to make sure that juniors can be productive even without understanding high level concepts, strategy, etc.
Senior devs -- are expected to know the tools, learn the high level design concepts. They are also expected to have enough experience to be able to tell right from wrong. The focus of senior developers is to understand and be able to productively use high level development concepts. This means ability to design single applications, modules, interfaces, etc. Work productively with stakeholders. Work productively with juniors. Etc. Seniors is when you should start understanding programming patterns, paradigms, learn when to use them, etc. Seniors are not expected to be able to solve all problems and still require some supervision. Seniors also are not expected to be able to form or understand strategic concepts.
Tech leader / principal developer -- are expected to know the tools, know high level development concepts AND also be strategic about it. Tech leader, however intelligent he/she is, is also expected to have immense experience at various types of projects so that he can immediately tell right from wrong and use his experience to put forward solutions that worked in the past and critique solutions that are known not to work. Tech leader is the person that needs to be able to understand and debug entirety of technical situation, form the vision of where he/she wants to be in future and put together coherent strategy. For example, tech leader is the one responsible for understanding blockers for individual contributor productivity and find strategy to improve and resolve these issues. Tech leader IMO should also be a person that is able to solve ANY problem, technical or otherwise.
I would say a tech leader does not always know right from wrong, but needs to be able to make the decision and own the consequences, especially when their decisions affect the happiness of other developers.
I like your distinction between senior devs and tech leads. I think a lot of rewrites come from good senior devs faced with an existing system with problems and knowing that they wouldn't have created those problems if they wrote the system themselves. For example, if the system has code quality issues or a poor internal architecture, the senior devs think, we write good code and make good design decisions, so why should we struggle with this bad code and bad design? We should rewrite it so that it reflects our quality.
I was certainly guilty of this at an early stage in my career. As soon as I could write good code and make good design decisions, I thought the future was going to be easy. I wasn't going to be struggling with poorly written, badly designed systems forever. I'd be working on awesome systems that reflected my standards, and everything would make sense.
That was a hard dream to give up.
Now I look around and think, what one thing can this team do to make this better, while still delivering software for the people who need it?
In my experience rewrites typically start with senior devs (or tech leads who are not really leads but rather senior devs with better pay). The rewrite starts when devs are able to force/guilt/persuade the manager to do it.
And also in my experience rewrites rarely succeed. There are multitude of reasons but the best way to put it is that devs don't usually know what they are getting into (they only have part of the picture) and they are out of stamina somewhere in the middle of the project. They also never learned what caused the previous project to fail (they have too limited view to understand it) and so they tend to repeat the same mistakes.
One project I joined had lost its entire development team. New devs came and demanded rewrite. The manager allowed it. The rewrite failed (of course). The cause: the internal customer was very intrusive and they demanded to get creative control over every part of the development process including approving code reviews, etc. The lack of expected progress on the features the customer demanded only got the situation worse and got them more arguments and in the end higher management decided to kill the rewrite.
Again -- devs had only partial understanding of what caused the fail of the previous project. They looked at badly written code and surmised the previous developers to be incompetent. The reality was those guys were competent but were completely demotivated by inability to get anything done with the internal customer and so did not care about quality one iota.
My solution to rewrites is avoid at any cost and to only do rewrites under exceptional circumstances when it is absolutely clear that refactoring is pointless.
So what do I do?
1. When setting on the project to improve your system/codebase, it is important to think about your ability to finish the project. This is going to be dependant on willingness of your various stakeholders to pour money (or see a slowdown in feature development). The best way is to get a credit of trust early on and the best way to get this is by showing some early results that the stakeholders care about especially if it is something they wanted for a long time but could not get.
2. No results will be worth anything if you don't get some visibility. Put up metrics for everything that can be reasonably measured and the customer cares about -- reliability, performance, turnaround time for defects/changes, etc.
3. Those early results can be anything but when I come into a project I am trying to find out what are the biggest issues and I try to locate one where it is possible to get substantial improvement quickly. This might be something like fixing unreliable behaviour, performance or getting done a particular feature that was asked for for a long time. It is important to select carefully -- you are working on an alien codebase with a new team. The worst that can happen is you promise a lot and deliver nothing.
4. Once you get a credit of trust, you spend it on improving development efficiency. Overall, this is one thing that is most important to get done early but at least early on is completely invisible to stakeholders -- and so you need to use up a bit of your credit.
5. Development efficiency is highly dependant on the project. Automated build? Faster build times? Automated end to end functional testing? Being able to set up your private development environment quickly? Getting rid of some stupid hoops you have to get to modify the app or get your piece of code through the process? Refactoring a couple things that are causing a lot of additional work for every change? The key is to look at the actual process and understand what really is driving inefficiency -- as tech lead I always pair program with developers to get understanding of what the situation really is like.
5.1 On one project I noticed developers spent a lot of time on internal requests form customer that were nothing else than changes in configuration. I wrote couple modules and small UI to let the user self-service themselves and suddenly eliminated about 1/5th of development effort (with about a week of effort on my part). I also spent some time with the team to talk about importance of self service and how it helps reduce unplanned work that interrupts their development.
5.2 Pair programming is ABSOLUTELY best way to get to know your team and the team to get to know you. You want some respect as tech lead? No better way than to actually stick with them and show you can do stuff. This is going to be very important for you later.
6. At this time you should be thinking about improving the basic improvement process -- at the very least get your team to understand what is wrong and right and have retrospectives with the team to figure out what the problems are and how to fix them. You don't want to bog your team with full agile, but you want to start building it from the ground up by introducing basic improvement loop, transparency, openness, etc.
7. By improving development efficiency you create additional development throughput which you then spend on more improvements, but now those improvements should start providing visible results to stakeholders. Faster turnaround time on changes, more reliable and predictable deployments, more reliable and faster system, etc. Here you want to be tracking how much resources you spend on internal improvements (code refactorings, development tooling, etc.) vs things that the customer cares. It is important that the customer is always satisified because this is what gives you freedom to do whatever changes you want to make.
And if anybody wants it, I am always happy to help with a problematic project:)
One critical point I forgot to include is that cognitive load of your team members should be treated as a precious resource. Whatever happens, you need to make sure you don't waste this resource on unneeded stuff -- cognitive load more than anything else will determine how quickly stuff can be changed.
Remember, if you introduce anything people will need to take time to learn, adjust and then understand. You can also count of experience at least temporary slowdown.
So don't waste time things that only marginally help with development. You definitely don't want to switch your project from Java to Kotlin if your goal is to get something done quickly! (Yeah, I have seen this happen in real time -- new guy came to a project and "listened" to devs and switched project from Java to Kotlin with predictable outcome that he was fired half a year later after disappointing progress on actual work).
A learning project with lots of fast iterations where concepts get added over time. With feedback on each iteration from experienced devs where you are able to discuss why you chose x and what the tradeoffs are. At least in my case.
Also: train your juniors, please. Getting thrown into the deep end REALLY hurts the speed of learning.