<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Othman Shareef</title>
    <description>The latest articles on DEV Community by Othman Shareef (@othman_pyor).</description>
    <link>https://dev.to/othman_pyor</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4014370%2F2c916e57-8199-41e5-8cd7-9a527e2de00e.png</url>
      <title>DEV Community: Othman Shareef</title>
      <link>https://dev.to/othman_pyor</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/othman_pyor"/>
    <language>en</language>
    <item>
      <title>GitHub Code Review Shortcuts That Actually Save Time</title>
      <dc:creator>Othman Shareef</dc:creator>
      <pubDate>Wed, 30 Sep 2026 08:00:00 +0000</pubDate>
      <link>https://dev.to/pyor/github-code-review-shortcuts-that-actually-save-time-2157</link>
      <guid>https://dev.to/pyor/github-code-review-shortcuts-that-actually-save-time-2157</guid>
      <description>&lt;p&gt;Most GitHub code review shortcuts go unused because nobody knows they exist. That is a real cost: reviewers spend their day in the Files changed tab reaching for the mouse to do things the keyboard already handles. Every shortcut in this piece is verified against &lt;a href="https://docs.github.com/en/get-started/accessibility/keyboard-shortcuts" rel="noopener noreferrer"&gt;GitHub’s keyboard shortcuts documentation&lt;/a&gt;; anything we could not verify there is left out. The second half is the honest part: where faster keys stop mattering because the surface itself is the bottleneck.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The short answer:&lt;/strong&gt; Learn a dozen keys and the GitHub review loop gets noticeably faster: &lt;strong&gt;?&lt;/strong&gt; for the cheat sheet, &lt;strong&gt;T&lt;/strong&gt; to filter changed files, &lt;strong&gt;C&lt;/strong&gt; for the commits menu, &lt;strong&gt;I&lt;/strong&gt; to toggle diff comments, and Cmd+Enter family keys for submitting. But shortcuts optimize navigation, not comprehension. Once the PR is large enough that the problem is understanding, not clicking, no key binding rescues the web UI.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Press ? and read the map
&lt;/h2&gt;

&lt;p&gt;The one shortcut that teaches the rest: typing &lt;code&gt;?&lt;/code&gt; on a GitHub page opens a cheat sheet of the shortcuts available on that page. The set is contextual, which is why most people never discover the review-specific keys; they only ever see the sheet on the dashboard, if at all. Open it once on the Files changed tab of a real PR and you will find the review keys documented below. Two site-wide keys worth binding into muscle memory while you are there: &lt;code&gt;S&lt;/code&gt; or &lt;code&gt;/&lt;/code&gt; focuses the search bar, and &lt;code&gt;G&lt;/code&gt; then &lt;code&gt;P&lt;/code&gt; jumps to the repository’s Pull requests tab.&lt;/p&gt;

&lt;p&gt;Outside the diff, in regular code views, three more keys carry their weight. Pressing &lt;code&gt;T&lt;/code&gt; activates the file finder so you can fuzzy-type a path, &lt;code&gt;L&lt;/code&gt; jumps to a line number, and &lt;code&gt;B&lt;/code&gt; opens the blame view, which is often the fastest way to answer the review question “why does this code exist at all” without leaving the browser. They are not review shortcuts strictly speaking, but a review that never needs surrounding context is rare, and these are how you get to that context quickly.&lt;/p&gt;

&lt;h2&gt;
  
  
  The GitHub code review shortcuts that earn their keep
&lt;/h2&gt;

&lt;p&gt;On the Files changed tab, the documented set is small but load-bearing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;T&lt;/code&gt; moves your cursor to the Filter changed files field. Type a path fragment, land on the file. This is the single highest-value key in a large diff.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;C&lt;/code&gt; opens the Commits dropdown to filter which commits are shown, which is how you scope the diff to one commit at a time instead of the whole branch.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;I&lt;/code&gt; shows or hides comments on diffs, useful when threads have buried the code they are arguing about.&lt;/li&gt;
&lt;li&gt;Click a line number, then Shift+Click another, to comment on a multi-line range instead of a single line.&lt;/li&gt;
&lt;li&gt;In a comment box, &lt;code&gt;Cmd+G&lt;/code&gt; (Ctrl+G) inserts a suggestion block, and &lt;code&gt;R&lt;/code&gt; quotes the text you have selected in your reply.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Batch the review, then submit once
&lt;/h2&gt;

&lt;p&gt;The submit keys mirror GitHub’s two commenting modes: &lt;code&gt;Cmd+Enter&lt;/code&gt; submits a standalone comment, while &lt;code&gt;Cmd+Shift+Enter&lt;/code&gt; on the Files changed tab submits a review comment, the kind that stays pending until you finish the review. Pending-first is the right default. Your comments remain private and editable until you submit, so a misreading you catch on file nine can be fixed on file two before the author ever sees it, and the author receives one notification instead of eleven. None of this is about typing speed; it is about turnaround. Google’s engineering guidance treats &lt;a href="https://google.github.io/eng-practices/review/reviewer/speed.html" rel="noopener noreferrer"&gt;review speed&lt;/a&gt; as a first-order health metric, and a reviewer who can enter, navigate, and batch a review without leaving the keyboard genuinely turns reviews around faster. Rounding out the set, the conversation page has its own documented keys: &lt;code&gt;Q&lt;/code&gt; opens the reviewer request menu, &lt;code&gt;A&lt;/code&gt; sets an assignee, and &lt;code&gt;L&lt;/code&gt; applies a label, so even the triage work around a review can stay on the keyboard.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where shortcuts hit the ceiling
&lt;/h2&gt;

&lt;p&gt;Here is the honest limit. Shortcuts compress the mechanical part of review: getting to the diff, getting to the file, getting the comment in. They do nothing for the expensive part, which is building a model of the change. When a PR spans forty files, the web UI offers you the same flat, alphabetical file list no matter how fast you filter it. There is no way to read by architectural layer, no persistent sense of place across visits, and jump-to-definition simply does not exist in a diff view. We have made &lt;a href="https://pyor.review/blog/stop-reviewing-code-on-github" rel="noopener noreferrer"&gt;the long version of this argument&lt;/a&gt; before, and the practical comparison of &lt;a href="https://pyor.review/blog/review-prs-locally-vs-browser" rel="noopener noreferrer"&gt;reviewing locally versus in the browser&lt;/a&gt; covers what an IDE gives you that no shortcut can.&lt;/p&gt;

&lt;h2&gt;
  
  
  The right way to think about it
&lt;/h2&gt;

&lt;p&gt;Learn the keys anyway. They are free, they compound over hundreds of reviews, and the cheat sheet takes two minutes to read. Just be clear about which problem they solve. If your reviews are slow because of clicking, shortcuts fix that this afternoon. If they are slow because &lt;a href="https://pyor.review/blog/how-to-review-large-pull-requests" rel="noopener noreferrer"&gt;the PRs are too large to hold in your head&lt;/a&gt;, the fix is structural: smaller units, commit-scoped reading, or a surface built for comprehension. Disclosure: that last category is why we build &lt;a href="https://pyor.review/" rel="noopener noreferrer"&gt;Pyor&lt;/a&gt;, which organizes the diff so the reading order makes sense rather than making you navigate an alphabetical list faster. Keys make a good surface quicker. They cannot make a flat one deep.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F47w0c3uw9fduunsfx7wn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F47w0c3uw9fduunsfx7wn.png" alt="Focus: Code mode: the pull request header, tabs and file rail are folded away and the split diff fills the window, with a thin bar at the top showing the hidden file count, search and an Exit Focus button with its shortcut." width="800" height="524"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Focus: Code, one shortcut away: the chrome folds and the diff fills the window, with the shortcut printed on the exit button.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently asked questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  How do I see all keyboard shortcuts on GitHub?
&lt;/h3&gt;

&lt;p&gt;Type ? on almost any GitHub page and a cheat sheet appears showing the shortcuts available for that specific page. The set changes by context: the Files changed tab has review shortcuts that do not exist elsewhere, and code views have their own navigation keys. The full list lives in the GitHub docs under accessibility keyboard shortcuts.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is the fastest way to jump to a file in a pull request?
&lt;/h3&gt;

&lt;p&gt;On the Files changed tab, press T to move your cursor to the Filter changed files field, then type part of the path. In regular code views (outside a PR diff), T activates the file finder instead. Combined with the file tree on wider screens, this beats scrolling through a long diff by a wide margin.&lt;/p&gt;

&lt;h3&gt;
  
  
  Should review comments be submitted one at a time or batched?
&lt;/h3&gt;

&lt;p&gt;Batched. Start a review with your first comment so subsequent ones stay pending and private until you submit, then send everything as one review. The author gets one coherent notification instead of a drip of emails, and you can revise earlier comments after later files change your understanding of the change.&lt;/p&gt;

</description>
      <category>github</category>
      <category>codereview</category>
      <category>programming</category>
      <category>productivity</category>
    </item>
    <item>
      <title>GitHub Stacked Pull Requests: What Native Stacks Change</title>
      <dc:creator>Othman Shareef</dc:creator>
      <pubDate>Mon, 28 Sep 2026 08:00:00 +0000</pubDate>
      <link>https://dev.to/pyor/github-stacked-pull-requests-what-native-stacks-change-3h7c</link>
      <guid>https://dev.to/pyor/github-stacked-pull-requests-what-native-stacks-change-3h7c</guid>
      <description>&lt;p&gt;GitHub stacked pull requests went from community workaround to native feature in April 2026. A stack, in GitHub’s &lt;a href="https://docs.github.com/en/pull-requests/get-started/about-stacked-prs" rel="noopener noreferrer"&gt;own definition&lt;/a&gt;, is “a series of pull requests in the same repository where each PR targets the branch of the PR below it, forming an ordered chain that ultimately lands on your main branch.” Teams have faked this for years with careful branch targeting and third party tools. Now the platform tracks the chain itself. This piece covers what shipped, what it changes, and how to actually review a stack.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The short answer:&lt;/strong&gt; GitHub now natively supports stacked pull requests: chains of dependent PRs with a stack map for navigation, cascading rebases when lower layers merge, and branch protection enforced against the final target branch. It is the platform admitting what reviewers always knew: large PRs do not get reviewed well. The feature is in public preview, and the hard part it cannot automate is the discipline of cutting work into layers.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What GitHub stacked pull requests actually are
&lt;/h2&gt;

&lt;p&gt;Each PR in a stack targets the branch of the PR beneath it instead of &lt;code&gt;main&lt;/code&gt;. The bottom PR targets main; everything above it targets its neighbor. GitHub’s UI shows a stack map so reviewers can see where a given PR sits in the chain and move between layers. When you merge, per the docs, “the remaining PRs in the stack are automatically rebased so the lowest unmerged PR targets the updated base branch,” which kills the manual retargeting ritual that made hand-rolled stacks miserable. Two details matter more than they look: branch protection rules are enforced against the final target branch, not just the direct base, and CI runs for every PR in the stack as if it were targeting the final branch. The &lt;code&gt;gh stack&lt;/code&gt; CLI extension automates creating and restacking, but GitHub is explicit that it is optional; stacks can be managed through the UI or API.&lt;/p&gt;

