Understanding and Effectively Utilizing Pull Requests: A Comprehensive Guide for Developers

Ali Süleyman TOPUZ
7 min readAug 5, 2023

--

Pull Requests (PRs) are fundamental to effective collaborative software development, particularly in the open-source space and in environments where version control systems like Git are widely used. They play an essential role in facilitating code reviews, maintaining code quality, and fostering collaborative discussions. This guide aims to provide you with a thorough understanding of PRs and how to make the most out of them.

I. Creating a Pull Request

Let’s consider a scenario where you’re working on a new feature in your local development environment and have committed the changes to a feature branch. Now you’re ready to merge your changes to the main project.

Here is a simplified workflow on GitHub:

  • Push your feature branch to the remote repository: git push origin feature_branch.
  • Navigate to your repository on GitHub. You’ll see a prompt to create a new Pull Request.
  • Click “Compare & pull request”.
  • In the “Open a pull request” screen:
  • Set the base branch to the branch you wish to merge your changes into, often main or master.
  • Make sure the compare branch is your feature branch.
  • Write a clear, concise title for your PR. This title should briefly describe the changes you’ve made.
  • Write a comprehensive description in the body of the PR:

Purpose: Why is this PR necessary? What problem does it solve?

Approach: What does this PR do to address the problem?

Changes: Provide a detailed list of changes you’ve made.

Tests: Describe any tests you’ve added or modified, and their results.

  • Tag your colleagues for a review or assign reviewers on the right side of the PR page.
  • Click “Create pull request”.

II. Reviewing a Pull Request

Reviewing a PR involves examining the changes made by others and providing feedback. Below are some tips to review PRs effectively:

  • Understanding the changes: Start by reading the description to understand the rationale behind the changes. Look at the associated task or issue for more context.
  • Code quality: Is the code clean, well-organized, and following the coding standards and conventions of the project?
  • Code functionality: Does the code do what it is supposed to? Check the logic and the flow of the code to ensure it’s doing its job correctly.
  • Testing: Ensure that the code includes appropriate tests, and that all tests are passing. Tests should cover edge cases and potential error scenarios.
  • Comments and documentation: Ensure that the code is well-commented and any new functions, classes, or modules have appropriate documentation.
  • Performance and security: The code should not introduce any performance issues or security vulnerabilities.

III. Giving Constructive Feedback

Feedback should be constructive, respectful, and focused on the code, not the coder. Use the “suggestion” feature on GitHub to propose specific changes, and explain why your suggestion improves the code.

IV. Responding to Feedback

Be receptive to feedback. Address each comment, make necessary changes, and ask for clarification if needed.

V. Merging the Pull Request

Once your PR has been reviewed and approved, you can merge your changes. Often, projects will require you to squash your commits into a single commit before merging.

VI. Code Review Best Practices

  • Small, focused PRs: Smaller PRs are easier to understand and review.
  • Single feature or bug fix per PR: Each PR should address only one issue or add one feature.
  • Include helpful descriptions: Your PR description should explain what you did, why you did it, and how you did it.
  • Link related issues: If your PR addresses a specific issue or task, make sure to link it in your PR description.
  • Thorough testing: Include relevant tests to prove that your changes work as expected.
  • Continuous integration (CI): Use CI tools to automatically run tests and linters on every PR.
  • Regular code reviews: Make code reviews a regular part of your development process to catch issues early.

By adhering to these practices, you’ll be well on your way to mastering the art of pull requests and code reviews.

Bad Review Examples

Vague, non-constructive feedback

Comment: “This code is sloppy.”

This comment is unhelpful because it doesn’t specify what the problem is, where it is, or how it could be improved. It’s also negatively phrased, which can discourage the contributor.

Direct edits without explanations

Comment: “return customers.filter(c => c.active) should be return customers.filter(c => c.isActive)."

While the suggested change may be correct, the reviewer hasn’t explained why it’s necessary, leaving the author to guess what the problem was.

Personal criticisms

Comment: “You always make the same mistake. Didn’t you learn from the last PR?”

This comment is inappropriate because it’s aimed at the author, not the code. Code reviews should always be about the code.

Broad, ambiguous comments

Comment: “I don’t like how this function is written.”

This feedback is not helpful because it fails to clarify the issue with the function. Additionally, it’s subjective and doesn’t guide the author on how to improve.

Feedback without context

Comment: “This is wrong.”

This comment doesn’t provide enough context or specifics about what is wrong, or where the mistake resides. It doesn’t offer any direction on how to correct the error.

