Introduction to Pull Requests
In our previous lecture, we introduced GitHub as a platform and briefly touched on pull requests as a key collaboration feature. Today, we'll dive deep into pull requests and code reviews, which form the backbone of collaborative development on GitHub and similar platforms.
Pull requests (often abbreviated as PRs) are more than just a mechanism for merging code—they're a communication tool, a documentation system, and a quality control checkpoint all in one. Think of them as a formal proposal to introduce changes, accompanied by a structured discussion forum.
By the end of this lecture, you'll understand how to create effective pull requests, review code thoughtfully, and use these tools to maintain high-quality code while collaborating efficiently with others.
Pull Request Anatomy
Let's examine the components of a pull request in detail to understand what makes them such powerful collaboration tools.
The Basic Structure
A pull request consists of several key elements:
- Title: A concise summary of the changes (e.g., "Add user authentication feature")
- Description: Detailed explanation of what the changes accomplish and why they're needed
- Source and Target Branches: The branch with changes (source/head) and the branch you want to merge into (target/base)
- Commits: The specific changes included in the pull request
- Changed Files: The files modified, added, or removed
- Comments: Discussion about the changes, both general and line-specific
- Review Status: Whether the PR has been approved, needs changes, or is still awaiting review
- Checks: Status of automated tests, linting, and other processes
- Labels: Tags that categorize the PR (e.g., "bug", "enhancement", "documentation")
- Assignees: People responsible for the PR
- Linked Issues: Related issues that this PR addresses
Together, these elements create a complete picture of what's being changed, why, and what the community thinks about it.
PR Lifecycle
A typical pull request goes through several stages:
- Creation: The PR is created, either as a draft or ready for review
- Review: Reviewers examine the code and provide feedback
- Revision: The author addresses feedback with additional commits
- Approval: Reviewers approve the changes
- Merge: The changes are incorporated into the target branch
- Cleanup: The source branch is typically deleted after merging
Some PRs might go through several rounds of review and revision before being approved and merged.
Types of Pull Requests
Pull requests can serve different purposes:
- Feature PRs: Introduce new functionality
- Bug Fix PRs: Resolve issues in existing code
- Refactoring PRs: Improve code quality without changing behavior
- Documentation PRs: Update documentation or comments
- Dependency PRs: Update libraries or dependencies
- Release PRs: Prepare code for a release
- Hotfix PRs: Emergency fixes for production issues
The type of PR often influences how it's reviewed and how quickly it's processed.
Pull Request Templates
PR templates help ensure that authors provide all necessary information. Here's an example of a comprehensive template:
## Description
Please provide a brief description of the changes in this pull request.
## Related Issue
Fixes #(issue number)
## Type of Change
- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
- [ ] This change requires a documentation update
## How Has This Been Tested?
Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration.
## Checklist:
- [ ] My code follows the style guidelines of this project
- [ ] I have performed a self-review of my own code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [ ] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] Any dependent changes have been merged and published in downstream modules
To add a template to your repository, create a file at .github/PULL_REQUEST_TEMPLATE.md.
Draft Pull Requests
Draft PRs allow you to create a pull request that is explicitly not ready for review yet:
- Signal that the PR is a work-in-progress
- Get early feedback on direction
- Prevent accidental merging
- Start CI runs to catch issues early
- Reserve the PR number and establish the change context
To create a draft PR, select "Create draft pull request" when creating the PR, or click "Convert to draft" on an existing PR.
Creating Effective Pull Requests
The way you structure and present your pull requests can significantly impact the review process and the likelihood of your changes being accepted. Let's explore best practices for creating effective PRs.
Preparation Before Creating a PR
Before submitting your pull request, take these preparatory steps:
- Pull Latest Changes: Update your branch with the latest changes from the target branch
git checkout main git pull git checkout feature-branch git rebase main - Run Tests Locally: Ensure all tests pass with your changes
npm test # or pytest # or whatever test command your project uses - Review Your Own Changes: Look at the diff to catch any issues
git diff main...feature-branch - Check Code Style: Run linters and formatters
npm run lint # or flake8 # or whatever linting command your project uses - Clean Up Commits: Consider using interactive rebase to make your history clean and logical
git rebase -i main
Writing Clear PR Descriptions
A good PR description should:
- Explain What: What changes are being made?
- Explain Why: Why are these changes needed?
- Explain How: How do these changes address the issue?
- Provide Context: Link to relevant issues, documentation, or discussions
- Highlight Key Changes: Point out important decisions or implementations
- Note Testing Done: Describe what testing you've performed
- List Potential Risks: Identify areas that might need special attention
Example of a well-written PR description:
## User Authentication Implementation
This PR implements a complete user authentication system using JWT tokens. It allows users to sign up, log in, and access protected routes with valid tokens.
### Changes Made
- Add User model with secure password hashing
- Create authentication controller with signup and login endpoints
- Implement JWT token generation and validation
- Add middleware for protecting routes
- Set up automated tests for authentication flows
### Why These Changes Are Needed
Issue #42 identified the need for a secure authentication system before we release the beta version.
### Implementation Details
- Uses bcrypt for password hashing with a cost factor of 12
- JWT tokens expire after 24 hours
- Includes email validation during signup
- Uses Redis for token blacklisting on logout
### Testing Done
- Added unit tests for all authentication functions
- Manual testing with Postman for all happy paths and common error scenarios
- Load tested with 1000 concurrent authentication requests
### Potential Concerns
- The Redis integration might need configuration updates in production
- We may want to adjust token expiration times based on user feedback
### Screenshots

