Your thoughts on Code Reviews

https://feddit.it/post/27805498

As with a lot of things in life, it depends.

I use 1-5 depending on the repo, who made the change, what the change is about, and how involved I am in the project.

Though the “time-frame” idea of #4 is usually replaced by conversations if it’s a coworker, as it’s more effective.

Q: about #3, do you mean on code that is already merged / committed to the default branch?

Added a few details in the post. Of course it depends, but let’s say you’re the team lead and you have to fix a general rule (otherwise no one is going to do them) which one you’re more likely to go for? e.g. if you choose (2), it’s up to every single member.

Q: about #3

yes already merged, updated the post.

The way I see it, for any code review there are going to be different levels of recommendation regarding the comments. When I review, I try to make it clear what’s optional (/ nitpick) and what I’d really like to see fixed before I can approve it.

So even making some assumptions, I can’t choose between 4 and 5 because optional and “less optional” changes are often in a same PR.

The only one I haven’t done much of is #3. That one looks better if one has questions about code that was already reviewed, merged, and it’s likely in production.

With regards to the given list, I think #2 would be the most forgiving, in the sense that #1 suggests that code reviews are viewed solely negatively and are punishable if undertaken. But that minor quibble aside, I have some questions about what each of these would even look like.

For example, #3 seems to be that code can be committed and pushed, and then review sought after-the-fact, but any results of the code review would not be binding for the original commit author to fix, nor apparently tracked for being fixed later. If that’s a correct description, I would describe that as the procedurally worst of the bunch, since it expends the effort to do reviews but then has such an open-loop process that the results of the review can be swept under the rug.

On the note of procedure, it is always preferable to have closed loops, where defects are: a) found, b) described, c) triaged, d) assigned or deferred, e) eventually fixed, and f) verified and closed out. At least with your examples #1 and #2, they don’t even bother to undertake any of the steps for a closed loop. But #3 is the worst because it stops right after the first step.

Your example #4 is a bit better, since in order to keep to a specified timeframe, the issues found during review have to at least be recorded in some fashion, which can satisfy the closed-loop steps, however abbreviated. If the project timeline doesn’t allow for getting all the code review issues fixed, then that’s a Won’t Fix and can be perfectly reasonable. The issue has been described and a risk decision (hopefully) was made to ship with the issue anyway. All things in life are a balance of expected risk to expected benefit. Ideally, only the trivial issues would be marked as Won’t Fix.

But still, this means that #4 will eventually accumulate coding debt. And as with all debt, interest will accrue until it is either paid down or the organization succumbs to code insolvency, paralyzed because the dust under the rug is so large that it jams the door shut. I hope you’ll allow me to use two analogies in tandem.

Finally, there is #5 which is the only one that prevents merging code that still has known issues. No doubt, code that is merged can still have further bugs that weren’t immediately obvious during code review. But the benefit is that #5 maintains a standard of functionality on the main branch. Whereas #4 would wilfully allow the main branch to deteriorate, in the name of expediency.

No large organization can permit any single commit to halt all forward progress on the project, so it becomes imperative to keep the main branch healthy. At a minimum, that means the branch can be built. A bit higher would be to check for specific functionality as part of automated checks that run alongside the code review. Again, #4 would allow breaking changes onto the branch due to expediency, whereas #5 will block breaking changes until either addressed, abandoned, or a risk decision is made and communicated to everyone working on the project to merge the code anyway.

TL;DR: software engineering processes seek to keep as many people working and out of each other’s way as possible, but it necessarily requires following steps that might seem like red-tape and TPS reports

Ah, I see that OP added more details while I was still writing mine. Specifically, the detail about having only a group of 5 fairly-experienced engineers.

In that case, the question still has to focus on what is an acceptable risk and how risk decisions are made. After all, that’s the other half of code reviews: first is to identify something that doesn’t work, and second is to assess if it’s impactful or worth fixing.