&lt;h2&gt;
  
  
  GitHub said the quiet part out loud
&lt;/h2&gt;

&lt;p&gt;The most interesting artifact of the launch is the admission that came with it. As &lt;a href="https://www.infoworld.com/article/4158575/github-adds-stacked-prs-to-speed-complex-code-reviews.html" rel="noopener noreferrer"&gt;InfoWorld reported&lt;/a&gt;, GitHub’s framing was blunt: “Large pull requests are hard to review, slow to merge, and prone to conflicts. Reviewers lose context, feedback quality drops.” That is the platform that hosts most of the world’s code review conceding &lt;a href="https://pyor.review/blog/why-are-pull-requests-so-hard-to-review" rel="noopener noreferrer"&gt;what reviewers have said for years&lt;/a&gt;. The vendor answer used to be “write smaller PRs,” which is correct and useless, because real features do not arrive in 200 line increments. Stacks are the first native acknowledgment that the unit of work and the unit of review are different things, and that the tooling should bridge them.&lt;/p&gt;

&lt;h2&gt;
  
  
  The new calculus for Graphite and friends
&lt;/h2&gt;

&lt;p&gt;An entire tool category existed to paper over this gap: Graphite, spr, stack-pr, and a dozen scripts named some variant of &lt;code&gt;restack.sh&lt;/code&gt;. Their core value was mechanical: keep dependent branches rebased, retarget PRs when a layer merges, give reviewers a map. Native stacks absorb exactly that layer. What remains for third parties is everything above the mechanics: review queues, team analytics, polish, and workflows that span repositories. If you pay for a stacking tool today, the question is which of those you actually use. We keep a broader comparison in our &lt;a href="https://pyor.review/blog/github-pr-review-alternatives" rel="noopener noreferrer"&gt;review tooling roundup&lt;/a&gt;, but the honest summary is that the free floor just rose, and paid tools now have to justify themselves on the parts GitHub did not build. Expect the survivors to retreat upmarket toward team workflow and analytics; the pure restacking utilities have the most to lose.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to review a stack without wasting the structure
&lt;/h2&gt;

&lt;p&gt;A stack only helps if reviewers use the layers. The pattern that works:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Review bottom up.&lt;/strong&gt; The lowest PR is the foundation everything above it assumes. Approving layer three while layer one is still contested just queues up rework.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Demand one idea per layer.&lt;/strong&gt; A stack of three grab-bags is worse than one big PR, because now the mess has ceremony. Each layer should be a single reviewable claim: the refactor, then the new API, then the callers. This is the &lt;a href="https://pyor.review/blog/atomic-commits-reviewable-prs" rel="noopener noreferrer"&gt;atomic commit discipline&lt;/a&gt; promoted to PR granularity.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep layers inside the size where review still works.&lt;/strong&gt; The evidence on &lt;a href="https://pyor.review/blog/how-big-should-a-pull-request-be" rel="noopener noreferrer"&gt;effective PR size&lt;/a&gt; did not change because stacking shipped; stacks are how you honor it on multi-thousand-line features.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Comment on the layer that owns the problem.&lt;/strong&gt; If a flaw in layer one surfaces while reading layer four, raise it on layer one so the fix cascades cleanly.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you review outside github.com, the layers travel with you: &lt;a href="https://pyor.review/" rel="noopener noreferrer"&gt;Pyor&lt;/a&gt; now surfaces the same stack, a navigator in the PR header and a per-layer status panel in the merge box, so you can see where a PR sits, jump between layers, and know which one has to land first while you read. It reads the stack GitHub tracks; it does not create stacks or run a merge queue.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fk25xxyzn8a1psebiqgnd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fk25xxyzn8a1psebiqgnd.png" alt="A merge box for the middle layer of a three-layer GitHub stack: the stack list shows all three pull requests with their status, the current layer marked as viewing, and a note that merging this layer also merges the one below it." width="800" height="524"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;The merge box on the middle layer of a three-layer stack: every layer with its status, and a note that merging this one also merges the layer below.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Honest limits
&lt;/h2&gt;

&lt;p&gt;First, maturity: the feature reached public preview for all repositories on 30 July 2026, but GitHub still labels it “subject to change,” and merge queue support was rolling out in the weeks after launch rather than on day one. Second, the cascading rebase automates the mechanical rebases, but conflicts between layers are still yours to resolve; automation moves the work, it does not delete it. Third, and most important: stacking is a discipline before it is a feature. The tooling cannot decide where the seams in your change are. An author who cannot split a feature into coherent layers will produce incoherent stacks, and analysts covering the launch flagged exactly this organizational cost. The teams that get value will be the ones that already think in reviewable units and finally have a platform that does not fight them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently asked questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What are GitHub stacked pull requests?
&lt;/h3&gt;

&lt;p&gt;A stack is a series of pull requests in the same repository where each PR targets the branch of the PR below it, forming a chain that ultimately lands on your main branch. GitHub added native support in April 2026: a stack map in the PR UI, cascading rebases when lower layers merge, and an optional gh stack CLI extension.&lt;/p&gt;

&lt;h3&gt;
  
  
  Are GitHub stacked pull requests available to everyone?
&lt;/h3&gt;

&lt;p&gt;Yes, as a public preview. GitHub opened stacked pull requests to every repository on 30 July 2026, with no waitlist, and the gh-stack CLI extension installs with one command. It is still labelled preview and subject to change, and merge queue support was rolling out progressively after launch, so check your repository before you build a workflow on it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Do native stacks replace tools like Graphite?
&lt;/h3&gt;

&lt;p&gt;For the core mechanics, largely yes: dependent PRs, automatic retargeting after merges, and stack navigation now live in GitHub itself. Third party tools still differentiate on polish, cross-repo workflows, and team features built up over years. If you adopted a stacking tool only to escape rebase pain, the native feature is worth evaluating first.&lt;/p&gt;

</description>
      <category>github</category>
      <category>codereview</category>
      <category>programming</category>
      <category>productivity</category>
    </item>
    <item>
      <title>GitHub Merge Queue, Explained: Why Green PRs Break Main</title>
      <dc:creator>Othman Shareef</dc:creator>
      <pubDate>Sat, 26 Sep 2026 08:00:00 +0000</pubDate>
      <link>https://dev.to/pyor/github-merge-queue-explained-why-green-prs-break-main-2bk1</link>
      <guid>https://dev.to/pyor/github-merge-queue-explained-why-green-prs-break-main-2bk1</guid>
      <description>&lt;p&gt;Two pull requests can both be green and still break main the moment they both land. Each one was tested against the main that existed when its CI last ran, not against each other. The GitHub merge queue exists for exactly this failure: it revalidates every pull request against the latest version of the target branch, plus the queued changes ahead of it, before anything merges. This piece explains how the queue works, verified against the GitHub docs, when the extra machinery pays for itself, and what it pointedly does not fix.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The short answer:&lt;/strong&gt; A merge queue tests each pull request in combination with the latest target branch and the pull requests queued ahead of it, using temporary branches, and merges only what passes. Failing entries are removed and the queue rebuilds without them. You need one when merge volume and CI duration make results stale before merging. It guarantees an integrated, green main. It says nothing about whether anyone reviewed the code well.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Green plus green equals broken
&lt;/h2&gt;

&lt;p&gt;The failure is not a textual merge conflict; Git catches those. It is the semantic conflict: one PR renames a helper while another adds a call to the old name, one tightens a validation while another starts sending the newly invalid input. Both pass CI, because both were tested against a main that contained neither. The traditional fix is to update your branch and rerun checks before merging, and on a quiet repository that works fine. On a busy one it becomes a treadmill: by the time your rerun finishes, someone else merged, your result is stale again, and the fastest clicker wins. The docs name this dynamic directly: without a queue, authors must update their branch and wait for status checks to finish before trying to merge.&lt;/p&gt;

&lt;h2&gt;
  
  
  How the GitHub merge queue works
&lt;/h2&gt;

&lt;p&gt;Per &lt;a href="https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/configuring-pull-request-merges/managing-a-merge-queue" rel="noopener noreferrer"&gt;the GitHub docs on merge queues&lt;/a&gt;, the flow runs like this. Once a pull request passes its required checks, anyone with write access can add it to the queue. The queue then verifies that the changes pass all required status checks when applied to the latest version of the target branch &lt;em&gt;and&lt;/em&gt; to any pull requests already queued ahead. It does this by creating temporary branches with a special prefix, each containing the target branch plus the queued changes in order, so a group of pending pull requests is effectively tested as the future main it would produce. Merges then happen in queue order, and main only ever receives combinations that passed together. Two setup details decide whether any of this functions: the branch protection rule must enable Require merge queue, and your CI has to run on the &lt;code&gt;merge_group&lt;/code&gt; event, because without that trigger the queued validation runs no checks at all.&lt;/p&gt;

&lt;h2&gt;
  
  
  Failures, ejection, and jumping the queue
&lt;/h2&gt;

&lt;p&gt;When a queued pull request fails checks, the docs are unambiguous: it is removed from the queue, and the temporary branches are recreated without it so the entries behind it can proceed against a clean base. The ejected author fixes and re-queues; nobody else is blocked. This is the property that makes batching safe, since one bad change cannot poison the merges around it for longer than a rebuild. There is also an escape hatch: you can move a pull request to the top of the queue. Use it the way the docs imply you should, sparingly, because a jump causes a full rebuild of every in-progress entry, which means one impatient hotfix can throw away the CI time of the entire queue behind it. A queue that gets jumped daily is a signal that either CI is too slow or too much is being treated as urgent.&lt;/p&gt;

&lt;h2&gt;
  
  
  When you actually need one
&lt;/h2&gt;

&lt;p&gt;The docs scope the feature honestly: it is particularly useful on branches where a relatively high number of pull requests merge each day from many different users. Two variables govern the decision. Merge volume, because each merge is a chance to invalidate everyone else’s CI results, and CI duration, because slow pipelines widen the staleness window. Ten merges a day against a five-minute pipeline is annoying but survivable by hand; ten merges against a forty-minute pipeline is four hundred minutes of potential staleness, and the treadmill wins. Below that threshold, a merge queue is process for the sake of process. Above it, the queue converts a coordination problem that scaled with team size into infrastructure, which is exactly what infrastructure is for.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a merge queue does not fix
&lt;/h2&gt;

