Developers are often so focused on writing code that they take other parts of the development process for granted; parts that, if upgraded, could substantially improve the efficiency and productivity of their entire team.
Pull requests (PRs) are one example. Often overlooked and rushed, poor pull requests can significantly slow development and create unnecessary work for other team members. Conversely, creating high-quality PRs through best practices and effective workflows can speed up the development process and improve code quality and reliability.
With so much focus on delivery speed, it's common for development teams to deprioritize creating quality pull requests and managing them effectively. A LinearB study on engineering metrics benchmarks found that half of the pull requests they analyzed were idle for at least half their lifespan, meaning no one was actively working on them.
Let’s take a deep dive into pull requests to uncover what good and bad PRs look like and what your team can do to optimize the process of creating and analyzing them.
What is a Pull Request?
A pull request, often called a merge request, is essentially a communication tool in development. Developers use pull requests to explain their work to the rest of their team (managers, scrum masters, testers, etc.).
A pull request provides an avenue for open communication, urging team members to talk about code changes, analyze them, and make recommendations for improvements.
When developers create a PR, they are setting the stage for collaboration with testers and other developers, making it easier for those reviewing the code to understand it and identify and fix any issues before merging the code into production. Because of this, following pull request best practices can go a long way toward maintaining code quality.
How Do Pull Requests Work?
Before a pull request can take place, the developer creates a fork in the main repository (repo). A fork is a new repo that has the same visibility and code as the original repo. Forks allow developers to iterate on code changes before adding them to the original repo. The fork that's created is cloned onto the developer’s local machine.
Now, the developer can make necessary changes to the code locally. Once they have completed and tested the code changes, they can push the changes to the forked repo they created.
A pull request can now be made. Once the PR is made, the maintainer of the main repository is alerted of the new code changes and can review them. The maintainer is usually a member of the DevOps team who is responsible for managing the repo. This person approves code changes and decides which merge requests are ready to be merged with the main repo and eventually pushed into production. While the repo maintainer is the one who makes the final decision on code changes, this person is usually not the one who reviews the PR first. Typically, a PR first goes through testers or other developers.
Pull requests can be used as a request for help as well. If a developer has issues and can’t figure out a proper solution, they can use a pull request to get constructive feedback from other team members.
To ensure this entire process runs smoothly, developers must invest time drafting the pull request before sending it. The process of drafting a pull request includes giving the PR a title and describing the code changes included in the PR.
Teams often create pull request templates to help with this process. A typical PR summary includes the following:
- A summary of the updates made to the code to explain what the developer was trying to accomplish with their work (bug fix, new feature, etc.).
- Unit test cases that document whether the new code has been properly tested across all necessary browsers or devices.
The pull request process protects the main repository from unsatisfactory code, encourages open communication and collaboration throughout the development lifecycle, and documents your developers' work.
What Does a Bad Pull Request Look Like?
Not all pull requests are created equal. A bad pull request is, essentially, one that is difficult to review and collaborate on. PRs that are hard to review get fewer comments and recommendations for improvement, often leading to undetected bugs, a general degradation of code quality, and a steady increase in accrued technical debt if left unaddressed.
In the worst-case scenario, bad PRs are ignored, leading to a process in which code changes are approved without reviewing pull requests, which negates the purpose of pull requests entirely.
Some examples of inadequate pull requests include:
- PRs with no context. Testers might not even want to pick up a PR if they don’t know what it’s about, what changes have been made, or what the estimated review time associated with the code changes is.
- PRs with no associated tests. Developers should run their own tests using static code analysis tools first and have unit tests in place to catch common coding mistakes and bugs before creating a PR.
- PRs with inadequate scope. Sometimes, PRs require multiple reviewers and input from internal experts (like DevSecOps team members) to analyze large and potentially high-impact changes properly.
- PRs with no documentation. Maintainers shouldn’t have to research to find the necessary documentation for understanding the code changes developers have made. A good PR provides all necessary documentation that helps reviewers better understand the intent of the developer's work.
Thankfully, there are plenty of best practices teams can follow to avoid creating bad pull requests and, instead, create meaningful and effective pull requests that make everyone’s jobs easier and, ultimately, your code better.
What Are the Benefits of Creating Proper Pull Requests?
Pull requests help development teams monitor and uphold code quality. A good PR process serves as a safety net, making sure that poor or potentially unsafe code doesn’t make it into production and providing other benefits to your development team, including:
- Decreased errors. When code is reviewed and tested by several people, the chances of merging coding errors, bugs, and security issues are significantly reduced. Pull requests are only merged once the build is finished, allowing your team to ensure that all code being committed adheres to relevant coding standards. It also confirms unit tests are performed, improving code coverage and overall stability and quality.
- Improved collaboration. Pull requests promote discussion and collaboration. They allow team members to comment on code changes, ask relevant questions, and suggest improvements before new code is merged.
- Learning opportunities. Collaboration and peer code reviews also facilitate up-skilling, allowing developers to learn new skills and update their knowledge. A senior developer can highlight approaches, techniques, and best practices that the developers who created the code might not have been familiar with initially.
- Increased visibility. Good pull requests give your entire team, stakeholders included, clearer insights and greater visibility into the release of new features, updates, and critical bug fixes.
- Improved onboarding. New team members can review past and current pull requests to learn more about the codebase and understand how coding standards are implemented. The ability to view more experienced team members' work can considerably decrease the learning curve for new developers.
But to see these benefits, your team must take the process of creating pull requests seriously and strive to make them exceptional.
4 Pull Request Best Practices
In most development teams, pull requests are an unavoidable part of the development process. If you want your code to merge into the product eventually, you must submit a pull request first.
However, the existence of pull requests on its own doesn’t guarantee good results. Here are a few initiatives to follow if you want to start producing pull requests that positively impact your development process.
1. Encourage Developers to Review Independently
Even though the purpose of a PR is to have someone else check your work, developers should be urged to take the time to review the code themselves before they create the PR.
Review your own code before submitting a PR to catch common mistakes and make the job of your testers or repo maintainers easier. If you see anything within your code that could be confusing or interpreted in different ways, leave inline comments to explain your code choices and changes.
2. Create Draft Pull Requests
Most popular code hosting platforms like GitHub and GitLab allow you to create drafts of your pull requests before you make your actual pull requests. Use this to your advantage and create drafts of your pull request even before you’re done with all your code changes so that you can get early feedback on your code.
Draft PRs provide an easy avenue for collecting input and suggestions from your team even before you’re ready to commit your changes. Incorporate feedback early to enhance your code quality through peer review and increase the chances of your pull request being accepted on your first commit.
3. Keep Pull Requests Small
There are many advantages to keeping your pull requests focused and short. Keeping PRs short allows the review to give it its undivided attention and analyze the changes faster.
The generally recommended number of lines of code (LOC) for a pull request is 200-400. LinearB’s study found that cycle and idle time doubled when comparing PRs of 200 lines to PRs with 100 lines of code or less.
The longer your PR, the more time it takes to review it and give feedback. Smaller pull requests are a staple of Agile software development practices. They are also encouraged in shift-left development strategies, which aim to increase the speed of the development process while, at the same time, guaranteeing code security by testing it early and often in the development lifecycle.
However, writing short PRs is easier said than done. Pull requests can quickly increase in length after tests are written for it, for example. It takes practice and a plan to keep them concise but thorough enough to provide context.
Instead of counting LOC, some teams create shorter pull requests by breaking them down into units like database layer or event publisher. Experiment with various methods for keeping PRs short and adopt whatever system works best for your team.
4. Create Clear Titles and Descriptions
Provide as much context as possible when writing commit messages for your PRs to make understanding and reviewing code easier. If your reviewer does not know what problem you are trying to solve with your code changes, they won’t know whether you’ve succeeded in addressing and solving it.
The easiest way to provide needed context for your PRs is to write a clear title and description for your commit message. A good PR title clearly states what you’ve changed—”Test case added for X,” for example.
Include visuals, like screenshots, videos, and GIFs, to improve the description, especially when making changes to the front end. When the reviewer can see the changes, it’s easier to understand and validate changes made to the product’s user interface and overall experience.
A good pull request description describes what changes were made, explains the PR's purpose, and clearly explains how the PR achieves its goals. It should also include the testing plan for the PR.
The testing strategy is especially important, letting reviewers know how you run unit tests, which code areas were tested, and what tests were run. Don’t forget to include your test results, both successful and unsuccessful. Provide test transparency to enable the PR reviewer to perform their tests and checks more effectively.
Automate PR Reviews With Static Code Analysis
Perform static code analysis before submitting your pull requests to increase the speed of your code reviews with automation. Static code analysis tools help you automate the process of checking your code changes against standards and requirements to find and fix issues in your pull request before you send them off to be reviewed by others.
Code quality tools like Codacy are perfect solutions for automating your PR code review process. Once static code analysis is performed, you can head to the platform’s Quality Pull Request page to see an overview of every pull request in your repository, complete with analysis statuses and code quality metrics for each PR.
You can set rules and quality gates for every PR to ensure you’re never committing a PR that doesn’t achieve a passing quality score. Some of the quality metrics Codacy shows include a list of all new and fixed code issues, duplicated code blocks, complexity, and diff coverage that tells you which new lines of code are covered by tests and which aren’t.
Start your free trial today to see how Codacy can help your organization improve its code quality throughout the entire development lifecycle, from pull requests to production.