Code Review Is Culture Shock
When we understand each other’s cultural context, code reviews can shift from confrontation to collaboration. Without that context, a simple request for changes can read as an attack—or worse, go unsaid entirely.
Code reviews are a process that invites critical feedback and conflict. They’re almost always delivered in written form, devoid of verbal cues. And increasingly, teams are diverse, meaning reviewers and authors bring different assumptions about what counts as polite, direct, or even acceptable feedback.
Consider how cultures treat a single word: please. In some cultures, a question littered with please is considered insulting; in others, it’s the marker of basic decency. A developer raised in one tradition may read a blunt “Time?” as efficient while a colleague from another hears rudeness. Neither is wrong. But when one person’s polite phrasing strikes another as patronizing—or when a direct critique is read as aggression—the codebase pays the price.
Positive Intent Cuts Both Ways
Positive intent—assuming the other person means well—sounds like a cure-all. Done correctly, it helps us navigate the biases we’ve developed from our upbringing. It lets me interpret my partner’s constant please and thank you as cultural habit, not passive-aggressive frustration.
But positive intent can be wielded as a weapon. It can invalidate someone’s experience and dismiss the impact of your words. Positive intent is something you assume, not something you assert. When someone tells you your comment embarrassed them, responding with “assume positive intent” isn’t collaboration—it’s deflection. The goal isn’t to avoid accountability for impact; it’s to minimize the biases and assumptions we bring to the conversation in the first place.
Feedback Styles Across Cultures
Cultures differ on more than just politeness. They differ on how feedback is delivered. Americans and Canadians often sandwich negative feedback between nice comments: “Great work! You should work on your X. But overall, great job!” A German or Russian reviewer may see that as patronizing, while a Japanese colleague may be offended by the lack of opportunity to save face.
These differences surface naturally in PR reviews. Here’s an example of a review where the reviewer expected a test for a permalink action:
Reviewer: “Are we missing some test cases for the permalink action here?”
Author: “permalink and /checkout share the same callback, hence I decided to not include them. Let me know if you disagree.”
Reviewer: “If we changed the callback for permalink, I would personally expect to see a failing test, but I’ll let you be the judge whether it’s worth it :shrug:”
The reviewer hedges their feedback with soft language and defers the decision. The author responds defensively. The test doesn’t get added, and the reviewer doesn’t push. The codebase suffers.
Now consider the same conversation made explicit and curious:
Reviewer: “Any reason for not adding a test for permalink action here?”
Author: “permalink and /checkout share the same callback.”
Reviewer: “The redundancy would give us a failing test if we changed the callback for permalink, a separate test would be worthwhile here.”
The reviewer opens with curiosity. The author provides context without framing it as a debate. The reviewer shares expectations without minimizing their own feedback. There’s no guarantee the outcome changes, but the explicit exchange removes the hidden clash of politeness.
The Cost of Avoiding the Fight
Confrontation is also culturally coded. Some teams treat disagreement as a sign of engagement; others treat it as hostility. In one workplace, a developer and a colleague built a reputation for fiercely debating decisions—so much so that others questioned whether they got along. Years later, that colleague admitted they miss having someone to disagree with; without it, they feel less confident in their decisions. Refusing to engage in conflict isn’t kindness. It deprives colleagues of the chance to learn, educate, and build confidence in their choices.
Another PR review illustrates what happens when one party frames disagreement as a war:
Author: “I don’t particularly agree about your use of mocks and about all tests doing this, but I also don’t want to fight so I changed it all to be using the database and fixtures.”
Reviewer: “It’s not ‘my use’, it’s just what most of the codebase is already doing. Feel free to do it differently, I don’t think anyone will force this opinion on you or necessarily stop you. But then don’t be surprised if your code explodes in production (or worse: doesn’t explode but cause much more subtle problems) :smile:”
“I don’t want to fight” is itself fighting language. It disarms the recipient and turns a technical decision into a personal battle. The reviewer’s follow-up, “If your code explodes,” personalizes the issue—not this code, but your code. The author makes the requested changes but will think twice before commenting again. The merchants lose out.
When one side aims for perfection rather than excellence, every piece of feedback feels unwelcome. Framing a request as a fight makes the whole exchange exhausting. Instead, the author could ask, “What value would using mocks and fixtures offer here?” and the reviewer could provide context on why the codebase does it one way. The technical question gets answered without either party performing a cultural dance they never signed up for.
Perfection vs. Excellence in Code Review
There is a particular kind of pull request we’ve all seen: one that is so thoroughly polished, so exhaustively self-reviewed, that the subsequent code review feels like a mere formality. The author has anticipated every edge case and expects approvals, not commentary.
This pursuit of perfection is ultimately about appearance — wanting others to see the work as flawless. Pursuing excellence, by contrast, is about outcomes. When the goal is excellence, feedback is not a threat to your ego; it is a tool for achieving the best result. Perfectionism can make review feel like a fight, but a collaborative review process has no fight in it. Perfection is a solitary endeavor; excellence requires a team.
There is a well-known rite of passage at Shopify: a new hire’s first PR. The surprise is not the volume of feedback, but the granularity. Comments are thorough and the bar is high. No one goes easy on the newcomer.
That should not be surprising. In fact, it reflects the healthiest possible view of what a review is for.
Setting Expectations Early
Early in my career, I worked on a small website, and we hired an outside developer, Ben, to handle the parts beyond my expertise. He was paid a fixed amount for a fixed set of tasks. As he worked, I read his code and learned. Eventually, I asked if I could take one of his tasks — he’d still get paid the same, but he would review my work instead of writing it.
That first review experience shaped my expectations for all future ones. A good review is an invitation: “Here is my thinking. What can be improved?” That framing does not preclude strong opinions about code — I have plenty — but it does require genuine open-mindedness and an ability to look past phrasing to the underlying point. In a review, both author and reviewer should ask: “Why does this person feel this way? Is this a mistake or a deliberate choice?” Productive disagreement is not a weakness; it is how developers get better.
Everyone benefits when we take time to question, to answer, to explain, and to ask for clarification. Saying “I don’t know what this does” is a strength, not an admission of failure.
Self-learning is valuable, but other people are better teachers than search engines. A search engine can answer questions, but it cannot tell us which questions to ask in the first place.
A Lesson in C++
I experienced this directly in a university course. Due to a scheduling conflict, I was the only student in my year taking C++ while everyone else took Java. To stay on track, I agreed to learn C++ from a textbook, with the understanding that my professor, juggling a full Java class, could not spend much time with me. After completing that, I joined the C++ cohort for the second course, surrounded by students who had learned the language the same way I had.
One thing the book never taught me was how to pronounce cout. In class, I would read it aloud as “cout” (rhyming with “boot”). My peers quickly corrected me to “c-out,” a nicety the textbook hadn’t covered. And along with the correction, they introduced me to printf, which the book hadn’t yet mentioned.
That small correction was a gift. Collaboration works that way — we all get better because of it.
Treating Reviewers as Co-Authors
What if we treated the reviewer as a major collaborator on the PR rather than just a gatekeeper? Imagine giving reviewers credit not only for catching bugs but for improving the work itself. Imagine recognizing reviewers as prominently as the author.
A shift in mindset makes this natural: when reviewers and authors both take ownership of a PR — not just the broader codebase — they bring the same standards, curiosity, and creative mindset to the code. Reviews stop being a separate task and become an opportunity for authorship. When reviewers are co-authors, they write code with their comments. Forgiveness and curiosity are easier to maintain when you feel a shared sense of ownership over the outcome.