&lt;p&gt;A merge queue guarantees the combination compiles and the tests pass. It has no opinion on whether the tests assert anything, whether the design is sound, or whether a human ever read the diff; a rubber-stamped approval rides the queue exactly as smoothly as a careful one. If your main is green but your defect rate is not moving, the bottleneck is the review itself, and the evidence on &lt;a href="https://pyor.review/blog/do-code-reviews-find-bugs" rel="noopener noreferrer"&gt;what reviews actually catch&lt;/a&gt; says that depends on humans reading with attention, which no merge automation supplies. Disclosure: this is the layer we work on at &lt;a href="https://pyor.review/" rel="noopener noreferrer"&gt;Pyor&lt;/a&gt;, on the view that the useful job for tooling there is organizing the diff so the human read gets faster, not summarizing it away. Queue for integration, review for correctness; neither covers for the other.&lt;/p&gt;

&lt;h2&gt;
  
  
  Merge queues and trunk-based flow
&lt;/h2&gt;

&lt;p&gt;Merge queues and trunk-based development solve the same problem at different layers. Trunk-based flow asks for small, frequent merges to a single branch, which is precisely the traffic pattern that makes stale CI results common, so teams that adopt the flow tend to hit the queue-shaped problem sooner. The queue, in turn, removes the biggest tax on high-frequency integration: the manual update-and-wait loop. They compound. Small pull requests keep queue batches cheap to rebuild when something is ejected, and the queue keeps small pull requests flowing without a human traffic controller. If you are heading toward trunk-based work, our piece on &lt;a href="https://pyor.review/blog/trunk-based-development-code-review" rel="noopener noreferrer"&gt;code review in trunk-based development&lt;/a&gt; covers the review side of that transition; the merge queue is the infrastructure that makes the merging side boring, which is the highest compliment infrastructure can earn.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently asked questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What problem does a GitHub merge queue solve?
&lt;/h3&gt;

&lt;p&gt;Stale CI results. Two pull requests can each pass checks against an older main and still break it when both merge, because neither was tested against the other. The queue validates every pull request against the latest target branch plus the queued changes ahead of it, so what lands has been tested in the combination that will actually exist.&lt;/p&gt;

&lt;h3&gt;
  
  
  Do small teams need a merge queue?
&lt;/h3&gt;

&lt;p&gt;Usually not. The queue earns its complexity when a busy branch takes many merges a day from many people, and CI takes long enough that results go stale before merging. A small team with fast CI can simply update branches before merging. Turn the queue on when update, wait, retry becomes a daily tax rather than an occasional chore.&lt;/p&gt;

</description>
      <category>github</category>
      <category>codereview</category>
      <category>programming</category>
      <category>productivity</category>
    </item>
    <item>
      <title>How to Require Code Review on GitHub (Branch Protection)</title>
      <dc:creator>Othman Shareef</dc:creator>
      <pubDate>Thu, 24 Sep 2026 08:00:00 +0000</pubDate>
      <link>https://dev.to/pyor/how-to-require-code-review-on-github-branch-protection-5250</link>
      <guid>https://dev.to/pyor/how-to-require-code-review-on-github-branch-protection-5250</guid>
      <description>&lt;p&gt;If review depends on everyone remembering to ask for it, it will be skipped exactly when it matters most. The fix is mechanical: require code review on GitHub with branch protection, so a pull request physically cannot merge without an approving read. The settings take five minutes; the policy design is the real work. This piece covers what the protections actually do, verified against the GitHub docs, and how to pick the configuration that guarantees a human read without turning every merge into a queue at the post office.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The short answer:&lt;/strong&gt; Branch protection can require a set number of approving reviews, dismiss approvals as stale when new commits change the diff, require sign-off from code owners, and demand that the latest push be approved by someone other than its pusher. By default, admins and roles with bypass permission are exempt unless you extend enforcement to them. Aim for the minimum friction that guarantees an honest read: usually one approval, stale dismissal on, and code owners where the risk lives.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What it means to require code review on GitHub
&lt;/h2&gt;

&lt;p&gt;The core setting is plain. Per &lt;a href="https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-protected-branches/about-protected-branches" rel="noopener noreferrer"&gt;the GitHub docs on protected branches&lt;/a&gt;, you can require that all pull requests receive a specific number of approving reviews before anyone merges them into the protected branch, and once required reviews are on, collaborators can only push changes to that branch through a pull request approved by the required number of reviewers with write access. That second half is the part teams forget: the rule does not just gate the merge button, it closes the direct-push side door. What the setting buys you is a guarantee that every change to main passed through a surface where review could happen. What it cannot buy you is the review itself, a gap we will come back to.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stale dismissal, code owners, and the last-push rule
&lt;/h2&gt;

&lt;p&gt;Three companion settings decide whether the required approval means anything. First, stale dismissal: with it enabled, the docs state that approving reviews are dismissed when commits are pushed that affect the diff, so an approval describes the code that merges, not a version from last Tuesday. Without it, approve-then-rewrite is a one-person bypass. Turning it on is close to free on a team that keeps pull requests small, and expensive exactly where the expense is telling you something. Second, code owner reviews: any pull request that affects code with a code owner must be approved by that owner before merging, which is how you attach mandatory expertise to specific paths instead of raising the approval count everywhere; our &lt;a href="https://pyor.review/blog/codeowners-best-practices" rel="noopener noreferrer"&gt;CODEOWNERS guide&lt;/a&gt; covers keeping that file honest. Third, the quieter one: you can require that the most recent reviewable push be approved by someone other than the person who pushed it, which blocks the author-pushes-then-self-approves loophole on shared branches.&lt;/p&gt;

&lt;h2&gt;
  
  
  The bypass honesty problem
&lt;/h2&gt;

&lt;p&gt;Here is the clause that decides whether your policy is real: by default, branch protection restrictions do not apply to repository admins or to roles granted the bypass permission. You can extend enforcement to administrators, and for most teams you should, but some bypass capacity usually survives for genuine emergencies. The problem is not that bypass exists; it is that bypass is quiet. A protection rule that senior people silently skip is worse than no rule, because everyone else can see the merged-without-review commits while the policy page still claims reviews are required. The workable norm is to treat every bypass as a public event: announced in the team channel when it happens, with a reason, and followed by a retroactive review. If that feels heavyweight, notice what that means: bypassing was becoming routine.&lt;/p&gt;

&lt;h2&gt;
  
  
  Design for the minimum friction that guarantees a read
&lt;/h2&gt;

&lt;p&gt;The failure mode when configuring all this is symmetrical. Too loose, and the settings are decoration; too strict, and engineers spend their afternoons collecting approvals like signatures on a permission slip. The design principle we keep coming back to is the one from &lt;a href="https://pyor.review/blog/review-by-blast-radius" rel="noopener noreferrer"&gt;review by blast radius&lt;/a&gt;: match rigor to what breaks if the change is wrong. In branch protection terms, that usually means one required approval with stale dismissal as the repository-wide floor, and code owners layered on the paths where mistakes are expensive (auth, payments, data migrations, public API), effectively requiring a second, specific reviewer only where it pays. Blanket two-approval rules feel rigorous but mostly convert the second reviewer into a formality; Microsoft’s &lt;a href="https://www.microsoft.com/en-us/research/publication/expectations-outcomes-and-challenges-of-modern-code-review/" rel="noopener noreferrer"&gt;research on modern code review&lt;/a&gt; found the value of review lives in understanding and improvement, not in stacking sign-offs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Protection is a floor, not a culture
&lt;/h2&gt;

&lt;p&gt;Branch protection guarantees a click. It cannot guarantee that anyone read the diff, and a team that rubber-stamps will rubber-stamp straight through a required approval, one keystroke slower than before. The settings also age: paths gain new risk, code owners leave, and a configuration nobody revisits quietly drifts away from the risks it was meant to cover, so put a yearly review of the rules themselves on the calendar. None of that is an argument against the settings; floors matter, and the direct-push door should be closed on any codebase with users. It is an argument for keeping the two layers straight. The settings make skipping review impossible; only norms make review real, and those norms (approvals that say what was read, nits labeled, leaders who queue like everyone else) are built in the open, the way we describe in &lt;a href="https://pyor.review/blog/code-review-culture" rel="noopener noreferrer"&gt;code review culture&lt;/a&gt;. Configure the floor in an afternoon. Expect the culture to take a year. Both are worth it, and neither substitutes for the other.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently asked questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  How many approvals should a protected branch require?
&lt;/h3&gt;

&lt;p&gt;One, for most teams. GitHub lets you require a specific number of approving reviews, but each extra required approval adds latency to every merge while adding little scrutiny beyond the first honest read. Reserve two approvals for genuinely risky surfaces, such as payment paths or auth, and enforce that through code owners rather than a blanket rule.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does dismissing stale approvals slow teams down?
&lt;/h3&gt;

&lt;p&gt;It adds a re-approval round trip whenever new commits change the diff, and that is the point: the approval should describe the code being merged, not an earlier version of it. Keep the cost low by keeping pull requests small and re-requesting review promptly. Teams that find this unbearable usually have a PR size problem, not a settings problem.&lt;/p&gt;

</description>
      <category>github</category>
      <category>codereview</category>
      <category>programming</category>
      <category>productivity</category>
    </item>
    <item>
      <title>GitHub Suggested Changes: When and How to Use Them</title>
      <dc:creator>Othman Shareef</dc:creator>
      <pubDate>Tue, 22 Sep 2026 08:00:00 +0000</pubDate>
      <link>https://dev.to/pyor/github-suggested-changes-when-and-how-to-use-them-2le6</link>
      <guid>https://dev.to/pyor/github-suggested-changes-when-and-how-to-use-them-2le6</guid>
      <description>&lt;p&gt;GitHub suggested changes are the closest thing code review has to a fast path: the reviewer proposes the exact replacement lines, and the author lands them with one click. Used well, they turn a comment round trip that costs hours into a commit that costs seconds. Used badly, they become a way to rewrite someone else’s pull request from the review pane. This piece covers how the feature actually behaves, verified against the GitHub docs, when a suggestion beats a prose comment, and the etiquette that keeps suggestions welcome.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The short answer:&lt;/strong&gt; A suggestion is an editable block inside a review comment that proposes replacement text for the commented lines. The author can apply one as a single commit, or batch several and land them together as one commit, with each suggester recorded as a co-author. Use suggestions for small, concrete, in-file fixes where the code is the clearest way to say it. For anything cross-file, structural, or genuinely debatable, write a comment instead.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  How GitHub suggested changes work
&lt;/h2&gt;

&lt;p&gt;On the reviewer side, the mechanics live inside an ordinary review comment. Per &lt;a href="https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/reviewing-changes-in-pull-requests/commenting-on-a-pull-request" rel="noopener noreferrer"&gt;the GitHub docs on PR comments&lt;/a&gt;, you comment on a line or range of lines, click the suggestion button in the comment toolbar, and edit the text within the suggestion block that appears. Whatever the block contains is your proposed replacement for the commented lines. On the author side, &lt;a href="https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/reviewing-changes-in-pull-requests/incorporating-feedback-in-your-pull-request" rel="noopener noreferrer"&gt;the docs on incorporating feedback&lt;/a&gt; describe the apply flow: clicking Commit suggestion creates a single commit on the pull request’s compare branch. Applying requires write access to the repository; on a pull request from a fork, maintainers can apply suggestions if the author allowed edits from maintainers. Everyone whose suggestion lands in a commit is recorded as a co-author, so attribution survives the shortcut.&lt;/p&gt;

