Imagine You're Reviewing a 500-Line PR
Imagine you're a reviewer, and a pull request lands in your queue. It's 500 lines of changes—touching a dozen files, mixing a refactor with a new feature, and there's a suspicious eval() buried in the middle. You know that Google's own research found the median change is just 24 lines, and that more than 35% of changes touch only one file (Modern Code Review: A Case Study at Google, ICSE-SEIP '18). This PR is not that. You're looking at something that will take hours to review carefully—hours you don't have. And here's the kicker: if you had the right automation in place, you wouldn't need to spend that time eyeballing for syntax errors, obvious security holes, or dependency vulnerabilities. The tools would have already flagged them. This is the core of modern code review: let machines handle the mechanical, so humans can focus on design, logic, and maintainability.
The Case for Static Analysis: Your First Line of Defense
Static analysis tools are not new—SonarQube has been analyzing reliability, security, and maintainability for years, measuring bugs, vulnerabilities, code smells, coverage, and duplication (SonarQube, GEANT KB). But the modern landscape is richer. For Python, you have Bandit, which parses each file into an AST and runs plugins to find common security issues (Bandit, PyCQA Docs). For Go, gosec goes further, scanning the AST and SSA representation, and even does taint analysis for SQL injection, command injection, path traversal, SSRF, XSS, and unsafe deserialization (gosec, Go Security Checker). For JavaScript, ESLint is completely pluggable—every rule is a plugin, making it a versatile tool for consistency and bug avoidance (ESLint Docs). And then there are general-purpose engines like Semgrep, which can scan any codebase, repository, or folder for insecure patterns (Semgrep Docs).
These tools are not replacements for human review. They are the first pass—the ones that catch the 'dumb' stuff so you don't have to. Google's own guidance is blunt: linters, formatters, static analysis, secret scanners, and dependency scanners should handle style and mechanical checks, so human review focuses on logic and architecture (Google Engineering Practices, code review). That's the right division of labor. But here's the trap: many teams stop there. They configure a linter, add a quality gate, and think they're done. They're not.
Human Review Still Matters: The Gates and the Eyes
The machines can't tell you if the design is sound, if the tests are meaningful, or if the code is over-engineered. Google's research on code review at scale found that finding bugs is not the primary focus—the key expectations are education, maintaining norms, gatekeeping, and accident prevention (Modern Code Review: A Case Study at Google, ICSE-SEIP '18). That's fundamentally human work. And it's not just about catching bugs; it's about knowledge transfer and team awareness, as Bacchelli and Bird found in their Microsoft study (Modern Code Review: Expectations, Outcomes, and Challenges, ICSE 2013).
So how do you make human review efficient? The answer is small pull requests. Google's guidance is clear: 100 lines is a reasonable size, 1000 lines is too large, and even a 200-line change spread across 50 files is too large (Google Engineering Practices - Small CLs). Small PRs are reviewed more quickly and thoroughly, and they're less likely to introduce bugs (Google Engineering Practices - Small CLs). That's not just opinion—it's backed by data. At Google, the median change is 24 lines, and more than 80% of reviews finish in a single iteration (Modern Code Review: A Case Study at Google, ICSE-SEIP '18). That's the sweet spot.
But even with small PRs, you need to enforce the process. That's where branch protection and code owners come in. On GitHub, you can require a specific number of approving reviews before merging, and you can require reviews from designated code owners (GitHub Docs - About protected branches, About code owners). GitLab offers similar enforcement, but with a catch: on GitLab Free, approvals are optional and don't block merging—you need Premium or Ultimate for required approvals (GitLab Docs - Merge request approvals). That's a critical distinction when you're choosing your platform.
The Tooling Showdown: GitHub vs. GitLab vs. Gerrit
Let's compare the three main platforms you're likely considering for your code review workflow. Each has its strengths, but they differ in how they handle automation and enforcement.
| Criterion | GitHub | GitLab | Gerrit |
|---|---|---|---|
| Review enforcement | Branch protection: require approvals, dismiss stale approvals, require status checks (GitHub Docs) | Free: optional; Premium/Ultimate: required approvals, code owners (GitLab Docs) | Web-based tool built on Git; review before commit (Gerrit Docs) |
| Code owner automation | CODEOWNERS file auto-requests reviews (GitHub Docs) | CODEOWNERS can determine reviewers in Premium/Ultimate (GitLab Docs) | Not native; manual assignment |
| Security scanning integration | Dependabot alerts, code scanning with CodeQL or SARIF (GitHub Docs) | Code Quality reports with gl-code-quality-report.json, integrates ESLint, mypy, etc. (GitLab Docs) | No native security scanning; relies on external CI |
| Stale approval handling | Dismiss stale approvals when diff changes (GitHub Docs) | Not explicitly mentioned; depends on configuration | Not applicable; Gerrit uses a different model |
GitHub and GitLab both have robust ecosystems, but Gerrit is a different beast—it's a review tool built on Git, not a full platform (Gerrit Docs). If you're starting fresh, I'd argue GitHub has the edge for teams that want automation baked in. Its branch protection rules let you require status checks, which means your CI can run static analysis and fail the merge if the code doesn't meet your quality gate. GitLab's free tier is a deal-breaker for many teams because approvals are optional—you can't enforce review without paying. But if you're already on GitLab Premium, it's a solid choice, especially with its Code Quality widget that shows violations in the merge request (GitLab Docs).
The Winning Combo: Automation Plus Small PRs
So what's the winning move? It's not just choosing a platform—it's how you configure it. Here's the blunt advice: set up a quality gate that blocks merging if static analysis fails. SonarQube's concept of a quality gate is exactly that—a set of conditions that answer 'is my project ready for release?' (SonarQube Server Docs). The built-in Sonar way gate, for example, requires no new issues, all new security hotspots reviewed, at least 80% test coverage on new code, and less than 3% duplication on new code (SonarQube Server Docs). That's a high bar, but it's a starting point. You can adjust it to your project.
And then, critically, enforce small PRs. Use branch protection to require a minimum number of approvals, and require status checks so that the quality gate must pass before merge (GitHub Docs - About protected branches). That way, you're not relying on reviewers to catch style nits—the machine does. Reviewers can focus on design, logic, and whether the change actually improves code health, which Google defines as the primary purpose of review (Google Engineering Practices - Standard of Code Review).
Let me give you a concrete example. Say you're reviewing a Python change that adds a new endpoint. Your CI runs Bandit and it flags a potential SQL injection because the code concatenates a user input directly into a query. Under your quality gate, the merge is blocked. The developer fixes it, and you review the diff. You're not spending time explaining why SQL injection is bad—the tool did that. You can instead ask: 'Is this the right design? Are the tests adequate? Is there unnecessary complexity?' That's where human review adds value.
Bottom line
If you take one thing from this, it's this: automate the mechanical checks—static analysis, security scanning, dependency alerts—and make them part of your merge pipeline via a quality gate. Then use branch protection to require human review, but keep pull requests small. The data is clear: small changes are reviewed faster and more thoroughly (Google Engineering Practices - Small CLs; Modern Code Review: A Case Study at Google). The tools will catch the 'dumb' bugs; you and your team can focus on the 'smart' ones. That's the winning combination.
Sources
- Google Engineering Practices - Small CLs - https://google.github.io/eng-practices/review/developer/small-cls.html
- Modern Code Review: A Case Study at Google (ICSE-SEIP '18) - https://www.papercache.org/papers/mlsys/system/2026/03/25/modern-code-review-a-case-study-at-google
- SonarQube Server Docs - Understanding quality gates - https://docs.sonarsource.com/sonarqube-server/2026.1/quality-standards-administration/managing-quality-gates/introduction-to-quality-gates
- GitHub Docs - About protected branches - https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-protected-branches/about-protected-branches
- Bandit (PyCQA) Docs - https://bandit.readthedocs.io/en/latest/
- GitLab Docs - Merge request approvals - https://docs.gitlab.com/user/project/merge_requests/approvals/
Comments (0)
Please sign in to post a comment.
Don't have an account? Create one
No comments yet. Be the first to comment!