As I said before, different projects have different definitions of acceptability. A startup is more amenable to shipping some rather ugly code, if their success criteria is simply to have a working proof of concept for VCs to gawk at. But a military contractor that is financially on the hook for broken code would need to be risk-adverse. Such a contractor might impose a two-person rule (ie all code must have been looked at by at least two pairs of eyeballs, the first being the author and the second being someone competent to review it).

In your scenario, you need to identify: 1) what your success criteria is, 2) what sort of bugs could threaten your success criteria, 3) which person or persons can make the determination that a bug falls into that must-fix category.

On that note, I’ve worked in organizations that extended the two-person rule to also be a two-person sign-offs: if during review, both persons find a bug but also agree that the bug won’t impact the success criteria, they can sign off on it and it’ll go in.

Separately, I’ve been in an organization that allows anyone to voice a negative opinion during a code review, and that will block the code from merging until either that person is suitably convinced that their objections are ameliorated, or until a manager’s manager steps in and makes the risk decision themselves.

And there’s probably all levels in between those two. Maybe somewhere has a 3-person sign-off rule. Or there’s a place that only allows people with 2+ years of experience to block code from merging. But that’s the rub: the process should match how much risk is acceptable for the project.

Boeing, the maker of the 737 MAX jetliner that had a falty MCAS behavior, probably should use a more conservative process than, say, a tech startup that makes IoT devices. But even a tech startup could be on the hook for millions if their devices mishandle data in contravention to data protection laws like the EU’s GDPR or California’s CCPA. So sometimes certain parts of a codebase will be comparmentalized and be subject to higher scrutiny, because of bugs that are big enough to end the organization.

Thanks for the insight

In your scenario, you need to identify: 1) what your success criteria is, 2) what sort of bugs could threaten your success criteria, 3) which person or persons can make the determination that a bug falls into that must-fix category.

I think is a good part of what I needed to be told, thank you!

For example, #3

yes that’s what I meant, comments on the review would just be a suggestion to the author, which can possibly fix but not in a controlled (or closed-loop as you said) manner.

software engineering processes seek to keep as many people working and out of each other’s way as possible, but it necessarily requires following steps that might seem like red-tape and TPS reports

In my experience even a too long staging process for merge/review, can hinder development since people that work on the same things can need each other changes to move on, so how to know where to trace the line and merge? No breaking the build I would say is universally accepted, but what if for example an issue is internal to a WIP feature?

people that work on the same things can need each other['s] changes to move on

If this is such a regular occurrence, then the overarching design of the code is either: 1) not amenable to parallelized coding at all, or 2) the design has not properly divided the complexity into chunks that can be worked on independently.

I find that the latter is more common than the former. That is to say, there almost always exists a better design philosophy that would have allowed more developers to work without stepping on each other’s toes. Consider a small group designing an operating system. Yes, there have to be some very deep discussions about the overall design objectives at the beginning, but once the project is rolling, the people building the filesystem won’t get in the way of the UI people. And even the filesystem people can divide themselves into logical units, with some working on the actual storage of bits while others work on implementing system calls.

And even when a design has no choice but to have two people working in lock-step – quite a rarity – there are ways to deal with this. Pair programming is the most obvious, since it avoids the problem of having to swap changes with each other.

I’ve seen pair programming done well, but it was always out of choice (such as to train interns) rather than being a necessary mandate from the design. Generally, I would reject designs that cannot be logically split into person-sized quantities of work. After all, software engineering is ultimately going to be performed using humans; the AIs and LLMs can figure out their own procedures on their own, if they’re as good as the pundits say (I’m doubtful).

but what if for example an issue is internal to a WIP feature?

I forgot to answer this. The question is always: will this materially impact the deliverable? Will the customer be unhappy if they hit this bug?

If the WIP isn’t declared to be fully working yet, then sure, let it on the branch and create a ticket to fix this particular bug. But closed-loop requires making this ticket, as a reminder to follow it up later, when the feature is almost complete.