&lt;h2&gt;
  
  
  When a suggestion beats a prose comment
&lt;/h2&gt;

&lt;p&gt;The test is whether the code is shorter than the explanation. A typo, a better variable name, a missing await, an off-by-one in a range check, a doc sentence that should read differently: writing “consider renaming this to reflect that it returns a list” forces the author to reverse-engineer your intent, apply it, and hope they landed where you pointed. The suggestion is the intent, byte for byte, and it removes an entire round trip along with the ambiguity. This makes suggestions the natural container for nits in particular: as we argued in &lt;a href="https://pyor.review/blog/code-review-nitpicks" rel="noopener noreferrer"&gt;our piece on nitpicks&lt;/a&gt;, small feedback should cost the author almost nothing to accept, and one click is almost nothing. If your nit is not worth typing out as a suggestion, that is useful information about whether it was worth raising at all.&lt;/p&gt;

&lt;h2&gt;
  
  
  Batch suggestions into one commit
&lt;/h2&gt;

&lt;p&gt;Applying eight suggestions one by one produces eight commits, eight CI runs, and a branch history that reads like a woodpecker. The docs describe the fix: instead of Commit suggestion, click Add suggestion to batch on each change you want, then click Commit suggestions once to land the whole set as a single commit, with every suggester co-authored. Authors should default to batching whenever a review contains more than a couple of suggestions. One caveat worth knowing before you click: an applied suggestion is a real commit, so it triggers CI like any push, and in repositories configured to dismiss stale approvals when the diff changes, it can invalidate the very approval the reviewer just gave. The polite reviewer flow is to approve and let the author apply, rather than leaving suggestions dangling behind a request for changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where suggestions stop working
&lt;/h2&gt;

&lt;p&gt;A suggestion can only say one thing: replace the lines this comment is anchored to with these lines. Everything outside that shape falls back to prose. Changes that span multiple files cannot be expressed, which rules out the most common real refactor (rename the function here, update its call sites there). Moved code has the same problem: a suggestion can delete lines in place or add lines in place, but it cannot say “this block belongs in the other module.” And because suggestions anchor to the diff a reviewer can comment on, code far from the visible changes is, as of this writing, out of reach. None of this is a flaw to work around with heroics. When a proposed fix outgrows the suggestion box, that is the feature telling you the change deserves a conversation, or its own pull request, not a bigger box.&lt;/p&gt;

&lt;h2&gt;
  
  
  Etiquette: an offer, not an order
&lt;/h2&gt;

&lt;p&gt;A suggestion carries more force than a comment, because accepting it takes one click while declining it takes a written justification. That asymmetry is why etiquette matters. A suggestion is an offer: the author may apply it, adapt it, or decline it, and a declined suggestion is a completed interaction, not an opening bid. Reviewers who pave a pull request with dozens of style suggestions are not reviewing; they are ghost-writing, and they teach authors to stop thinking about the feedback and start clicking through it. Keep suggestions for changes you would be content to see merged exactly as written, mark the optional ones as optional, and put anything you actually require behind an explicit request instead. The distinction is worth stating in the review itself, because the author cannot read your mind about which suggestions are load-bearing; we cover that boundary in &lt;a href="https://pyor.review/blog/when-to-request-changes" rel="noopener noreferrer"&gt;when to request changes&lt;/a&gt; and the phrasing side in &lt;a href="https://pyor.review/blog/review-comments-that-land" rel="noopener noreferrer"&gt;review comments that land&lt;/a&gt;. The feature works best when it stays what it is: the smallest possible gift.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently asked questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  How do I apply a suggested change on GitHub?
&lt;/h3&gt;

&lt;p&gt;Open the review comment that contains the suggestion and click Commit suggestion, which creates a single commit on the pull request branch. To combine several, click Add suggestion to batch on each one, then Commit suggestions to land them all as one commit. You need write access to the repository, or maintainer edit rights on a fork based pull request.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can GitHub suggestions span multiple files?
&lt;/h3&gt;

&lt;p&gt;No, as of this writing. A suggestion replaces the lines a review comment is anchored to, inside a single file in the diff. Changes that span files, move code between locations, or touch lines outside the diff cannot be expressed as suggestions. For those, describe the change in a comment, or offer to push a commit yourself with the author agreeing first.&lt;/p&gt;

</description>
      <category>github</category>
      <category>codereview</category>
      <category>programming</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Solo Developer Code Review: A System That Works</title>
      <dc:creator>Othman Shareef</dc:creator>
      <pubDate>Sun, 20 Sep 2026 08:00:00 +0000</pubDate>
      <link>https://dev.to/pyor/solo-developer-code-review-a-system-that-works-7ei</link>
      <guid>https://dev.to/pyor/solo-developer-code-review-a-system-that-works-7ei</guid>
      <description>&lt;p&gt;Nobody reviews your pull requests, because there is nobody. Solo developer code review sounds like an oxymoron, but the underlying goal (a second, skeptical read of every change before it ships) does not actually require a second person. It requires distance from the code, and distance can be manufactured three ways: with time, with automation, and with discipline borrowed from teams. Here is the system worth setting up for a one-person codebase that has real users, in rough order of value per hour invested.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The short answer:&lt;/strong&gt; Solo developer code review replaces a teammate with three sources of distance: time (read your own diff tomorrow morning, not tonight), automation (an AI first pass that flags what it can and asks questions), and structure (checklists for the failure modes you repeat, atomic commits so each change reads on its own). None of these substitutes for a human on high-stakes changes. Buy the eyes when the cost of a bug exceeds the cost of a review.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Time-shifting is the heart of solo developer code review
&lt;/h2&gt;

&lt;p&gt;The reason you cannot review your own code tonight is that you still remember what you meant, and memory autocompletes over what the code says. Overnight, that mental model decays just enough. The core routine is mechanical: finish the change, do not merge, and read the entire diff the next morning as your first task, before touching the code again. Read it somewhere other than the editor you wrote it in; a different surface breaks the familiarity that lets your eyes slide over lines. Everything we wrote about &lt;a href="https://pyor.review/blog/author-self-review" rel="noopener noreferrer"&gt;author self-review&lt;/a&gt; applies double here, because for you it is not a courtesy pass before a colleague reads, it is the only human read the change will ever get. Write down the intent before you start reading, then check the diff against the note rather than against your memory.&lt;/p&gt;

&lt;h2&gt;
  
  
  AI as the first pass, not the last word
&lt;/h2&gt;

&lt;p&gt;A model reading your diff at 7am has one enormous advantage over you: it was not there yesterday. It has no memory of what you meant, so it reads what you wrote, which is exactly the stance you struggle to reach on your own code. Use it as the pass that runs before your read: surface-level defects, inconsistencies between the change and the rest of the file, and pointed questions about intent. Then keep the caveats loaded. As we covered in &lt;a href="https://pyor.review/blog/ai-code-review-accuracy" rel="noopener noreferrer"&gt;our look at AI review accuracy&lt;/a&gt;, these tools miss real bugs, flag non-issues, and deliver both in the same confident tone, so every finding is a lead to verify, not a verdict. Disclosure: we build &lt;a href="https://pyor.review/" rel="noopener noreferrer"&gt;Pyor&lt;/a&gt;, and our stance is that the AI should organize the diff so your own read gets faster, not hand you a narrated summary you might trust instead of reading.&lt;/p&gt;

&lt;h2&gt;
  
  
  Checklists are the teammate who never forgets
&lt;/h2&gt;

&lt;p&gt;A teammate catches your blind spots because their blind spots are different. A checklist does the same thing more cheaply, if it is yours. The generic lists are a starting point (we published &lt;a href="https://pyor.review/blog/code-review-checklist" rel="noopener noreferrer"&gt;ours&lt;/a&gt;), but the high-value version is personal: the five to ten failure modes you have actually shipped. Forgotten index on the new query. Timezone handling. The error path that swallows the cause. Off-by-one on pagination. Checklists earn their keep on omissions specifically, because a missing thing produces no diff line to catch your eye; only a list makes absence visible. SmartBear’s &lt;a href="https://smartbear.com/learn/code-review/best-practices-for-peer-code-review/" rel="noopener noreferrer"&gt;peer review best practices&lt;/a&gt; make the same point for teams, and it holds harder for a team of one. Append to the list every time production teaches you something. That is the whole maintenance burden.&lt;/p&gt;

&lt;h2&gt;
  
  
  Atomic commits make your own diff readable
&lt;/h2&gt;

&lt;p&gt;Tomorrow-morning-you is a reviewer, and reviewers are wrecked by 900-line mixed diffs no matter who wrote them. The discipline that saves teams saves you too: one logical change per commit, so the next-morning read happens commit by commit, each judged on its own terms. Google’s guidance on &lt;a href="https://google.github.io/eng-practices/review/developer/small-cls.html" rel="noopener noreferrer"&gt;small changes&lt;/a&gt; is written for authors with reviewers, but every argument in it is really about the reader, and solo, the reader is you. We laid out the mechanics in &lt;a href="https://pyor.review/blog/atomic-commits-reviewable-prs" rel="noopener noreferrer"&gt;atomic commits&lt;/a&gt;: separate the rename from the behavior change, the refactor from the feature, the formatter from everything. Solo work makes it tempting to skip this because nobody will see the mess. Somebody will. You, at 7am, trying to find the one dangerous line in a commit called “stuff”.&lt;/p&gt;

&lt;h2&gt;
  
  
  When to buy a second pair of eyes
&lt;/h2&gt;

&lt;p&gt;The system above covers the routine ninety-five percent. The remaining five percent is where solo review honestly fails, and the fix is to pay for eyes rather than pretend. The trigger list is short: authentication and session handling, payments, destructive data migrations, anything cryptographic, and public API contracts you cannot easily walk back. For those, options scale with budget: a few hours of a contractor who specializes in the area, a review swap with another solo developer (you read their risky change, they read yours), or, for open source, asking a domain expert directly with a small, well-framed diff. The rule of thumb does not need refinement: when the realistic cost of a bug exceeds the cost of a review, the review is cheap. Everything else in this system exists so that you only have to pay it rarely. And when you do pay, prepare the change the way you would for a demanding colleague: a small diff, a written summary of intent, and the specific question you want answered. Paid eyes are expensive; aim them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently asked questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  How do you review your own code as a solo developer?
&lt;/h3&gt;

