I love all of your advice, but I would start straight-away with writing tests. Not only is it low risk, it is the best way to start understanding the code base, and gives you an avenue through which you can start introducing small refactorings. The other important thing is that developers LOVE to have outside help with testing and a pair of fresh eyes to look at the test-suite through.
Start by adding a whole-system black box end-to-end test, if there aren't already any good ones. Ideally fully automated and automatically run for every commit via CI, but don't let the perfect be the enemy of the good, take what you can get for starters.
Benefits:
(1) You only really need to know the system as a user, not the codebase as well, to do this.
(2) Well, #1 was a bit of a white lie. You'll end up finding out about all the (possibly undocumented) runtime dependencies this way, spinning up throwaway VMs and databases, etc. If the project is in production, this will be very useful knowledge, since you're probably the last point of escalation for strange prod issues.
(3) Running this out of CI with throwaway VMs/containers will also force you to fully automate the install and make the damn thing actually work on a generic blessed OS configuration, which might be a huge boon to your team if you currently are in "Works on my machine" hell. I did this somewhere where we had tons of lost productivity because developers used OSX or Ubuntu on their workstations, but prod was RHEL, and the most fascinating deviations would be found by developers chasing the strangest of bugs. Making the install reproducible so we could have CI totally ended this.
(4) If you don't have this already, and you set up infrastructure to gate commits on this test passing, team love and productivity will rapidly go through the roof as suddenly your developers aren't spending half their time fighting each other's build breaking changes.
So yeah, it's just one thing, but it leads to so many benefits it's definitely where I would start.
I've had the same experience. I'm sure it's somewhat context dependent, but if the code amounts to business rules and they are not documented, which is very common, you can only reverse engineer what the system _does_ and then write tests for that.
Of course you can ask people who are more familiar but whether you end up helping or being a distraction then is an open question.
Yeah, whenever new hires complain about the lack of
completeness or correctness of documentation, I'm like: that's a great place for you to start. It also seems to be a great signal of the attitude of the new hire, because the people who kind of groan at that task usually end up having problems.. but that's another topic altogether.
As a (junior) new hire in a group without very complete or correct documentation, I'm not sure I can agree with that. It can be nigh on impossible to try to improve documentation for complex systems without a very deep understanding of the stack. I could spend hours writing documentation but it's not useful when I don't know what is and isn't an intended behavior. I think a fresh face is a great asset to have for writing docs but they need someone with a very good understanding of the system to work with them. Some of the most frustrating times I've had had a junior dev have been documentation tasks for things I did not know very well, spending time poking the system to gain understanding and more time writing clear docs, only to hear that my docs are 'not how it works' and I had either setup and configuration wrong or need to file bugs so it works how it's 'supposed to', even though that is the exact documentation it's lacking. Maybe this is different for projects with less technical debt, where if the current behavior was documented that documentation would be useful. I think this habit of giving documentation tasks to the least knowledgeable people on a project, even though it's reviewed by those with more knowledge, makes the docs suffer.