Aggressive or disrespectful language

Comment: “This is a mess. Can’t believe you submitted this.”

Such comments are unprofessional and disrespectful. They provide no value to the author and can harm the team’s morale.

Good Review Examples

Specific, actionable feedback

Comment: “The function findActiveCustomers uses c.active to filter customers. However, our customer objects use isActive as the property. Please change c.active to c.isActive to reflect this."

This comment explains what the problem is, where it is, and how to fix it. It’s clear and constructive.

Feedback with explanations

Comment: “I see that you’re using a for-loop to iterate over allProducts and filter out the ones with product.isAvailable set to true. This can be done more succinctly and readably using the Array .filter() method. For example: return allProducts.filter(product => product.isAvailable). This does the same thing but is cleaner and easier to understand."

This comment not only provides a suggestion but also explains why the suggestion might be an improvement, offering the author a chance to learn.

Positive reinforcement

Comment: “Good job on the calculateDiscount function. The logic is clear, and the use of a ternary operator makes it concise."

While it’s important to point out areas for improvement, it’s also crucial to acknowledge what the author did well. This can boost morale and encourage good practices.

In-depth, educational feedback

Comment: “This block of code could be refactored into a separate function to improve readability and maintainability. Keeping functions focused on a single task improves testability and makes the code easier to understand.”

This feedback is constructive, explaining both the issue and the proposed improvement. It’s also educational, providing reasoning behind the suggestion.

Praising good practices

Comment: “I really appreciate your thorough unit tests. They cover all the possible edge cases and make the function’s expected behavior very clear. Well done!”

Positive reinforcement encourages developers and helps them understand what they’re doing right.

Feedback with code examples

Comment: “Instead of the nested if-statements, consider using a ‘guard clause’ pattern to make the code easier to read. This approach reduces the cognitive load required to understand the function. For example:

function processOrder(order) {
if (order) {
if (order.isPaid) {
if (order.isShipped) {
return 'Order has been shipped already';
} else {
return 'Processing your order now';
}
} else {
return 'Order not paid';
}
} else {
return 'No order found';
}
}
// main code example

function processOrder(order) {
if (!order) {
return 'No order found';
}
if (!order.isPaid) {
return 'Order not paid';
}
if (order.isShipped) {
return 'Order has been shipped already';
}
return 'Processing your order now';
}

// recommendation

Including code examples in your feedback can help clarify your suggestions and show the author what you’re proposing.

Additional topics that you can consider to enrich review phase

Importance of Context

  • Stress the importance of including context in a PR. This includes linking to related issues, describing how you tested your changes, and documenting any out-of-the-ordinary decisions you had to make.

Inclusion of Screenshots or Videos

When changes are visual or interactive (like UI changes), including screenshots or short screen recordings can be extremely helpful to reviewers. It helps them understand what the changes will look like without needing to check out and run the code themselves.

Necessity of Timely Reviews

Encourage your team to prioritize PR reviews. Code is easiest to review when it’s fresh in the author’s mind, and leaving PRs open for a long time can lead to merge conflicts.

Value of Pair Programming and Pre-Review

Sometimes, complicated changes can be reviewed in person (or over a call) before the PR is even opened. This pre-review process can help catch issues early and reduce the back-and-forth in PR comments.

Usage of Linters and Automated Checks

Linters, style checkers, and automated tests can catch many common issues before a human reviewer even looks at the code. They enforce consistency across the codebase, saving time during code reviews.

Importance of a Good Summary

Encourage developers to take time to write a good summary in their commit messages. It’s often useful to detail the ‘why’ (the context, including bug numbers) as well as the ‘what’ (what was changed).

PR Templates

Mention the use of PR templates to standardize the information given when submitting a PR. This ensures all relevant information is provided and makes the review process smoother.

Conclusion

The practice of code reviews and pull requests forms an integral part of any successful software development cycle. It promotes collaboration, improves code quality, and shares knowledge across the team. Remember, the goal of code reviews is not just to improve the code in question, but also to foster a learning environment and help developers grow. Therefore, feedback should always be constructive, specific, and kind. Maintain a positive and respectful attitude during reviews, focusing on the code rather than the coder.

Moreover, never underestimate the importance of clear communication. Provide ample context in your PRs, be responsive to feedback, and strive to make your code as readable and understandable as possible. By following these guidelines, we can ensure a more productive, educational, and enjoyable experience for all team members involved in the code review process.

--

--

Ali Süleyman TOPUZ

Software Engineering and Development Professional. Writes about software development & tech. 📍🇹🇷