&lt;p&gt;Separate writing from reviewing with time. Finish the change, stop, then read the full diff the next morning before merging, ideally in a different tool than the editor you wrote it in. Add a written checklist for the failure modes you personally repeat, and keep commits atomic so each one can be judged on its own. The routine matters more than any single technique.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can AI replace a human reviewer for solo developers?
&lt;/h3&gt;

&lt;p&gt;It replaces the first pass, not the judgment. AI reviewers are good at surface defects, inconsistencies, and awkward questions about intent, and they never get tired. They also miss context, flag noise, and sound equally confident either way. Treat AI findings as leads to verify during your own read, and buy a human review for changes where being wrong is expensive.&lt;/p&gt;

</description>
      <category>github</category>
      <category>codereview</category>
      <category>programming</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Code Review Culture That Survives Deadlines</title>
      <dc:creator>Othman Shareef</dc:creator>
      <pubDate>Fri, 18 Sep 2026 08:00:00 +0000</pubDate>
      <link>https://dev.to/pyor/code-review-culture-that-survives-deadlines-377a</link>
      <guid>https://dev.to/pyor/code-review-culture-that-survives-deadlines-377a</guid>
      <description>&lt;p&gt;Every team has two review processes: the one written in the onboarding doc and the one that actually runs the week before a release. Code review culture is the gap between them. With slack in the schedule, almost any process looks healthy: approvals arrive within a day, comments are thoughtful, follow-up pushes get re-read. The revealing question is what happens in the bad week, because that is the process your codebase actually lives under. This piece is about what breaks first under deadline pressure, which norms hold, and why leadership behavior sets the ceiling on all of it.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The short answer:&lt;/strong&gt; Code review culture is revealed under pressure, not defined in documents. The first casualties are honest reading and the re-review; rubber stamps keep the ritual while dropping the substance. The norms that survive are the cheap, explicit ones: review SLAs, approvals that state what was actually read, nits labeled as nits, and comment style that carries no blame. Leaders set the ceiling by what they visibly let slide.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What breaks first under pressure
&lt;/h2&gt;

&lt;p&gt;The failure is rarely that reviews stop. The ritual survives; the substance leaves. Approvals speed up, not because reviewers got faster but because they stopped reading, and the PR record fills with LGTM stamps that certify nothing. We wrote about that failure mode in &lt;a href="https://pyor.review/blog/lgtm-culture-code-review-theatre" rel="noopener noreferrer"&gt;review theatre&lt;/a&gt;: it is worse than no review, because it launders unreviewed code as reviewed. The second casualty is the re-review. An author pushes fixes after a round of comments, and under deadline the reviewer approves the notification instead of the diff, so the riskiest commits in the PR (the hasty ones, written to satisfy feedback) are exactly the ones nobody reads. Nobody decides to lower the bar. Each person makes one locally reasonable trade, and the sum is a review process that no longer exists.&lt;/p&gt;

&lt;h2&gt;
  
  
  An SLA keeps speed from becoming the excuse
&lt;/h2&gt;

&lt;p&gt;Slow review is the pressure that creates rubber-stamping in the first place: when approvals take days, deadlines turn reviewers into bottleneck-clearers. Google’s engineering practices are blunt about the fix, telling reviewers to respond within &lt;a href="https://google.github.io/eng-practices/review/reviewer/speed.html" rel="noopener noreferrer"&gt;one business day&lt;/a&gt; at the slowest. An explicit SLA does two things under pressure. It makes review latency a visible, shared number instead of a private grievance, and it removes the main justification for skipping review entirely, because waiting is affordable when the review reliably arrives tomorrow morning. We covered how to pick and enforce one in &lt;a href="https://pyor.review/blog/code-review-slas" rel="noopener noreferrer"&gt;our piece on review SLAs&lt;/a&gt;. The cultural point is simpler: teams keep norms they can measure and drop the ones that live in vibes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Say what you actually reviewed
&lt;/h2&gt;

&lt;p&gt;The cheapest honesty upgrade available is an approval that states its own scope. “Reviewed the migration and the handler logic, skimmed the tests, did not run it locally” takes fifteen seconds to type and changes what the green checkmark means. It lets a reviewer do a partial review honestly instead of pretending to a full one, and it tells the author exactly which risks remain theirs to carry. This norm matters most under deadline pressure, because partial reviews are what pressure produces anyway. The real choice is never between full reviews and partial ones; it is between labeled partial reviews and silent ones, and only the labeled kind leaves the next engineer an accurate record of what was checked.&lt;/p&gt;

&lt;h2&gt;
  
  
  Label the nits, drop the blame
&lt;/h2&gt;

&lt;p&gt;Two comment norms carry disproportionate cultural weight. First, label the nits. A nit prefix tells the author this is optional polish rather than a merge blocker, which keeps small feedback flowing without turning every round into a negotiation; we took a longer position in &lt;a href="https://pyor.review/blog/code-review-nitpicks" rel="noopener noreferrer"&gt;our nitpicks piece&lt;/a&gt;, and the short version is that unlabeled nits train authors to dread review. Second, keep blame out of the phrasing. &lt;a href="https://conventionalcomments.org/" rel="noopener noreferrer"&gt;Conventional Comments&lt;/a&gt; exists precisely to make severity and intent explicit: “suggestion (non-blocking)” defuses what “why would you do this” inflames. Comments that critique the code rather than the author are what make honest disagreement survivable, and &lt;a href="https://pyor.review/blog/review-comments-that-land" rel="noopener noreferrer"&gt;comments that land&lt;/a&gt; covers how to write them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Leadership sets the ceiling
&lt;/h2&gt;

&lt;p&gt;Culture is downstream of what the most senior people do when it costs them something. A staff engineer who ships a large change with “urgent, merging on green” teaches more in one afternoon than the wiki teaches in a year. The inverse is just as visible: a tech lead who requests changes on a feature the director is watching, or who says “I have not reviewed this properly, give me until tomorrow” in a release week, licenses everyone below them to be honest too. Review norms are permission structures. People do not follow the documented standard; they follow the worst behavior that visibly goes unpunished at the level above them. If you lead a team, your review habits in the bad week are the actual policy, whatever the doc says.&lt;/p&gt;

&lt;h2&gt;
  
  
  Code review culture is what gets reviewed when nobody is watching
&lt;/h2&gt;

&lt;p&gt;A definition worth keeping: code review culture is whatever gets genuinely reviewed when nobody is watching. Not the checklist, not the branch protection settings, but whether the second reviewer actually reads the diff at 6pm on release day. Tooling cannot enforce that; settings guarantee a click, not a read. What a team can do is make the honest path cheap (SLAs, scope statements, labeled nits), make the dishonest path visible (approvals that say nothing, re-reviews that arrive suspiciously fast), and have leaders model the expensive behavior in public. Teams that do all three still cut corners under pressure. They just cut them on purpose, out loud, and they go back afterward to pay the debt down, which is the whole difference between a culture and a document.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently asked questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What is code review culture?
&lt;/h3&gt;

&lt;p&gt;Code review culture is the set of habits a team actually follows when reviewing code, as opposed to the process it documents. It shows up in how fast reviews happen, how honest approvals are, how nits are handled, and whether re-reviews happen after changes. The reliable test is behavior under deadline pressure, when shortcuts get tempting and norms either hold or collapse.&lt;/p&gt;

&lt;h3&gt;
  
  
  How do you keep review quality under deadline pressure?
&lt;/h3&gt;

&lt;p&gt;Make the norms cheap and explicit before the crunch: a review SLA measured in hours, approvals that state what was actually read, nits labeled so they can be deferred honestly, and comments that critique code rather than people. Under pressure, teams drop whatever is vague. Norms that are specific, observable, and modeled by senior engineers tend to survive.&lt;/p&gt;

</description>
      <category>github</category>
      <category>codereview</category>
      <category>programming</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Onboarding Code Review: New Hires Review First</title>
      <dc:creator>Othman Shareef</dc:creator>
      <pubDate>Wed, 16 Sep 2026 08:00:00 +0000</pubDate>
      <link>https://dev.to/pyor/onboarding-code-review-new-hires-review-first-1hc7</link>
      <guid>https://dev.to/pyor/onboarding-code-review-new-hires-review-first-1hc7</guid>
      <description>&lt;p&gt;Most onboarding plans hand the new hire a wiki that is eighteen months stale and a starter ticket in the safest corner of the codebase. There is a faster vehicle sitting in plain sight: the review queue. Onboarding code review, meaning the deliberate use of code review as the primary onboarding mechanism, flips the usual order. New hires read and review changes before they write any, because the review stream is the one place where the living codebase, the real standards, and the actual humans all show up in the same window.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The short answer:&lt;/strong&gt; Code review is the highest-bandwidth onboarding channel a team has. Assign new hires as extra reviewers from week one, with no gate authority, so they tour the codebase where it is actually changing. Point them at the review archive as the true documentation of team standards. Pair them with a review buddy who calibrates their comments and their confidence. The research is unambiguous that knowledge transfer is a primary outcome of review; onboarding is that outcome, concentrated.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Onboarding code review: read before you write
&lt;/h2&gt;

&lt;p&gt;A codebase at rest tells you what the code is; a diff tells you how the team thinks. Reviews carry the argument: why this abstraction, why not that shortcut, what this team considers worth a comment. This is not a folk theory. Microsoft’s &lt;a href="https://www.microsoft.com/en-us/research/publication/expectations-outcomes-and-challenges-of-modern-code-review/" rel="noopener noreferrer"&gt;Bacchelli and Bird study&lt;/a&gt; found knowledge transfer and team awareness among the strongest actual outcomes of modern code review, ahead of the defect counts everyone expects, and Google’s &lt;a href="https://research.google/pubs/modern-code-review-a-case-study-at-google/" rel="noopener noreferrer"&gt;Critique case study&lt;/a&gt; lists education as an explicit reason review is universal there. If review transfers knowledge between veterans, it transfers far more to someone starting from zero. The onboarding question is not whether to use that channel but how early, and the answer is: before the first commit.&lt;/p&gt;

&lt;h2&gt;
  
  
  Week one: assign them as an extra reviewer
&lt;/h2&gt;

&lt;p&gt;Add the new hire as an additional reviewer on a few PRs a day, chosen for variety rather than simplicity: one core-path change, one test-heavy change, one config or infra change. The assignment logic your team already uses (we covered the options in &lt;a href="https://pyor.review/blog/assigning-code-reviewers" rel="noopener noreferrer"&gt;assigning code reviewers&lt;/a&gt;) just gains one rule: newcomers ride along on changes that touch the systems they will own. Their instructions fit in three lines: read the whole diff, ask at least one question, flag anything you could not follow. Our &lt;a href="https://pyor.review/blog/first-code-review-guide" rel="noopener noreferrer"&gt;first code review guide&lt;/a&gt; covers the mechanics of doing that well. The point is exposure with a purpose. Two weeks of this beats two months of wandering the repo, because the review queue is a guided tour of exactly the code that is alive. Keep the volume modest, two or three PRs a day, and protect time for it on the calendar; a ride-along that gets squeezed out by setup tasks in week one silently teaches the newcomer that review is optional here.&lt;/p&gt;

