With experience comes the judgment to know when code is really bad, and when it is just written in a different style. If it's perfectly functional and maintainable and there is good automated test coverage, then it's not bad and you just need to open your mind. You will probably learn something. Bad code is not functional and maintainable.
Here are some markers of truly bad code:
- Large blocks of logic have been duplicated instead of refactored.
- Circular dependencies between classes or packages
- High coupling; low cohesion
- Unused variables, writing to variables that are never read, unreachable code.
- Reimplementation of standard library functions, e.g. date formatting.
- Unnecessarily complex logic; i.e. 50 lines of code where 10 would do nicely.
- No comments describing the purpose of classes or methods.
- Misleading comments.
A lack of automated tests doesn't mean the code is bad, but it means the project is bad.
These are not a matter of taste; these practices make program maintenance much more expensive.
How do you prepare yourself?
Accept the fact that it takes a while to be able to successfully work on a new code base. If it's "perfectly maintainable" and there is high test coverage, it takes less time but it still won't happen immediately. If the code is bad, then the first thing I do is warn the stakeholders that it is in bad shape and initial progress will be slow. If they are skeptical, then I back up my claim by showing them a sample of problems in the actual code and explaining how it varies from industry best practice.