If instead the bug would be catastrophic but is exceptionally rare, then that’s a tough call. But that’s precisely why the call should involve more people, not less. A single person making a tough call is always a risky endeavor. Better to get more people’s input and hopefully make a collective choice. Also, humans too often play the blame-game if there isn’t a joint, transparent decision making process.

I don’t think I’ve ever not done #5 in all places I’ve worked. It’s insane to even think otherwise. What happens is that if anything really urgent needs to bypass the process, then the team lead or someone in high power can merge or bypass the normal procedure, but that’s rare.

Ok then you’re moving the problem to the reviewer, what change request would you say is a mandatory fix? In the place you worked, were you marking the comments on the review in any way to make them mandatory / non mandatory? Or just discussing them one by one?

Edit: given the amount of downvotes let me clarify this comment is not trying to be polemical, I’m genuinely asking the above questions.

Everything gets reviewed. If you have a constructive comment you put it in the review.

I note when I think I have a better way of doing something but the existing way works fine, and I leave that fix up to the submitter. But sometimes I just say no this is wrong. And then whether it gets merged anyway depends on my role. I’m a tech lead now so that’s basically the end although if they want to argue their case I’ll hear them out.

The devs I work with are all seniors and have all been working in the system longer than me, so I respect them and listen when they disagree. Generally when that happens I’m right in principle and they agree with me, but the code is a fucking mess and we can’t do A right without having to change the rest of the alphabet, and we have bigger fish to fry.

In other positions I made my comments and whoever was in charge got to decide whether to accept the change or send it back. I try to always make at least one constructive comment even if it’s just like: I really like how you did this.

I’m not sure what problem you think is being moved to the reviewer. It’s a team and everyone has the same end goal. I appreciate when my code is reviewed because any of us can make a mistake or forget to consider some outside factor. Code review is where assumptions are tested and discussed and hopefully everyone comes away knowing more and agreeing on a path forward.

Everything gets reviewed. If you have a constructive comment you put it in the review.

I’m a tech lead now so that’s basically the end although if they want to argue their case I’ll hear them out.

So basically you’re saying that all the comments are welcome, and should be argued, but you have to appoint a person that have the final say on what to merge right?

I’m not sure what problem you think is being moved to the reviewer.

The problem of deciding what should be merged or blocked, I’ve mainly made this post to understand that, so saying “#5 or you’re crazy” doesn’t answer much. But I’ve probably worded that badly.

If a story gets created, the code will be merged… when it’s right. If you’re talking OSS, then I am out of my element, but I’ll wager there’s no universal answer because each code owner sets their own standards.

you have to appoint a person that have the final say on what to merge right?

If there is work that needs to be done, and you are asked to do it, the code will be merged when it’s right. I don’t decide what to merge, I decide when something is ready to merge.

The problem of deciding what should be merged or blocked

If you want to merge something and I read it over and reject the PR because you forgot about concurrency, that doesn’t mean you don’t get to merge, it means that it’s not finished baking. And assuming you give a shit about the code your response should be “oh shit, lemme fix that and resubmit” OR “actually this code will never have concurrent access, and here’s why.”

You’re making this process sound adversarial when it isn’t. It’s a group effort. Everyone wins or loses together.

The problem of deciding what should be merged or blocked

If you want to merge something and I read it over and reject the PR because you forgot about concurrency, that doesn’t mean you don’t get to merge, it means that it’s not finished baking. And assuming you give a shit about the code your response should be “oh shit, lemme fix that and resubmit” OR “actually this code will never have concurrent access, and here’s why.” You’re making this process sound adversarial when it isn’t. It’s a group effort. Everyone wins or loses together.

You’re obviously right, you’re misunderstanding me. With blocked I didn’t meant “forever”, I meant until the issues is discussed. I’m merely asking how the reviewer is making the call on what should be addressed before merge in #5

If there is work that needs to be done, and you are asked to do it, the code will be merged when it’s right. I don’t decide what to merge, I decide when something is ready to merge.