&lt;h2&gt;
  
  
  No gate authority, and say so out loud
&lt;/h2&gt;

&lt;p&gt;The extra-reviewer role only works if it is explicitly ungated. The newcomer’s approval does not merge anything; a second, experienced reviewer still owns the decision. This removes the fear that makes new reviewers either rubber-stamp or go silent, and it frees them to ask the questions veterans have stopped asking. Those questions are not a cost. A new hire who cannot follow a change has found a comprehension problem, and comprehension problems are precisely what a future maintainer will hit. “I could not tell why this function needs the lock” is a legitimate review finding regardless of tenure. Teams that treat newcomer confusion as signal get two artifacts from the same review: a better change, and a map of where their codebase is hardest to enter.&lt;/p&gt;

&lt;h2&gt;
  
  
  The review archive is your real style guide
&lt;/h2&gt;

&lt;p&gt;Every team has a written style guide and a real one, and the real one lives in review threads. Which shortcuts get called out, which get waved through, how disagreements resolve, what a respected senior actually says when someone hard-codes a timeout: that is the culture, recorded. Point new hires at the archive deliberately. Have them read the last month of review threads on the service they will own, the way you would hand over design docs. It teaches standards, and it teaches register: what &lt;a href="https://pyor.review/blog/review-comments-that-land" rel="noopener noreferrer"&gt;comments land&lt;/a&gt; on this team and what phrasing falls flat. An hour in the archive answers questions the wiki never will, including the ones the newcomer would not have known to ask. If your review threads are too thin to teach anything, that is a finding about your review culture, not about the onboarding plan, and it is worth fixing for the veterans as much as for the new hire.&lt;/p&gt;

&lt;h2&gt;
  
  
  Give them a review buddy
&lt;/h2&gt;

&lt;p&gt;Reviewing into a void is how newcomers learn bad habits or lose their nerve, so pair each new hire with a review buddy for the first month or two. The buddy reviews the same PRs, reads the newcomer’s draft comments before they post in the early weeks, and debriefs afterward: that question was great, this nitpick was not worth the thread, here is why the approval was premature. It is calibration, the same mechanism that makes pairing effective, applied to judgment instead of code. The buddy also closes the loop in the other direction, telling the team how the codebase reads to fresh eyes. Wind the arrangement down when the newcomer’s reviews stop needing edits. By then, onboarding has quietly finished, and what remains is just a reviewer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently asked questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Should new hires review code before they write it?
&lt;/h3&gt;

&lt;p&gt;Yes, from week one, as an extra reviewer without merge-blocking authority. Reviewing exposes them to the parts of the codebase that are actively changing, the team’s real standards, and the people behind the work, faster than reading static code ever does. Their outsider questions are also genuinely useful: they surface everything the team has stopped seeing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is it fair to ask newcomers to review code they barely understand?
&lt;/h3&gt;

&lt;p&gt;It is, if the role is framed honestly. They are not the gate; a second, experienced reviewer still owns the approval. The newcomer’s job is to read, ask questions, and flag anything confusing. Confusion is signal, not failure: if the new person cannot follow a change, the next maintainer probably cannot either.&lt;/p&gt;

&lt;h3&gt;
  
  
  How long should a new hire have a review buddy?
&lt;/h3&gt;

&lt;p&gt;Four to eight weeks covers most cases. The buddy reviews alongside them, reads their draft comments before they post early on, and debriefs on tone and calibration. Wind it down when the newcomer’s comments stop needing edits and their approvals start matching what the buddy would have decided independently.&lt;/p&gt;

</description>
      <category>github</category>
      <category>codereview</category>
      <category>programming</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Pull Request Template Best Practices That Survive</title>
      <dc:creator>Othman Shareef</dc:creator>
      <pubDate>Mon, 14 Sep 2026 08:00:00 +0000</pubDate>
      <link>https://dev.to/pyor/pull-request-template-best-practices-that-survive-3p3e</link>
      <guid>https://dev.to/pyor/pull-request-template-best-practices-that-survive-3p3e</guid>
      <description>&lt;p&gt;Most pull request templates are written for an imaginary audit and abandoned by everyone else. Twelve checkboxes, a testing matrix nobody fills honestly, a screenshot section for a backend repo. Pull request template best practices start from a different question: what does the reviewer need to do a good job in the next fifteen minutes? A template is not a compliance form. It is the cheapest tool you have for moving context from the head of the author, who has it, to the reviewer, who does not.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The short answer:&lt;/strong&gt; A pull request template earns its existence one way: reviewers read what it produces. Keep four sections, what changed, why, how to review it, and what the risk is. Cap the whole thing under eight prompts, because every prompt past the reviewer’s patience converts the template into boilerplate. And in the AI era, add two lines that did not matter five years ago: where this code came from, and what the author actually asked for.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Pull request template best practices: write for the reviewer
&lt;/h2&gt;

&lt;p&gt;The audience for a template is not the author, not the auditor, and not the process document. It is the reviewer, fifteen minutes from now, deciding where to spend limited attention. We have written about &lt;a href="https://pyor.review/blog/why-are-pull-requests-so-hard-to-review" rel="noopener noreferrer"&gt;why pull requests are hard to review&lt;/a&gt;, and the answer is mostly missing context: the diff shows what changed but not why, not what was considered and rejected, not which files carry the risk. A good template is a context pump aimed at exactly those gaps. Every prompt should be answerable in a sentence or two and useful to the person reading the diff. If a prompt exists to prove diligence rather than to transfer context, it is decoration, and reviewers learn to scroll past decoration fast.&lt;/p&gt;

&lt;h2&gt;
  
  
  Four sections that earn their place
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;What.&lt;/strong&gt; Two or three sentences describing the change at the level of behavior, not files. The diff already lists the files.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Why.&lt;/strong&gt; The problem, the ticket, the constraint that forced this approach over the obvious alternative. This is the section future archaeologists will thank you for.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;How to review this.&lt;/strong&gt; Where to start reading, which file is the heart of the change, what deserves scrutiny versus what is mechanical rename noise. SmartBear’s &lt;a href="https://smartbear.com/learn/code-review/best-practices-for-peer-code-review/" rel="noopener noreferrer"&gt;peer review guidance&lt;/a&gt; found that authors who annotate their changes before review trigger better reviews, partly because annotating forces a self-review pass. This section is that annotation, structured.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Risk.&lt;/strong&gt; What could break, how you would notice, and how to roll back. One honest sentence here outperforms ten ticked checkboxes.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Template rot: twelve checkboxes nobody ticks honestly
&lt;/h2&gt;

&lt;p&gt;Templates die by accretion. Every incident adds a checkbox, no retro ever removes one, and within a year the template is a wall of prompts that authors fill with “N/A” and reviewers skip wholesale. Worse than useless, rotten templates train both sides that the description block is noise, so even genuine context gets ignored. You can watch the rot progress in three stages: first authors answer every prompt, then they answer the first two and paste dashes into the rest, then a well-meaning contributor deletes the template block entirely and nobody objects, because it stopped carrying information months ago. A ticked box that was never honestly checked is the same pathology as the rubber-stamp approval we described in &lt;a href="https://pyor.review/blog/lgtm-culture-code-review-theatre" rel="noopener noreferrer"&gt;LGTM culture&lt;/a&gt;: process theatre that consumes credibility without producing safety. The maintenance rule is simple and almost nobody follows it: when you add a prompt, remove one, and once a quarter, delete any prompt whose answers you cannot remember a reviewer ever using.&lt;/p&gt;

&lt;h2&gt;
  
  
  AI-era additions: provenance and intent
&lt;/h2&gt;

&lt;p&gt;Two prompts have become worth their cost since code generation went mainstream. First, provenance: which parts of this change were AI-generated, and what level of self-review have they had? Not as a purity test, but because reviewers calibrate differently for generated code, and they should get to. Second, intent: what did you ask for, and what did the tool decide on its own? The reasoning behind a generated change lives in a prompt session that will not exist next week; the PR description is the last cheap place to write it down, which is the argument we made at length in &lt;a href="https://pyor.review/blog/capturing-intent-ai-changes" rel="noopener noreferrer"&gt;capturing intent for AI changes&lt;/a&gt;. Both prompts together are three lines of template. Skip the temptation to add an AI checklist section; two honest sentences beat a compliance block here too.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep it under eight prompts
&lt;/h2&gt;

&lt;p&gt;The binding constraint on templates is not thoroughness, it is the author’s patience multiplied by the reviewer’s. Under roughly eight prompts, authors answer thoughtfully; past that, they paste boilerplate, and one boilerplate answer teaches reviewers to distrust all of them. Four core sections, two AI-era lines, and maybe one repo-specific prompt (migrations, screenshots, whatever your codebase genuinely bleeds on) is the whole budget. If a category of information matters only sometimes, do not add a prompt that is “N/A” the rest of the time; trust authors to add sections when relevant. The same budget logic applies per section: a heading with a one-line hint beats a heading with three sub-questions, because authors answer the hint and ignore the sub-questions anyway. Templates are also repo-scoped, so resist the org-wide mega template; the sections a mobile app needs are dead weight in a terraform repo. Finally, treat any template change like code: propose it, try it for a month, and keep it only if reviews measurably went better. The best template is the shortest one your reviewers actually read.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently asked questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What should a pull request template include?
&lt;/h3&gt;

&lt;p&gt;Four sections earn their place: what changed, why it changed, how to review it (where to start, what to scrutinize), and risk (what could break, how you would know, how to roll back). Everything else is optional. The test for any additional prompt is whether a reviewer will read the answer, not whether the answer sounds responsible.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why do PR templates stop working?
&lt;/h3&gt;

&lt;p&gt;Template rot. Prompts accumulate faster than they are removed, authors start pasting boilerplate or ticking boxes unread, and reviewers learn to skip the whole block. Once the template becomes noise, it actively hurts: real context drowns in ritual text. The fix is pruning to the few prompts that demonstrably change how reviews go, and deleting the rest.&lt;/p&gt;

&lt;h3&gt;
  
  
  Should PR templates ask about AI-generated code?
&lt;/h3&gt;

&lt;p&gt;Yes, briefly. One prompt for provenance (which parts were generated, and with what level of self-review) and one for intent (what was asked for, what the tool chose). The reasoning behind generated code lives only in a session that will be gone tomorrow, so the template is the last cheap place to capture it.&lt;/p&gt;

