Code reviews are an essential part of the work in a team of software developers. In many teams, they are the primary moment of exchange between developers. Here is my personal approach on how to make them work well:
Goals
First of all, you should be aware of the goals of a code review:
Create a common understanding: After the code review, not only the author but at least the reviewer should understand what was changed and why.
Find errors: One eye sees more than two. The reviewer looks for errors that the author has missed.
Standardize code style: Not in the sense of the correct quotation marks or line breaks (there are formatters for that). It's about using the same abstractions and pointing out to the author if a pattern already exists, an API is used incorrectly or other technical debts are built up that can be avoided with the reviewer's knowledge.
Methods
A good code review consists exclusively of questions.
These serve the goals described above.
If I don't understand what the code I'm reviewing does, I ask questions.
If I don't understand why a change was made, I ask questions.
If I don't like the part I'm supposed to review, I ask why it was solved that way instead of criticizing. Often suboptimal solutions are carefully chosen compromises.
If I see a mistake, I ask whether section X might lead to problem Y.
If I see an abstraction that I have already seen very similarly elsewhere in this codebase, I ask why the existing abstraction was not used.
If I think I have a better solution, I ask why the problem was not solved the way I imagine it to be.
Communication
When asking questions (in general and especially in code reviews), we should keep in mind
That we do not put our colleagues in need of explanations. The goal should be to create understanding, never to force the colleague to justify themselves.
To give constructive feedback: If I have a suggestion for improvement, I should bring it up (in this case, the question may be whether the proposed solution has already been considered and, if so, not chosen for good reasons).
To communicate non-violently, taking into account how we formulate our feedback or questions and how they might be received by the recipient.
Juniors
You have little experience and have doubts whether you are able to judge the code of a more experienced developer?
You don't have to, asking comprehension questions is enough. In my experience, a review by a less experienced colleague reveals comparatively fewer subtle errors, but this is more than made up for by the impetus to explain and question my own decisions.
So what if you feel like you do not know the project well enough at all and have no idea where to start with the review? If possible talk to the author directly and let them explain to you personally what they've changed and why.
Exceptions
Last but not least, exceptions prove the rule, of course. There are situations in which a review is not a question. There are situations in which I am sure that a solution should not be adopted as I have it in front of me in the review. In these cases, I formulate my requirements (not questions) and insist that the relevant passages are changed.
I find exceptions mostly by realizing that the question I am formulating is actually rhethoric (has only one answer). If that's the case then it's not a question and I should not pretend that it is.