you’re really nitpicking my English, which I know is not great, but yeah that’s what I was asking, so you use #5 with a single person making the final call on when something is ready.

You’re making this process sound adversarial when it isn’t.

Absolutely not, I’ve never said or thought that. But of course development is made of people and computers can only tell you what compiles, not “when it’s right” as you say. So of course I’m more curious to understand how to solve situations when you do have conflict, if you don’t it’s easy.

you’re really nitpicking my English

Mate, the hardest part of software development is communication and autism is ubiquitous — got a touch myself. So I over explain and I’m very specific. But let me make one thing abundantly clear: I don’t have time to spend this many words trying to be a pedantic asshole. I have much better things to do with my time. If you don’t like my approach, feel free not to engage, but I’m here trying to distill some value for you out of my experience.

Now, I don’t put too much stock in up and down votes (and to be clear none of your downvotes is from me — I don’t waste time responding to stuff I downvote), but the pattern suggests that what I’ve said resonates with other developers.

So of course I’m more curious to understand how to solve situations when you do have conflict, if you don’t it’s easy.

So here’s the disconnect: you’re worrying about shifting burdens like it’s a huge weight, but conflict is exceedingly rare — too rare to worry about. It’s a non-consideration.

I’m going to leave it there because I think anything else would just be repeating myself.

5 only. Even when I only had a single partner doing non-professional work. Though on occasion when life got away from us we would just merge after a few days. But as a rule we always had at least 24 hours.
The main branch should always contain working code. You should assume you can deploy it to production and it will work. Not having anybody review your code is lunacy, and ignoring critical feedback is even more insane. You can ignore linting complaints assuming you don’t have a linter that fails the build, but you should not consider faulty business logic as an optional fix.

but you should not consider faulty business logic as an optional fix

The same goes for unreadable/unmaintainable code (though that’s a bit harder).

Wow. I’m more chill, I prefer #5, where some (no breaking) feedback can still be deferred to a future follow up issue.

That said, my team rarely exercises the option to defer feedback.

We have #5, but some (non-breaking) feedback can still be deferred to a future follow up issue.

This is usually my preferred option, but usually i differentiate between blocking and non-blocking feedback in my reviews. Non-blocking is some improvement that can be made, but is not necessary, like cleaning up some (tangentially-related) code. Blocking is anything that is logically incorrect, unreadable, uses deprecated features unnecessarily, etc.

From a scientific modeler perspective: Always trying to do 5 (or 4), but I’m having difficulties getting a culture of reviewing each other’s codes going. Many times I was asked to “just merge” months after submitting a PR. In the context of operational or large community codes, 5 is usually strictly enforced. Weather services don’t appreciate broken code.
when you were asked to “just merge” why was the review still on going? too large, or you didn’t find an agreement with the autor?
It was more a question of finding the time within the daily business of doing science. I suppose it is also a culture issue, the priority to do a review is usually low. In other words, there was de facto never a review.

Thanks, that’s actually interesting. I’ve found making #5 work with limited human resources / deadlines challenging, and wondered what to do. My answer in the past has been to lower review quality (reviewing faster) while keeping #5.

In my case the priority for reviews was high, but we were limited by the reviewers/developers ratio since most people would not do reviews…

I’m glad to hear that lack of time/resources for code reviews are more common. Also for clarification: I was the author and requested reviews by my colleagues. In reverse, I did not receive requests to review PRs so far. Tbh. I would really like such a review culture as it is already standard in scientific publishing and it would have avoided some obvious bugs we did encounter in the past. Having that said, as I did not receive any review at all and I would appreciate low(er) quality reviews better than none.

mandatory reviews on code before merging (PR) with mandatory fixes.

This one. Open PR, review by at least one peer, address concerns, merge.

Code review is not punishment - it’s part of your job. You should be willing and able to provide meaningful feedback to your peers. It also gives the team an opportunity to see how other people write code and to agree on norms and standards.

Anyone who answers other than 5 is a fucking idiot.