</description>
      <category>github</category>
      <category>codereview</category>
      <category>programming</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Draft Pull Requests: Cheap Feedback, Used Right</title>
      <dc:creator>Othman Shareef</dc:creator>
      <pubDate>Sat, 12 Sep 2026 08:00:00 +0000</pubDate>
      <link>https://dev.to/pyor/draft-pull-requests-cheap-feedback-used-right-2fmn</link>
      <guid>https://dev.to/pyor/draft-pull-requests-cheap-feedback-used-right-2fmn</guid>
      <description>&lt;p&gt;The most expensive feedback in software is the kind that arrives after the polish. You spend two days refining an approach, open the PR, and the first comment questions the approach itself. A draft pull request exists to make that conversation happen two days earlier, while the change is still cheap to redirect. GitHub’s &lt;a href="https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/changing-the-stage-of-a-pull-request" rel="noopener noreferrer"&gt;own docs&lt;/a&gt; define the mechanics simply: a draft cannot be merged until you mark it ready for review, and marking it ready is what triggers review requests to code owners. Everything interesting about drafts follows from those two properties.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The short answer:&lt;/strong&gt; A draft pull request is a machine-enforced signal: this change is visible and CI-checked but not yet asking for formal review. Use it to get design direction before you invest in polish, and say explicitly what feedback you want. Drafts beat WIP titles because the merge block and the reviewer-notification timing are enforced by the platform, not by convention. And in the agent era, drafts are the natural holding state for generated code awaiting human self-review.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What a draft pull request is for
&lt;/h2&gt;

&lt;p&gt;Drafts decouple “the code is pushed” from “the code is ready for your judgment.” That gap is where cheap feedback lives. Open a draft when the skeleton of an approach exists: the new module boundary, the schema change, the API shape, with half the error handling missing and the tests stubbed. A colleague can look at the direction in five minutes and either nod or save you days. This is the same economics that make &lt;a href="https://pyor.review/blog/how-big-should-a-pull-request-be" rel="noopener noreferrer"&gt;small PRs&lt;/a&gt; work: feedback value decays with the amount of work already stacked on top of the decision being questioned. A draft moves the review of the riskiest decision, the design, to the moment it is cheapest to change. The state costs you nothing to enter: open the PR as a draft from the start, or convert an existing one back to draft when review reveals the design needs another lap. CI keeps running either way, so the feedback you get is grounded in a building change, not a sketch.&lt;/p&gt;

&lt;h2&gt;
  
  
  Etiquette: say what feedback you are asking for
&lt;/h2&gt;

&lt;p&gt;The failure mode of drafts is ambiguity. A reviewer opens one and does not know whether to comment on the approach, the naming, the missing tests, or nothing at all, so they either waste effort nitpicking scaffolding or skip it entirely. The fix costs one sentence at the top of the description: “Looking for feedback on the retry strategy in client.ts; ignore the tests, they are placeholders.” Scope the ask, name the files that matter, and state what is deliberately unfinished. Reviewers of drafts are volunteering time ahead of the formal request, and the same courtesy that makes &lt;a href="https://pyor.review/blog/why-are-pull-requests-so-hard-to-review" rel="noopener noreferrer"&gt;any PR reviewable&lt;/a&gt;, context up front, applies double when the code itself is admittedly rough.&lt;/p&gt;

&lt;h2&gt;
  
  
  Drafts vs the WIP title convention
&lt;/h2&gt;

&lt;p&gt;Before drafts existed, teams typed WIP into titles and hoped. The difference is enforcement. A WIP title is a string; nothing stops a distracted teammate from merging it, and deleting the prefix notifies no one. A draft is a state: GitHub blocks the merge until you mark it ready, and the ready-for-review transition requests reviews from code owners at that moment, which makes the start of formal review an explicit, logged event rather than a title edit someone may or may not notice. You can also convert a ready PR back to draft when review surfaced something structural, and people already subscribed stay subscribed. If your team still uses WIP titles, the migration is one click per PR and a habit change, and the habit pays for itself the first time a half-finished change does not get merged on a Friday.&lt;/p&gt;

&lt;h2&gt;
  
  
  Drafts and agents: the holding pen for generated code
&lt;/h2&gt;

&lt;p&gt;Agent-written code gives drafts a second career. The person who ran the agent is the author of record, but they have not read the diff yet, and until they have, the change should not be asking for anyone else’s time. Landing agent output as a draft makes that state explicit: CI runs, the diff is visible, nothing can merge, and no code owner has been paged. The human then does &lt;a href="https://pyor.review/blog/author-self-review" rel="noopener noreferrer"&gt;author self-review&lt;/a&gt; inside the draft: read every line, delete the weirdness, and write down what was asked for and what the agent chose, the intent capture we argued for in &lt;a href="https://pyor.review/blog/capturing-intent-ai-changes" rel="noopener noreferrer"&gt;capturing intent for AI changes&lt;/a&gt;. Only after that does the draft become ready. The conversion is the accountability boundary: it is the author asserting that a human has read this code and stands behind the request for review.&lt;/p&gt;

&lt;h2&gt;
  
  
  When to convert to ready
&lt;/h2&gt;

&lt;p&gt;Convert when three things are true. The open questions you wanted early feedback on are resolved or explicitly deferred with a note. The change is complete enough that a reviewer’s comments will target real code, not scaffolding you already planned to replace. And you have done a self-review pass, because the ready button is a request for someone else’s scarce attention. Convert too early and you burn reviewer goodwill on churn; every force-push that rewrites half the diff after review started is a tax on the reviewer. Convert too late and you have used the draft as a private branch with extra steps, forfeiting the early feedback that justified it. The draft state is cheap to hold and cheap to leave. What is expensive is pretending a change is ready when the honest answer is “almost.” If you live in the terminal, &lt;code&gt;gh pr ready&lt;/code&gt; makes the transition a one-liner, which removes the last excuse for leaving a finished change marked as a draft overnight.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently asked questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Can a draft pull request be merged?
&lt;/h3&gt;

&lt;p&gt;No. GitHub blocks merging until the pull request is marked ready for review, which is the whole value of the state: it is machine-enforced, not a social convention. CI still runs, comments still work, and you can convert back to draft at any time; people already subscribed to the PR stay subscribed when you do.&lt;/p&gt;

&lt;h3&gt;
  
  
  What happens when I mark a draft as ready for review?
&lt;/h3&gt;

&lt;p&gt;GitHub requests reviews from any code owners at that moment, so the ready-for-review transition is the real start of the review clock. That is exactly why drafts are useful: you can push code, run CI, and gather informal feedback without paging the owners of every touched path before the change is worth their time.&lt;/p&gt;

&lt;h3&gt;
  
  
  Should AI agent output always start as a draft PR?
&lt;/h3&gt;

&lt;p&gt;It is a sensible default. A draft holds generated code in a visible, CI-checked, unmergeable state until the person who ran the agent has read the diff, written down intent, and decided the change is worth a human reviewer. Converting to ready then becomes an explicit claim: I have reviewed this myself and I am asking for your time.&lt;/p&gt;

</description>
      <category>github</category>
      <category>codereview</category>
      <category>programming</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Trunk Based Development Code Review: Keep It Fast</title>
      <dc:creator>Othman Shareef</dc:creator>
      <pubDate>Thu, 10 Sep 2026 08:00:00 +0000</pubDate>
      <link>https://dev.to/pyor/trunk-based-development-code-review-keep-it-fast-3190</link>
      <guid>https://dev.to/pyor/trunk-based-development-code-review-keep-it-fast-3190</guid>
      <description>&lt;p&gt;Trunk-based development has a reputation for being anti-review, and it is unearned. The &lt;a href="https://trunkbaseddevelopment.com/" rel="noopener noreferrer"&gt;canonical reference&lt;/a&gt; describes a model where developers collaborate in a single branch called trunk, resist long-lived development branches, and commit multiple times a day. But it also explicitly blesses short-lived feature branches for exactly two purposes: code review and build checking. Trunk based development code review is not an afterthought bolted onto the model. It is the model, with one non-negotiable property: it has to be fast.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The short answer:&lt;/strong&gt; Trunk-based development does not remove code review; it constrains it until review stops being a bottleneck. Branches live hours or a day or two, so diffs stay small. Diffs stay small, so reviews finish fast. Reviews finish fast, so branches can stay short. Feature flags decouple deploying code from releasing features, which removes the last excuse for long branches. Break any link in that loop, usually review speed, and the whole model quietly reverts to feature branches.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What the model actually prescribes
&lt;/h2&gt;

&lt;p&gt;Strip away the folklore and the prescription is concrete. Everyone integrates with trunk at least daily, which is the bar Continuous Integration has always technically demanded. Branches, where they exist at all, live for hours or a couple of days, exist so that a reviewer and a build server can check the change before it lands, and are never the place where releases get cut. A build server verifies every commit to trunk, because with everyone integrating constantly, a broken trunk blocks the whole team. None of that abolishes review. It relocates review to the only place it can keep up: small changes, checked quickly, merged the same day.&lt;/p&gt;

&lt;h2&gt;
  
  
  Small PRs are the review model, built in
&lt;/h2&gt;

&lt;p&gt;Most teams fight an endless battle to keep pull requests reviewable. Trunk-based teams get that property structurally: if every branch integrates within a day or so, a PR physically cannot grow to two thousand lines. The change is one coherent step, which is exactly the shape review works best on. We have made &lt;a href="https://pyor.review/blog/how-big-should-a-pull-request-be" rel="noopener noreferrer"&gt;the case for small PRs&lt;/a&gt; on review quality grounds, and Google makes it on velocity grounds in &lt;a href="https://google.github.io/eng-practices/review/developer/small-cls.html" rel="noopener noreferrer"&gt;their small CLs guide&lt;/a&gt;: small changes are reviewed faster, more thoroughly, and with less wasted rework when the design is wrong. Trunk-based development takes that advice and makes it mandatory instead of aspirational. The branching model is doing the PR-size policing your process documents never managed to do.&lt;/p&gt;

&lt;h2&gt;
  
  
  Trunk based development code review must be fast or the model dies
&lt;/h2&gt;

&lt;p&gt;Here is the failure mode: a developer cuts a short-lived branch Monday morning, opens a small PR by noon, and the review sits until Wednesday. Now they either start the next change on top of unmerged work, recreating the stacked, drifting state the model exists to prevent, or they stall. Multiply by a team and trunk-based development degrades into feature-branch development with extra steps. Review latency is the load-bearing number. Google’s &lt;a href="https://google.github.io/eng-practices/review/reviewer/speed.html" rel="noopener noreferrer"&gt;reviewer speed guide&lt;/a&gt; draws the line at one business day for a first response, and frames slow review as a team-velocity problem, not a reviewer-convenience problem. Trunk-based teams need to treat that as a ceiling, not a target, which is why they benefit most from explicit &lt;a href="https://pyor.review/blog/code-review-slas" rel="noopener noreferrer"&gt;review SLAs&lt;/a&gt;. Tooling matters here too; ours (&lt;a href="https://pyor.review/" rel="noopener noreferrer"&gt;Pyor&lt;/a&gt;) exists largely because a reviewer who gets the diff organized by what matters first can turn a review around in the window trunk-based development actually allows.&lt;/p&gt;

