Code review is one of the most valuable skills in software development. It's how teams maintain quality, catch bugs early, share knowledge, and help each other grow. In this lesson, you'll learn how to review pull requests effectively, what to look for during reviews, how to give constructive feedback that improves code without discouraging authors, and understand the etiquette that makes code review a positive experience. Good reviewers are as valuable as good coders!
Why Code Review Matters
Code review isn't just about finding bugsβit serves multiple crucial purposes:
Benefits of Code Review
- Catch bugs early: Find issues before they reach production
- Improve code quality: Ensure code is readable, maintainable, and follows standards
- Share knowledge: Team members learn from each other
- Spread ownership: More people understand each part of the codebase
- Maintain consistency: Keep code style and patterns uniform
- Prevent technical debt: Address problems before they compound
- Build team culture: Foster collaboration and learning
- Onboard new developers: Reviews help newcomers learn the codebase
Studies show:
Code review catches 60-90% of bugs before production, saves significant debugging time, and improves team knowledge sharing more than documentation alone.
π Learning Goes Both Ways
As a reviewer, you learn from others' approaches. As an author, you learn from feedback. Code review is a powerful learning tool for everyone involved!
The Code Review Process
Here's how code review typically works on GitHub:
Step 1: You're Assigned or Find a PR
- Assigned by maintainers (you get a notification)
- You volunteer to review
- You regularly check for new PRs in projects you follow
Step 2: Initial Assessment
Quickly check:
- PR description: Is it clear what this changes and why?
- Size: Is it small enough to review effectively?
- Related issues: Does it address the stated problem?
- CI status: Are tests passing?
PR Too Large?
If a PR changes 1000+ lines, it's often too big to review effectively. Politely ask the author to split it into smaller PRs.
Step 3: Review the Code
Read through the changes carefully (more on what to look for below).
Step 4: Leave Comments
Add comments on specific lines or general feedback.
Step 5: Submit Your Review
Choose one of three actions:
- Comment: Give feedback without formal approval/rejection
- Approve: Code looks good, ready to merge
- Request Changes: Issues must be fixed before merge
Step 6: Follow Up
Continue discussion, review updates, and approve when ready.
How to Review on GitHub
Option 1: Review on GitHub (Most Common)
Starting a Review
- Go to the Pull Request on GitHub
- Click the "Files changed" tab
- You'll see a diff of all changes
Adding Line Comments
- Hover over a line of code
- Click the + button that appears
- Write your comment
- Click "Start a review" (first comment) or "Add review comment" (subsequent comments)
π‘ Batch Your Comments
Use "Start a review" instead of "Add single comment". This batches all your comments together, sending one notification instead of dozens!
Adding Suggestions
GitHub lets you suggest specific code changes:
Click the suggestion icon in the comment box, then:
```suggestion
// Your suggested code here
const result = items.map(item => item.value);
```
The author can accept this with one click!Adding General Comments
For feedback not tied to specific lines:
- Scroll to the bottom of "Files changed" tab
- Write your overall feedback in the review summary box
Submitting Your Review
- Click "Review changes" button (top-right)
- Write a summary of your review
- Choose:
- Comment: Neutral feedback
- Approve: LGTM (Looks Good To Me)
- Request changes: Must be addressed
- Click "Submit review"
Option 2: Review Locally (For Testing)
Sometimes you want to run the code locally:
# Method 1: Fetch PR by number
git fetch origin pull/123/head:pr-123
git checkout pr-123
# Method 2: Add contributor's fork as remote
git remote add contributor https://github.com/contributor/repo.git
git fetch contributor
git checkout contributor/feature-branch
# Test the changes
npm install
npm test
npm start
# When done reviewing locally, switch back
git checkout mainUsing GitHub CLI
# Install GitHub CLI first: https://cli.github.com
# Checkout a PR
gh pr checkout 123
# View PR details
gh pr view 123
# Review with comments
gh pr review 123 --comment -b "Great work! Just a few suggestions..."
# Approve
gh pr review 123 --approve
# Request changes
gh pr review 123 --request-changes -b "Please address these issues"What to Look For During Review
Here's a systematic approach to reviewing code:
1. Correctness
- Does it work? Does the code do what it's supposed to?
- Edge cases: What happens with empty input, null values, large data?
- Logic errors: Are there any logical mistakes?
- Off-by-one errors: Array indices, loop conditions
2. Testing
- Tests included: Are there tests for new features?
- Tests pass: Do existing tests still pass?
- Test coverage: Are important cases tested?
- Test quality: Do tests actually verify behavior?
3. Code Quality
- Readability: Is the code easy to understand?
- Naming: Are variables/functions well-named?
- Complexity: Is it unnecessarily complicated?
- DRY principle: Is there repeated code that could be extracted?
- Functions: Are functions small and focused?
4. Design & Architecture
- Design patterns: Are appropriate patterns used?
- Separation of concerns: Is logic properly separated?
- Dependencies: Are new dependencies justified?
- Scalability: Will this work with more data/users?
5. Security
- Input validation: Is user input validated?
- SQL injection: Are queries parameterized?
- XSS prevention: Is output properly escaped?
- Authentication: Are protected routes actually protected?
- Secrets: No API keys or passwords in code?
6. Performance
- Algorithm efficiency: Could this be faster?
- Database queries: N+1 query problems?
- Memory usage: Are there memory leaks?
- Caching: Should results be cached?
7. Documentation
- Code comments: Are complex sections explained?
- Documentation updated: README, API docs, etc.
- Examples provided: For new features
- Changelog: Is it updated if applicable?
8. Code Style
- Project conventions: Does it match existing code?
- Linting rules: Does it pass the linter?
- Formatting: Consistent indentation, spacing
- Import organization: Consistent import order
Don't Nitpick Style
If the project has automated formatting (Prettier, Black, etc.), don't waste time on style issuesβlet the tools handle it. Focus on substance!
Giving Constructive Feedback
How you communicate feedback is as important as what you say.
The Feedback Formula
Good feedback structure:
- Observe: "This function returns null when X"
- Explain impact: "which could cause a crash in Component Y"
- Suggest solution: "Consider returning an empty array instead"
- Invite discussion: "What do you think?"
Good vs Bad Feedback Examples
Example 1: Naming
β Bad:
"This variable name is terrible."
β Good:
"The variable name data is a bit generic. Since this holds user profiles, maybe userProfiles would be more descriptive? This makes the code more self-documenting."
Example 2: Logic Issue
β Bad:
"This is wrong, you should use map."
β Good:
"This loop mutates the original array, which could cause issues for other consumers. Consider using .map() to create a new array instead. Here's an example:"
const processed = items.map(item => ({
...item,
processed: true
}));Example 3: Performance
β Bad:
"This will be slow. You need to optimize."
β Good:
"With large datasets, this nested loop could become slow (O(nΒ²) complexity). Have you considered using a Set or Map for faster lookups? Would reduce it to O(n). Happy to discuss if you'd like!"
Feedback Best Practices
Do:
- Ask questions: "Why did you choose this approach?"
- Explain reasoning: "This could cause X because Y"
- Provide examples: Show what you mean with code
- Acknowledge good work: "Nice solution to the edge case!"
- Be specific: Point to exact lines and issues
- Consider context: Understand time constraints, scope
- Offer to help: "Want to pair on this?"
Don't:
- Be harsh: "This is terrible code"
- Be vague: "Something seems off here"
- Make it personal: "You always do this"
- Demand without explaining: "Change this"
- Bikeshed: Argue about trivial style preferences
- Review while angry: Take a break if frustrated
- Forget to praise: Acknowledge what's done well
π― The 'We' Technique
Use "we" instead of "you" to make feedback collaborative:
- β "You didn't handle the error case"
- β "We should handle the error case here"
Types of Review Comments
1. Blocking Issues (Must Fix)
Critical problems that prevent merging:
- Security vulnerabilities
- Bugs that break functionality
- Breaking changes without migration path
- Missing tests for critical features
**Blocking:** This exposes user emails without authentication.
We need to add auth middleware here before merging.2. Important Suggestions (Should Fix)
Improvements that significantly impact quality:
- Performance issues
- Poor code structure
- Confusing naming
- Missing error handling
**Suggestion:** This N+1 query will slow down with many users.
Consider using a join or eager loading to fetch in one query?3. Nits (Nice to Have)
Minor improvements that don't block merging:
- Style preferences (if no auto-formatter)
- Minor naming improvements
- Optional refactorings
**Nit:** We typically use camelCase for function names here,
but not a blocker if you prefer snake_case.4. Questions
Ask for clarification:
**Question:** Why did you choose to use setTimeout here instead
of async/await? Just curious about the approach!5. Praise
Acknowledge good work:
**Nice!** This is a really elegant solution to the race condition.
Love the use of debouncing here. ππ·οΈ Label Your Comments
Prefix comments with their type (Blocking, Suggestion, Nit, Question) so the author knows priority.
Code Review Checklist
Use this checklist for consistent, thorough reviews:
Before Starting:
- β Read the PR description and linked issues
- β Check that CI/tests are passing
- β Verify PR size is reasonable
Functionality:
- β Does the code do what it's supposed to?
- β Are edge cases handled?
- β Is error handling appropriate?
Quality:
- β Is the code readable and well-named?
- β Is it reasonably simple (not over-engineered)?
- β Are functions/components appropriately sized?
- β Is there unnecessary code duplication?
Testing:
- β Are there tests for new functionality?
- β Do tests actually verify behavior?
- β Are edge cases tested?
Security:
- β Is user input validated?
- β Are there any SQL injection risks?
- β Is authentication/authorization correct?
- β Are secrets properly handled?
Documentation:
- β Are complex parts commented?
- β Is documentation updated?
- β Are API changes documented?
Common Review Pitfalls to Avoid
1. Rubber Stamping
Approving without actually reviewing:
Don't approve PRs you haven't read carefully. Your approval means you're confident the code is good!
2. Perfectionism
Demanding perfect code before merging:
Perfect is the enemy of good. Look for code that's good enough to merge, not perfect. Focus on significant issues, not every tiny detail.
3. Style Bikeshedding
Arguing about trivial style preferences:
If the project has formatting tools, let them handle style. If not, defer to existing conventions. Don't block PRs over personal style preferences.
4. Design Reviews During Code Review
Questioning fundamental approach after code is written:
Major architectural concerns should be discussed BEFORE implementation, not during code review. If you have fundamental concerns, discuss them, but understand the author already invested significant time.
5. Being a Gatekeeper
Using reviews to assert dominance:
Code review isn't about showing off your knowledge or blocking others. It's a collaborative process to improve code quality together.
Common Review Scenarios
Scenario 1: Everything Looks Good
Great work! The code is clean, well-tested, and solves the issue
effectively. I particularly like how you handled the edge case in
line 45. Approving! πScenario 2: Minor Issues Only
Overall this looks good! I have a few minor suggestions:
1. Consider renaming `data` to `userProfiles` for clarity (line 23)
2. This error message could be more descriptive (line 67)
None of these block merging though - feel free to merge as-is or
address them, your choice! Approving.Scenario 3: Needs Changes
Thanks for the PR! I've found a few issues that need addressing:
**Blocking:**
- Lines 45-50: This doesn't handle the null case, which will crash
when users have no profile
**Suggestions:**
- Line 78: Consider caching this API call - it's called on every render
- Lines 100-120: This logic could be simplified
Let me know if you have questions on any of this! Happy to discuss.Scenario 4: Major Architectural Concerns
I appreciate the work here, but I have concerns about the overall
approach. This tightly couples the auth logic to the component, which
will make testing difficult and doesn't match our architecture pattern.
Can we hop on a quick call to discuss? I want to make sure we align on
the approach before you put more time into this. My fault for not
catching this earlier in the design phase.Practice Review Commands
Try these commands for reviewing PRs locally:
Practice PR Review Commands
Test pull requests locally before reviewing
Try these examples:
Code Review Etiquette
For Reviewers:
- Review promptly: Don't leave PRs hanging for days
- Be kind: Remember there's a person on the other end
- Assume competence: The author probably had good reasons
- Ask, don't command: "What do you think?" not "You must"
- Explain why: Don't just say what to change
- Praise good work: Acknowledge what's done well
- Know when to discuss live: If review has 20+ comments, hop on a call
For Authors Receiving Reviews:
- Don't take it personally: It's about the code, not you
- Appreciate the time: Reviews take effort
- Ask questions: If you don't understand feedback
- Push back respectfully: If you disagree, explain why
- Learn from feedback: Reviews help you grow
- Respond to each comment: Even if just "Done!"
π€ It's a Collaboration
The best code reviews feel like a conversation between teammates working toward the same goal, not a one-sided critique. Both reviewer and author should learn something!
Key Takeaways
- Code review catches bugs, improves quality, and shares knowledge
- Review on GitHub's "Files changed" tab or check out locally for testing
- Look for correctness, testing, quality, security, performance, and documentation
- Give constructive feedback: observe, explain impact, suggest, invite discussion
- Label comments by severity: blocking, suggestion, nit, question, praise
- Use "Comment" for feedback, "Approve" when ready, "Request Changes" for must-fix issues
- Avoid perfectionism, bikeshedding, and gatekeeping
- Be kind, specific, and helpful in all feedback
- Review promptly and acknowledge good work
- Code review is collaborative, not adversarial
What's Next?
Excellent work! You now understand how to review pull requests effectively, give constructive feedback, and be a valuable collaborator. Code review skills make you a better developer and teammate!
In the next lesson, we'll tackle Handling Merge Conflicts. You'll learn what causes conflicts, how to resolve them step-by-step, understand conflict markers, use merge tools, and prevent conflicts from happening in the first place. Merge conflicts sound scary, but they're actually quite manageable once you understand them!
π― Practice Assignment
Before the next lesson, practice reviewing:
- Find an open source project you're interested in
- Look for open PRs that need review
- Review one PR using the checklist from this lesson
- Leave thoughtful, constructive comments
- If you have your own projects, ask a friend to review your PRs
- Pay attention to how different reviewers communicate feedback
Remember: reviewing code makes you better at writing it!