Keeping PRs Focused and Manageable
Large, unfocused PRs are difficult to review and more likely to introduce bugs. To keep your PRs manageable:
- One Purpose Per PR: Each PR should do one thing well
- Limit Size: Aim for under 400 lines of changed code when possible
- Split Large Changes: Break large features into a series of smaller PRs
- Logical Sequence: If using multiple PRs, structure them to build on each other
- Avoid Refactoring with Features: Separate refactoring changes from functional changes
- Exclude Unrelated Changes: Don't fix unrelated issues in the same PR
Example of breaking down a large feature:
Making PRs Easier to Review
Help reviewers by making your PR easy to understand and evaluate:
- Logical Commits: Structure commits to tell a story about the changes
- Descriptive Commit Messages: Write clear messages that explain the purpose of each commit
- Add Comments: Use PR comments to highlight areas that need special attention
- Include Tests: Add relevant tests that demonstrate your changes work
- Link to Documentation: Provide references to relevant docs or standards
- Show Before/After: For visual changes, include screenshots or videos
- Update Documentation: Ensure documentation reflects your changes
Consider adding a special "Notes for Reviewers" section in complex PRs to guide the review process.
Addressing Feedback
When you receive feedback on your PR, handle it professionally:
- Be Responsive: Address all feedback in a timely manner
- Be Gracious: Thank reviewers for their input, even if you disagree
- Explain Changes: Describe how you addressed each point of feedback
- Use Suggestions: Use GitHub's suggestion feature to directly apply simple changes
- Mark as Resolved: Resolve comments when you've addressed them
- Request Re-review: Once you've made changes, request another review
Example response to feedback:
Thanks for the feedback! I've made the following changes:
1. Fixed the validation logic as suggested
2. Added tests for the edge cases you mentioned
3. Improved the error messages to be more user-friendly
Regarding the suggested refactoring of the authentication flow, I think that's a great idea but it might be better as a separate PR since it would touch multiple systems. What do you think?
Code Review Fundamentals
Code review is a systematic examination of code to find and fix mistakes, improve code quality, and ensure adherence to standards. Let's explore the foundations of effective code reviews.
The Purpose of Code Reviews
Code reviews serve multiple important purposes:
- Quality Assurance: Identify bugs, security issues, and performance problems
- Knowledge Sharing: Spread understanding of the codebase across the team
- Mentorship: Help junior developers learn from more experienced colleagues
- Consistency: Ensure code follows project conventions and standards
- Collective Ownership: Build shared responsibility for the codebase
- Documentation: Record design decisions and the reasoning behind them
Effective code reviews balance these different purposes to maximize the value derived from the process.
What to Look for in a Code Review
When reviewing code, consider these aspects:
- Correctness: Does the code do what it's supposed to do?
- Design: Is the code well-structured and maintainable?
- Functionality: Does the code handle all use cases, including edge cases?
- Complexity: Is the code as simple as possible but no simpler?
- Tests: Are there adequate tests that cover the changes?
- Naming: Are variables, functions, and classes named clearly?
- Comments: Is the code adequately commented where needed?
- Style: Does the code follow the project's style guidelines?
- Documentation: Are user-facing changes properly documented?
- Performance: Are there any potential performance issues?
- Security: Could the changes introduce security vulnerabilities?
- Accessibility: Do UI changes maintain or improve accessibility?
It's helpful to have a checklist or guide to ensure you cover all relevant aspects during a review.
Code Review Checklist
Here's a sample checklist to guide your code reviews:
## Code Review Checklist
### Functionality
- [ ] The code works as expected
- [ ] Edge cases are handled appropriately
- [ ] Error cases are handled gracefully
- [ ] The code handles concurrent operations safely if applicable
### Code Quality
- [ ] The code follows the project's style guide
- [ ] Variable, function, and class names are clear and meaningful
- [ ] There is no unnecessary duplication
- [ ] The code is as simple as possible but no simpler
- [ ] There are no commented-out code blocks
- [ ] There are no debug statements (e.g., console.log, print)
### Architecture and Design
- [ ] The code follows SOLID principles
- [ ] The code uses appropriate design patterns
- [ ] New components fit well with the existing architecture
- [ ] Dependencies are appropriate and minimized
### Performance
- [ ] The code doesn't perform unnecessary operations
- [ ] Expensive operations are optimized
- [ ] Database queries are efficient
- [ ] Resources are properly released
### Security
- [ ] User input is validated and sanitized
- [ ] Authentication and authorization are properly implemented
- [ ] Sensitive data is handled securely
- [ ] The code doesn't introduce new vulnerabilities
### Testing
- [ ] The code includes appropriate tests
- [ ] Tests cover normal cases, edge cases, and error cases
- [ ] Tests are clear and maintainable
- [ ] All tests pass
### Documentation
- [ ] Code includes necessary comments
- [ ] API documentation is updated
- [ ] README and other documentation is updated if necessary
Adapt this checklist to your project's specific needs and priorities.
Different Types of Code Reviews
Code reviews can take different forms, each with its own strengths:
- Pull Request Reviews: Asynchronous reviews performed through the PR interface
- Pair Programming: Real-time review while collaboratively writing code
- Over-the-Shoulder Reviews: Informal reviews where a developer walks through their code with a colleague
- Team Reviews: Group sessions where the team reviews code together
- Automated Reviews: Tools that automatically check for issues (linters, static analysis)
Many teams use a combination of these approaches depending on the situation.
Code Review Roles
In a typical code review process, there are several roles:
- Author: The person who wrote the code and is requesting review
- Reviewer: Person(s) examining the code and providing feedback
- Maintainer: Person with authority to approve and merge changes
- Stakeholder: Person with interest in the changes who may provide input
Often, the same person may play multiple roles on different PRs, rotating responsibilities within the team.
Performing Effective Code Reviews
The way you conduct a code review significantly impacts its effectiveness and the team's experience. Let's explore best practices for reviewing code.
Code Review Mindset
Approach code reviews with the right mindset:
- Be Collaborative: It's a team effort to produce the best code, not a critique session
- Focus on Learning: Use reviews as an opportunity to learn and teach
- Assume Positive Intent: Believe the author is trying their best
- Review the Code, Not the Coder: Separate the work from the person who wrote it
- Embrace Different Perspectives: Value diverse approaches to solving problems
- Balance Thoroughness with Practicality: Consider the context and purpose of the changes
This mindset helps create a positive and productive review environment.
The Review Process
Follow a structured process when reviewing code:
- Context Understanding: Read the PR description and linked issues
- Big Picture Review: Look at the overall changes before diving into details
- Detailed Examination: Go through the code line by line
- Testing Verification: Check that tests are adequate and pass
- Documentation Check: Ensure documentation is updated appropriately
- Feedback Compilation: Organize your thoughts into clear feedback
- Follow-up: Be available to discuss and clarify your feedback
This systematic approach helps ensure a thorough and effective review.
Providing Constructive Feedback
The way you phrase your feedback dramatically affects how it's received and acted upon:
Constructive Feedback Examples
| Instead of | Try |
|---|---|
| "This code is a mess." | "This might be easier to understand if we restructured it like this..." |
| "Why would you do it this way?" | "I'm curious about the reasoning behind this approach." |
| "You forgot to handle this edge case." | "It looks like we need to handle the case when the input is empty." |
| "This is wrong." | "I think there might be an issue here because..." |
| "Never use global variables." | "Using a local variable here would prevent potential side effects." |
Feedback Guidelines
- Be Specific: Point to exact lines or sections of code
- Explain Why: Don't just point out issues, explain the reasoning
- Offer Solutions: Suggest specific improvements when possible
- Ask Questions: Use questions to understand and prompt thought
- Prioritize Feedback: Distinguish between essential changes and preferences
- Praise Good Work: Call out well-implemented parts of the code
- Use "We" Language: Frame feedback as a team effort
Example of well-structured feedback:
I've reviewed your authentication implementation and have a few thoughts:
### Strengths
- The token generation logic is clean and well-tested
- Good job separating the authentication logic into its own middleware
- I like the clear error messages for different authentication failures
### Suggestions
- In the login controller, we might want to rate-limit login attempts to prevent brute force attacks
- The password validation could be strengthened with a minimum complexity requirement
- Consider adding a refresh token mechanism for better security
### Questions
- What was the reasoning behind the 24-hour token expiration? Would a shorter time improve security without affecting UX too much?
- Have we considered how this would scale across multiple servers?
Let me know what you think!
Using GitHub's Review Features
GitHub provides several tools to make the review process more efficient:
Line Comments
Click on the "+" icon that appears when hovering over a line to add a comment specific to that line.
Suggestion Feature
Use the suggestion feature to propose specific code changes:
- Click the "+" icon next to a line
- Click the "suggestion" button (looks like a pencil)
- Edit the code as needed
- Add any explanatory comments
- Submit the suggestion
The author can then directly accept your suggestion with a single click.
File View Options
Use these options to make reviewing easier:
- Unified vs. Split View: Choose between side-by-side or inline diffs
- Hide Whitespace Changes: Focus on meaningful changes
- View File: See the entire file instead of just the changes
- Expand/Collapse All: Manage visibility of all files at once
Review Summary
When you're done reviewing, submit an overall review:
- Click "Review changes" at the top right of the PR
- Add summary comments
- Choose a review type:
- Comment: General feedback without explicit approval
- Approve: Approve the changes and allow merging
- Request changes: Indicate that changes are needed before merging
- Submit the review
Balancing Thoroughness and Speed
One of the challenges in code reviews is finding the right balance between thoroughness and timely feedback:
- Prioritize Reviews: Treat code reviews as a high-priority task
- Set Aside Dedicated Time: Schedule specific time for reviews
- Use Progressive Levels of Detail: Start with the big picture, then dive deeper
- Focus on What Matters: Prioritize correctness and design over style
- Automate What You Can: Use tools to catch style and simple issues
- Timebox Reviews: Limit initial reviews to a reasonable time (e.g., 60 minutes)
- Consider Pairing: For complex changes, consider a pairing session instead of async review
Aim to provide initial feedback within one business day to keep development flowing.
Handling Code Review Challenges
Code reviews can sometimes be challenging, both technically and interpersonally. Let's discuss how to handle common issues.
Dealing with Large PRs
Very large pull requests are difficult to review effectively. When faced with a massive PR:
- Ask for Context: Request an overview of the changes
- Divide and Conquer: Focus on different aspects in separate review passes
- Review in Sessions: Break the review into multiple sessions
- Suggest Splitting: Recommend breaking the PR into smaller, logical chunks
- Pair Review: Consider reviewing with the author or another reviewer
- Focus on Architecture First: Review high-level design before details
For the future, work with the team to establish guidelines for PR size and scope.
Handling Disagreements
Disagreements during code reviews are normal and can be productive if handled well:
- Focus on Principles: Reference shared principles and standards
- Provide Evidence: Back up opinions with data, examples, or documentation
- Consider Trade-offs: Acknowledge that different approaches have pros and cons
- Seek Additional Perspectives: Involve other team members when appropriate
- Choose the Right Medium: Move complex discussions to real-time conversation
- Remember the Goal: The shared objective is to deliver quality code
- Agree on a Decision-Making Process: Have a clear way to resolve persistent disagreements
Example approach to a disagreement:
I see your point about using a factory pattern here. My concern is that it adds complexity for our specific use case. Perhaps we could discuss this in person? I'd like to understand your perspective better and see if we can find an approach that balances simplicity and flexibility.
Managing Review Fatigue
Review fatigue can reduce the effectiveness of code reviews. To combat it:
- Rotate Reviewers: Distribute the review load across the team
- Set Time Limits: Limit review sessions to maintain focus
- Take Breaks: Use techniques like Pomodoro to stay fresh
- Automate When Possible: Use tools to catch routine issues
- Recognize the Work: Acknowledge that reviews are valuable contributions
- Improve PR Quality: Work with authors to create more reviewable PRs
- Consider Review Pairs: Share the review load for complex changes
Remember that a tired reviewer might miss important issues, so managing fatigue is crucial for quality.
Mentoring Through Code Reviews
Code reviews provide excellent opportunities for mentorship:
- Explain the Why: Don't just point out issues, explain the reasoning
- Reference Resources: Link to articles, documentation, or examples
- Highlight Patterns: Point out recurring issues to focus learning
- Suggest Alternatives: Offer different approaches to solve problems
- Acknowledge Growth: Recognize improvements over time
- Balance Feedback: Mix constructive criticism with positive reinforcement
- Follow Up: Check in after the review to answer questions
Example of mentorship-oriented feedback:
I notice we're using a lot of nested if statements here. This can make the code harder to follow as complexity grows. Have you come across the "early return" pattern? It can help flatten the code and make the logic clearer. Here's an example:
```javascript
// Instead of:
function processUser(user) {
if (user) {
if (user.isActive) {
if (user.hasPermission) {
// Do something
return true;
} else {
return false;
}
} else {
return false;
}
} else {
return false;
}
}
// Consider:
function processUser(user) {
if (!user) return false;
if (!user.isActive) return false;
if (!user.hasPermission) return false;
// Do something
return true;
}
```
This article explains the pattern in more detail: [link]
What do you think about this approach?
Security and Compliance Considerations
Some projects require special attention to security and compliance issues:
- Maintain a Security Checklist: Have a specific list of security items to verify
- Include Security Experts: Involve specialists for security-sensitive changes
- Verify Compliance Requirements: Check that code meets regulatory standards
- Look for Common Vulnerabilities: Be familiar with issues like OWASP Top 10
- Verify Input Validation: Ensure all user input is properly validated
- Check Authentication/Authorization: Verify that access controls are properly implemented
- Review Data Handling: Ensure sensitive data is properly protected
For regulated industries or sensitive applications, consider implementing specialized review processes.
Automating Code Reviews
Automation can significantly enhance the code review process by catching issues early and freeing reviewers to focus on higher-level concerns.
Static Analysis Tools
Static analysis tools analyze code without executing it, finding potential issues:
- Linters: Enforce style and catch common errors
- ESLint/TSLint for JavaScript/TypeScript
- Flake8/Pylint for Python
- RuboCop for Ruby
- PHP_CodeSniffer for PHP
- Type Checkers: Verify type consistency
- TypeScript
- Flow for JavaScript
- Mypy for Python
- Style Formatters: Automate code formatting
- Prettier for JavaScript/TypeScript
- Black for Python
- Gofmt for Go
- Security Scanners: Identify potential vulnerabilities
- Semgrep
- Snyk
- Bandit for Python
- Complexity Analyzers: Measure code complexity
- SonarQube
- CodeClimate
- CodeFactor
These tools can be run locally during development and as part of automated CI checks.
Automated Tests in Review
Automated tests provide confidence that code changes work as expected:
- Unit Tests: Verify individual components in isolation
- Integration Tests: Check interactions between components
- End-to-End Tests: Validate complete workflows
- Performance Tests: Ensure changes don't degrade performance
- Security Tests: Check for vulnerabilities and security issues
- Accessibility Tests: Verify that UI changes maintain accessibility
Automated tests should run as part of the CI process for every pull request.
Setting Up GitHub Checks
GitHub Checks provide feedback directly in the PR interface:
GitHub Actions Example
name: Code Quality Checks
on:
pull_request:
branches: [ main, develop ]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Node.js
uses: actions/setup-node@v3
with:
node-version: '16'
- name: Install dependencies
run: npm ci
- name: Run linting
run: npm run lint
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Node.js
uses: actions/setup-node@v3
with:
node-version: '16'
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm test
security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Run security scan
uses: snyk/actions/node@master
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
Required Checks
You can configure GitHub to require certain checks to pass before a PR can be merged:
- Go to the repository's Settings tab
- Click on Branches in the sidebar
- Under "Branch protection rules," select the branch (e.g., main)
- Check "Require status checks to pass before merging"
- Select the checks that must pass
This ensures that PRs can only be merged when they meet your quality standards.
Code Review Bots
Specialized bots can further automate the review process:
- Dependabot: Automatically updates dependencies and creates PRs
- CodeClimate: Provides automated code quality feedback
- Codecov/Coveralls: Reports on test coverage changes
- Danger: Automates common review chores and enforces team practices
- Reviewable: Enhances GitHub's review interface
Example Danger.js file to enforce PR best practices:
import {danger, fail, warn, message} from 'danger';
// Require PR description
if (danger.github.pr.body.length < 10) {
fail('Please provide a meaningful description for this PR.');
}
// Check for test files
const changedFiles = [...danger.git.modified_files, ...danger.git.created_files];
const hasTestChanges = changedFiles.some(file => file.includes('test') || file.includes('spec'));
const hasSourceChanges = changedFiles.some(file =>
file.includes('src/') &&
!file.includes('test') &&
!file.includes('spec')
);
if (hasSourceChanges && !hasTestChanges) {
warn('This PR contains source code changes, but no tests. Consider adding tests.');
}
// Check PR size
const bigPRThreshold = 500;
const linesChanged = danger.github.pr.additions + danger.github.pr.deletions;
if (linesChanged > bigPRThreshold) {
warn(`This PR is quite large (${linesChanged} lines changed). Consider breaking it into smaller PRs if possible.`);
}
// Encourage labels
if (danger.github.pr.labels.length === 0) {
message('Consider adding labels to this PR to categorize it.');
}
These tools can catch issues early in the process and provide consistent feedback.
Balancing Automation and Human Review
While automation is valuable, it's important to find the right balance:
- Automate the Mundane: Use tools for style, formatting, and simple checks
- Reserve Human Review for Higher-Level Concerns: Design, architecture, business logic
- Don't Over-Automate: Some judgments require human expertise
- Use Automation as a First Pass: Fix automated issues before human review
- Customize Rules to Your Team: Adapt tooling to your specific needs
- Regularly Review and Update Rules: Evolve automation as your team learns
The goal is to use automation to enhance human review, not replace it.
Building a Code Review Culture
Beyond the technical aspects, creating a positive code review culture is essential for team success.
Establishing Team Guidelines
Clear guidelines help set expectations and create consistency:
- Define Review Scope: What aspects should reviewers focus on?
- Set Timelines: How quickly should reviews be performed?
- Clarify Approval Process: How many approvals are needed? Who can approve?
- Document Conventions: What are the team's coding standards?
- Specify PR Format: What information should PRs include?
- Outline Resolution Process: How are disagreements handled?
Example code review guidelines document:
# Code Review Guidelines
## Purpose
Our code review process aims to improve code quality, share knowledge, and ensure maintainability.
## Timeline
- Reviewers should begin review within 24 business hours
- Authors should respond to feedback within 24 business hours
- For urgent PRs, use the "urgent" label and notify the team
## PR Requirements
- Clear description of changes
- Link to relevant issue
- Appropriate tests
- Updated documentation if applicable
- Passing CI checks
## Review Focus
Reviewers should prioritize in this order:
1. Correctness: Does the code do what it's supposed to?
2. Security: Are there potential vulnerabilities?
3. Design: Is the code well-structured and maintainable?
4. Performance: Are there efficiency concerns?
5. Readability: Is the code clear and self-documenting?
6. Style: Does the code follow our conventions?
## Approval Process
- All PRs require at least one approval before merging
- For critical components, require approval from component owner
- No self-approvals
## Communication Guidelines
- Be respectful and constructive
- Frame feedback as suggestions or questions when possible
- For complex feedback, consider real-time discussion
- Use GitHub suggestions for simple changes
- Praise good work
## Resolving Disagreements
- Focus on principles and evidence
- If consensus can't be reached, escalate to tech lead or team discussion
Document your guidelines and keep them in your repository for easy reference.
Training and Onboarding
Help team members become effective reviewers and PR authors:
- Review Walkthrough: Demonstrate how to perform a thorough review
- PR Creation Guide: Show how to create effective PRs
- Code Examples: Share examples of good PRs and helpful reviews
- Pair Reviews: Have new team members review alongside experienced developers
- Feedback on Reviews: Provide guidance on review quality
- Technical Standards: Ensure everyone understands the team's coding standards
For new team members, consider gradually introducing them to the review process.
Measuring and Improving
Track metrics to identify bottlenecks and improvement opportunities:
- Time to First Review: How long until a PR receives initial feedback?
- Time to Merge: How long from PR creation to merge?
- Review Iteration Count: How many rounds of feedback before approval?
- Defect Rate: How many bugs are found after merge?
- PR Size: How many lines of code are changed in PRs?
- Review Coverage: What percentage of code changes are reviewed?
Regularly discuss these metrics as a team and experiment with process improvements.
Recognizing Good Work
Acknowledge and celebrate positive contributions to the review process:
- Highlight Thorough Reviews: Recognize detailed, helpful reviews
- Praise Well-Structured PRs: Call out PRs that are easy to review
- Acknowledge Improvement: Notice when team members apply feedback
- Celebrate Collaboration: Recognize productive discussions
- Value Review Time: Treat code review as important work, not an afterthought
This positive reinforcement encourages continued good practices.
Advanced Pull Request Techniques
Let's explore some advanced techniques to make your pull request workflow even more effective.
Draft Pull Requests for Early Feedback
Draft PRs are perfect for getting early feedback while making it clear the work isn't complete:
- Work in Progress: Signal that the code is still evolving
- Design Validation: Get feedback on your approach before investing too much time
- Incremental Reviews: Break complex changes into manageable review chunks
- Parallel Development: Allow others to see your progress while you continue working
Example workflow:
- Create a draft PR early in the development process
- Add a note about what feedback you're looking for
- Continue working while waiting for initial feedback
- Address feedback as you go
- Mark as "Ready for Review" when complete
Dependent Pull Requests
For complex features that need to be broken down, you can create dependent PRs:
- Create the first PR with foundational changes
- Create subsequent PRs that branch from the first PR
- In the description, note the dependency: "Depends on #123"
- Review and merge PRs in dependency order
This approach allows for more focused reviews while maintaining the relationship between changes.
Using PR Templates Effectively
Customize PR templates for different types of changes:
- Feature Template: Focus on requirements, implementation details, and testing
- Bug Fix Template: Emphasize reproduction steps, root cause, and verification
- Refactoring Template: Highlight before/after comparisons and risk assessment
- Documentation Template: Focus on clarity, completeness, and examples
To set up multiple templates, create a .github/PULL_REQUEST_TEMPLATE/ directory with a template file for each type.
Interactive Rebasing Before PR
Clean up your branch before submitting a PR:
git checkout feature-branch
git rebase -i main
During the interactive rebase, you can:
- Squash related commits: Combine multiple small commits into logical units
- Reword commit messages: Make messages clear and consistent
- Reorder commits: Present changes in a logical sequence
- Split commits: Separate unrelated changes
- Fix up: Combine minor fixes with their related commits
This creates a clean, logical history that's easier to review and understand.
PR Descriptions for Maximum Clarity
Advanced PR descriptions include several key sections:
## Overview
[Provide a high-level summary of the changes]
## Problem
[Explain what problem this PR solves]
## Solution
[Describe your implementation approach and why it's appropriate]
## Changes
[List specific changes, possibly organized by component or file]
## Testing
[Describe how you've tested these changes]
## Screenshots/Videos
[Include visuals for UI changes]
## Performance Impact
[Discuss any performance implications]
## Security Considerations
[Address any security aspects]
## Deployment Notes
[Include any special deployment requirements]
## Related PRs
[Link to any related pull requests]
## Checklist
- [ ] Documentation updated
- [ ] Tests added/updated
- [ ] Accessibility maintained/improved
- [ ] Performance impact assessed
- [ ] Security implications considered
- [ ] Compatibility checked
Adapt this template to fit your project's specific needs.
Advanced Code Review Techniques
For complex PRs, consider these advanced review approaches:
- Multi-Stage Reviews: First focus on architecture, then implementation details
- Synchronous Review Sessions: Schedule a live session for complex changes
- Specialized Reviewers: Assign different aspects to reviewers with relevant expertise
- Pre-Implementation Reviews: Review design documents before coding begins
- Post-Merge Reviews: For urgent changes, merge first but review thoroughly after
- Test-Driven Reviews: Focus first on test coverage and quality
Choose the approach that best fits the specific PR and team context.
Practice Exercises
Let's reinforce what we've learned with hands-on exercises:
Exercise 1: Creating an Effective Pull Request
- Create a new branch from main in a repository
- Make several meaningful changes (add a feature or fix a bug)
- Commit your changes with clear, descriptive messages
- Push your branch to GitHub
- Create a pull request with:
- A descriptive title
- A comprehensive description following the template provided earlier
- Screenshots or videos if applicable
- Any relevant labels
- Request a review from a colleague
Exercise 2: Performing a Thorough Code Review
- Find a pull request to review (from a colleague or an open source project)
- Follow a structured review process:
- Understand the context from the description and linked issues
- Review the overall change for design and architecture
- Examine the code line by line for issues
- Check tests for coverage and correctness
- Verify documentation updates
- Provide constructive feedback:
- Use line comments for specific issues
- Use the suggestion feature for simple fixes
- Ask questions to understand choices
- Highlight positive aspects
- Submit your review with a summary of your findings
Exercise 3: Addressing Review Feedback
- Review feedback received on one of your pull requests
- Respond to each comment:
- Thank the reviewer for their input
- Address the feedback with code changes or explanations
- Apply suggestions when appropriate
- Ask questions if something is unclear
- Push additional commits to address the feedback
- Mark resolved comments as resolved
- Request a re-review when all feedback is addressed
Exercise 4: Setting Up Automated Checks
- Choose a repository to set up automated checks for
- Configure at least three of the following:
- Linting (ESLint, Flake8, etc.)
- Automated tests
- Code formatting (Prettier, Black, etc.)
- Code coverage checks
- Security scanning
- Set up a GitHub Actions workflow to run these checks on PRs
- Configure branch protection to require these checks to pass
- Test the setup by creating a PR with intentional issues
Exercise 5: Collaborative Review Session
- Form pairs or small groups
- Select a complex PR or open source contribution
- Conduct a synchronous review session:
- Have the author explain the changes
- Review the code together
- Discuss alternative approaches
- Document findings and feedback
- Compare this experience with asynchronous reviews
- Reflect on what worked well and what could be improved
Further Reading
- GitHub Documentation: Pull Requests
- Google Engineering Practices: Code Review
- Code Reviews: Just Do It by Jeff Atwood
- The (Written) Unwritten Guide to Pull Requests by Atlassian
- Five Tips for More Helpful Code Reviews by thoughtbot
- How to Serve Up Pull Requests by GitHub
- Conventional Comments for structured review feedback
- Conventional Commits for standardized commit messages