&lt;h2&gt;
  
  
  Feature flags decouple deploy from release
&lt;/h2&gt;

&lt;p&gt;The classic argument for long-lived branches is hiding unfinished features until they are ready. Trunk-based development answers with feature flags: merge the incomplete code, keep it dark behind a flag, and release by flipping configuration rather than by merging a branch. The canonical guidance pairs this with branch by abstraction for longer structural changes, and describes flags as a way of hedging on the order of releases. For review, this is a quiet win. The reviewer sees small, integrated slices of a feature as they land, instead of one giant reveal at the end. The cost is real: flags are code, they accumulate, and unflagged cleanup is a review item of its own. But reviewing ten small flagged PRs beats reviewing one thousand-line merge every time.&lt;/p&gt;

&lt;h2&gt;
  
  
  When review becomes post-commit sampling
&lt;/h2&gt;

&lt;p&gt;Some mature trunk-based teams go further: commit straight to trunk, review after the fact, sometimes only a sample. That is a legitimate end state, not a cheat, but it is a different contract. Pre-merge review is a gate; post-commit review is monitoring, the shift we described in &lt;a href="https://pyor.review/blog/human-in-the-loop-vs-on-the-loop" rel="noopener noreferrer"&gt;human in the loop vs on the loop&lt;/a&gt;. The honest prerequisites: a build server that verifies every commit, deploys that are easy to revert, blast-radius awareness about which paths still get pre-merge eyes, and an actual sampling discipline rather than review quietly stopping. Auth, payments, and data migrations should stay gated even when everything else flows. Post-commit sampling is what review looks like when trust and automation are both high. It is earned, and it is reversible the moment defect rates say so.&lt;/p&gt;

&lt;h2&gt;
  
  
  The loop to protect
&lt;/h2&gt;

&lt;p&gt;Everything above is one feedback loop. Short branches keep diffs small; small diffs keep reviews fast; fast reviews keep branches short; flags keep unfinished work merged instead of hidden. Protect the loop at its weakest link, which in most organizations is reviewer turnaround, and trunk-based development delivers the thing it promises: integration as a habit rather than an event. Let review latency creep, and no amount of branching policy will save you; the long-lived branch will come back wearing a different name.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently asked questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Does trunk-based development eliminate code review?
&lt;/h3&gt;

&lt;p&gt;No. The trunk-based playbook explicitly allows short-lived feature branches whose purpose is code review and CI checking before the code integrates into trunk. What it eliminates is long-lived branches and the giant, week-old PRs they produce. Review survives, but it has to be small and fast enough not to become the new long-lived branch in disguise.&lt;/p&gt;

&lt;h3&gt;
  
  
  How fast does review need to be for trunk-based development?
&lt;/h3&gt;

&lt;p&gt;Faster than your merge cadence. If developers integrate at least daily, a review that waits two days forces either queued work or drift, both of which break the model. Google’s reviewer guide sets one business day as the outer bound for a first response, and trunk-based teams should treat hours, not days, as the working norm.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is post-commit review?
&lt;/h3&gt;

&lt;p&gt;Code merges to trunk first and gets reviewed after, either every change or a sampled subset. It trades the gate for throughput and works only with strong automated checks, easy reverts, and a real sampling discipline. It shifts the reviewer from approving each change up front to monitoring the stream and intervening when something looks wrong.&lt;/p&gt;

</description>
      <category>github</category>
      <category>codereview</category>
      <category>programming</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Pair Programming vs Code Review: Not Rivals</title>
      <dc:creator>Othman Shareef</dc:creator>
      <pubDate>Tue, 08 Sep 2026 08:00:00 +0000</pubDate>
      <link>https://dev.to/pyor/pair-programming-vs-code-review-not-rivals-2p8l</link>
      <guid>https://dev.to/pyor/pair-programming-vs-code-review-not-rivals-2p8l</guid>
      <description>&lt;p&gt;Every few months the pair programming vs code review debate resurfaces, usually framed as a choice: if two people wrote the code together, why review it again? The framing is wrong. Pairing and review both put a second brain on the code, which makes them look interchangeable from a distance, but one is synchronous co-creation and the other is asynchronous verification. They catch different classes of problems at different points in time, and the teams that get the most out of either tend to run both.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The short answer:&lt;/strong&gt; Pair programming and code review are not substitutes. Pairing is synchronous co-creation: it catches design missteps in the moment, before they harden into structure. Review is asynchronous verification: it adds fresh eyes that were absent during writing, plus a durable record of what was decided and why. Some trunk-based teams replace review with pairing, but that trade has real requirements. Most teams should pair on the gnarly work and review everything else.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Pair programming vs code review: different jobs
&lt;/h2&gt;

&lt;p&gt;Pairing is a writing practice. Two people share one problem in real time, and the navigator questions the approach while it is still cheap to change. Review is a reading practice. Someone who was not in the room reconstructs the change from a diff, later, with no shared context to lean on. The research reflects that split: Microsoft’s study of modern code review (&lt;a href="https://www.microsoft.com/en-us/research/publication/expectations-outcomes-and-challenges-of-modern-code-review/" rel="noopener noreferrer"&gt;Bacchelli and Bird&lt;/a&gt;) found that although defect finding is the top stated motivation for review, the observed outcomes lean heavily toward code improvement, knowledge transfer, and team awareness. Those are reader-side benefits. Pairing delivers its value on the writing side, before a diff even exists.&lt;/p&gt;

&lt;h2&gt;
  
  
  What pairing catches: design missteps, early
&lt;/h2&gt;

&lt;p&gt;The cheapest moment to catch a design mistake is before code accumulates on top of it, and that is pairing’s home turf. A navigator asking “why a queue here?” at minute ten saves the three days it would take to unwind that decision in review, where the same objection arrives after the structure has hardened and the author is defending sunk cost. Pairing also transfers tacit knowledge continuously: debugging habits, tooling tricks, the unwritten reasons the codebase looks the way it does. What pairing does not deliver is fresh eyes. By the second hour, both people share the same context and most of the same blind spots. A pair can talk itself into a bad idea just as smoothly as an individual can, sometimes more smoothly, because agreement feels like validation.&lt;/p&gt;

&lt;h2&gt;
  
  
  What review catches: fresh eyes and a record
&lt;/h2&gt;

&lt;p&gt;A reviewer arrives cold, and that is the point. They read the change the way a future maintainer will: without the conversation, without the context, without knowing which alternatives were already rejected. That coldness surfaces what pairing structurally cannot: the missing comment, the name that only makes sense if you were there, the edge case both partners stopped seeing. The evidence on raw defect discovery is more modest than folklore suggests (we have covered &lt;a href="https://pyor.review/blog/do-code-reviews-find-bugs" rel="noopener noreferrer"&gt;what reviews actually find&lt;/a&gt;), but the fresh-eyes read reliably catches comprehension problems, and comprehension problems are what kill codebases slowly. Review also leaves an artifact. The thread of comments, objections, and resolutions is a durable, searchable record of why the code is the way it is. Pairing produces better code and no trace.&lt;/p&gt;

&lt;h2&gt;
  
  
  When pairing replaces review
&lt;/h2&gt;

&lt;p&gt;Some trunk-based teams treat pairing as the review: the code was continuously inspected while it was written, so it merges to trunk without a second gate. That model is real and it can work, but its requirements deserve honesty. First, the pairing has to be genuine: two engaged engineers rotating roles, not a senior typing while a junior watches. Second, rotation across pairs has to be systematic. Without it you trade individual silos for pair-shaped ones, and nobody outside the pair ever reads the code, so the fresh-eyes check never happens at all. Third, there is no written record; if your process commitments require documented review (the same forces that push teams toward &lt;a href="https://pyor.review/blog/code-review-slas" rel="noopener noreferrer"&gt;review SLAs&lt;/a&gt; usually require the paper trail too), pairing alone will not satisfy them. Teams that drop review without meeting those bars are not making a disciplined trade. They are simply not reviewing, which is at least more honest than &lt;a href="https://pyor.review/blog/lgtm-culture-code-review-theatre" rel="noopener noreferrer"&gt;LGTM theatre&lt;/a&gt;, but no safer.&lt;/p&gt;

&lt;h2&gt;
  
  
  The hybrid most teams should run
&lt;/h2&gt;

&lt;p&gt;Pair on the gnarly work: novel design, unfamiliar territory, risky migrations, anything where a wrong early decision is expensive to unwind. Review the rest asynchronously, where the interruption cost of scheduling two people is not justified. When a pair does open a PR, review it lighter, not zero: a fast comprehension pass from outside the pair, not a line-by-line audit of code that already had two authors. Google’s &lt;a href="https://research.google/pubs/modern-code-review-a-case-study-at-google/" rel="noopener noreferrer"&gt;Critique case study&lt;/a&gt; is instructive here: even with a mature review culture and heavy tooling, Google keeps review universal partly for education, because reading each other’s changes is how standards propagate. Pairing spreads knowledge deep between two people; review spreads it wide across the team. You want both directions, and neither practice gives you the other one for free.&lt;/p&gt;

&lt;p&gt;If you need a tiebreaker for a given piece of work, price the two honestly. Pairing costs two synchronized calendars for the duration of the work; review costs latency and a context switch, but the reviewer schedules it themselves. High-uncertainty work justifies the synchronous price because the feedback loop is measured in seconds. Routine work does not, and forcing pairing onto it breeds the checked-out navigator that gives the practice a bad name. Pick per task, not per ideology, and let the two practices cover for each other’s blind spots.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently asked questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Does pair programming replace code review?
&lt;/h3&gt;

&lt;p&gt;Sometimes, but only under real conditions: engaged role rotation within the pair, systematic rotation across pairs so knowledge spreads, and no compliance requirement for a documented review. Some trunk-based teams meet those bars and merge pair-authored code without a second gate. Most teams do not, and for them pairing plus a lightweight review works better than picking one.&lt;/p&gt;

&lt;h3&gt;
  
  
  What does code review catch that pairing misses?
&lt;/h3&gt;

&lt;p&gt;Fresh-eyes problems. A pair shares context and blind spots by the second hour, so neither partner notices what only makes sense if you were there: unclear names, missing context, undocumented assumptions. A cold reviewer reads the change the way a future maintainer will and surfaces those comprehension gaps. Review also leaves a searchable record of decisions, which pairing never produces.&lt;/p&gt;

&lt;h3&gt;
  
  
  Should a pair-authored PR still be reviewed?
&lt;/h3&gt;

&lt;p&gt;Usually yes, but lighter. The design was already challenged in real time by the navigator, so a line-by-line audit mostly duplicates work. A quick pass from someone outside the pair adds the one thing pairing structurally cannot: a reader with no shared context. It also creates the written record your future team will search for.&lt;/p&gt;

</description>
      <category>github</category>
      <category>codereview</category>
      <category>programming</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