I’ll also say 5 but I have my gripes with it. Mainly with the “review from any other engineer” aspect that usually comes with it.. I have met so many engineers whose review seems to just depend on who created the MR, as opposed to what’s in it. When an MR with 500+ lines changed gets reviewed in about 10s after requesting it, it’s kinda obvious that the system is broken.

The people I’ve worked with who are good at their job and I’d probably be okay with them merging their changes without reviews would always ask for a review, even when it’s not mandatory or enforced. And their MR would already have comments by themselves around bits I might have a question around, and they’d even come with prompts of what they want input on. Whereas the people I wish wouldn’t even be allowed to approve anything would usually ask for an approval instead (even the wording seems telling). Sadly, often these 2 groups will have the same job title and HR will dictate that they should have the same permissions and say in things, which is what usually breaks the system IMO.

  • The amount of people who seem to treat reviews as currency/favours and just rubber stamp each others MRs without looking..sigh.
  • It takes discipline to produce good code.
  • Why would the answer ever be anything other than 5?

    Let’s just go full boar hypothetical: Someone is trying to merge malicious code. Anything other than 5 means the malicious code gets merged.

    In a small shop where people really know and trust each other and all have high quality standards and would never break main - is code review necessary and for what purposes if so?

    Yes, absolutely.

    “Never break main” is the same concept as “never get in a car accident.” Good in theory, but it’s no replacement for insurance.

    Everyone makes mistakes. PRs help catch those mistakes. Yes, bugs will still sneak in, no one is perfect, but a proper PR process is absolutely vital no matter the team size.

    Yes, it’s necessary. Even if everyone writes perfect, bug-free code, people learn from code reviews.
    Even well intentioned people can make mistakes
    I work in a similar environment. Most of our projects lifecycle we were 4 devs who knew each other reasonably well and all had high trust in each other. Unless it was a one-liner or a hotfix at 4am did get merged without a code review. Most if the reviews were just hitting the checkmark, things look fine done. But sometimes someone makes a mistake, as is human. In that case we caught it before it hit master.
    I can only think that what they have in mind is a small project with only few people involved. Otherwise anything other than 5 is ridiculous.

    Let’s just go full boar bore hypothetical:

    Whoop yeah good catch but I’ll leave it.
    Always have done 5

    I’ve worked for managers that didn’t believe in the necessity of code reviews, and some that downright hated them. All of them wrote garbage code, and the codebases were equally awful. Some people just cannot handle even the slightest critique.

    If you find yourself on a dev team doing anything other than 5, run, don’t walk, and find a new job if you can. If you can’t, focus on increasing your knowledge and skills, because no one else there is going to help you.

    If you find yourself on a dev team doing anything other than 5, run, don’t walk, and find a new job if you can. If you can’t, focus on increasing your knowledge and skills, because no one else there is going to help you.

    Is great advice, which I have followed, and it has served me well!

    Thank god you specified dev team. I personally just go by ear and I mainly just work alone
    5 works best. In order to do 5 well, PRs must be small and nothing in any given PR should really be a surprise to anyone on the team. To accomplish both of these, this means that the team already discussed the work, broke it down into tasks, and then pointed the work. If any tasks are going to take longer than a few days, break it down. Otherwise, you’ll end up with 100 file PRs and 2 second LGTM reviews.
    There’s a number 6, where if you’re on a small team with good synergy and well experienced members, the PR is a good thing each member requests to answer the question , hey can you double check my work and please give me feedback because I really trust your judgement.it’s a no nonsense way for confident developers to get a second opinion.

    5 with reasonable acceptance and use, even advocacy, for up to 1. I don’t see a difference between 4 and 5, though.

    Reviews should be the norm. Even for simple changes, a simple code change should be simple to review and approve, too. At the same time, some formatting changes or small or minimal changes with high confidence can be pushed to main without review - that’d be just wasted time and effort on the reviewer’s side. High urgency can also warrant an immediate push to main, or live hotfixing on prod if possible, with a corresponding PR still open.