<?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>Forem: Kimmo Brunfeldt</title>
    <description>The latest articles on Forem by Kimmo Brunfeldt (@kimmobrunfeldt).</description>
    <link>https://forem.com/kimmobrunfeldt</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F724207%2F8c38203e-1533-4466-8a79-b8f897d69541.jpeg</url>
      <title>Forem: Kimmo Brunfeldt</title>
      <link>https://forem.com/kimmobrunfeldt</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/kimmobrunfeldt"/>
    <language>en</language>
    <item>
      <title>5 tips for debugging Apollo GraphQL MockedProvider</title>
      <dc:creator>Kimmo Brunfeldt</dc:creator>
      <pubDate>Tue, 07 Jun 2022 13:16:51 +0000</pubDate>
      <link>https://forem.com/kimmobrunfeldt/5-tips-for-debugging-apollo-graphql-mockedprovider-5ajh</link>
      <guid>https://forem.com/kimmobrunfeldt/5-tips-for-debugging-apollo-graphql-mockedprovider-5ajh</guid>
      <description>&lt;p&gt;We’re heavy users of Apollo GraphQL in my team at &lt;a href="https://www.swarmia.com/"&gt;Swarmia&lt;/a&gt;, but sometimes mocking the queries is bothersome. And based on a few GitHub comments, it looks like &lt;a href="https://github.com/apollographql/react-apollo/issues/1711"&gt;we’re&lt;/a&gt; &lt;a href="https://github.com/apollographql/react-apollo/issues/617"&gt;not&lt;/a&gt; &lt;a href="https://github.com/apollographql/apollo-client/issues/7134"&gt;alone&lt;/a&gt;. This blog post is here to help!&lt;/p&gt;

&lt;h2&gt;
  
  
  Why is debugging so difficult?
&lt;/h2&gt;

&lt;p&gt;The problems arise for a few reasons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Mocks lack verbosity.&lt;/strong&gt; It’s not easy to debug why a test case failed if the issue originates from mocks. This post will cover a solution, though, so keep reading.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mocks need incredible precision.&lt;/strong&gt; Even a single-char difference in mocked variables vs. received variables will cause the &lt;em&gt;"No more mocked responses for the query: ...” error.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;There’s no expected vs. actual diffing.&lt;/strong&gt; There’s an &lt;a href="https://github.com/apollographql/react-apollo/pull/2883"&gt;old PR&lt;/a&gt; about this.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;There’s no built-in way to assert if all mocks were used.&lt;/strong&gt; This assertion would be useful to know if a test case ended up doing what was intended. In contrast, for example, &lt;a href="https://github.com/nock/nock"&gt;nock&lt;/a&gt; library allows examining all pending mocks to determine if the code fired all the expected requests.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It’s common to have multiple problems at the same time.&lt;/strong&gt; A multitude of things can go wrong when a test case requires mocking. It can be difficult to understand what the core reason is, and sometimes multiple issues appear in parallel. There are a variety of common issues: async UI updates, issues with Apollo mock, jest working its magic, etc. During those cases, you easily blame Apollo mocks for &lt;em&gt;everything (at least I do!)&lt;/em&gt;, when in reality, there’s an overlapping issue with something else.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s go through five practical tips to make debugging Apollo MockedProvider more enjoyable.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Add logging with MockLink
&lt;/h2&gt;

&lt;p&gt;Queries fail silently during a test case if the &lt;code&gt;MockedProvider&lt;/code&gt; doesn’t find a matching mock for the given request. You may eventually figure it out by console-logging the error returned by the &lt;code&gt;useQuery&lt;/code&gt; hook, but that requires additional digging.&lt;/p&gt;

&lt;p&gt;Fortunately, we can use &lt;a href="https://github.com/apollographql/apollo-client/blob/607e32b11e433e0eef361df4a554910edd61908f/src/testing/core/mocking/mockLink.ts"&gt;MockLink&lt;/a&gt; to add logging. I would link to the API docs but couldn’t find any. We have a &lt;code&gt;VerboseMockedProvider&lt;/code&gt; helper in our test utilities which we use as a replacement for &lt;code&gt;MockedProvider&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ApolloError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ApolloLink&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@apollo/client&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;onError&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@apollo/client/link/error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;MockedProvider&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;MockedProviderProps&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;MockedResponse&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@apollo/client/testing&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;MockLink&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@apollo/react-testing&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Props&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;MockedProviderProps&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;mocks&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;ReadonlyArray&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;MockedResponse&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ReactElement&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;VerboseMockedProvider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;mocks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;otherProps&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mockLink&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;MockLink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mocks&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;errorLoggingLink&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;onError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;graphQLErrors&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;networkError&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;graphQLErrors&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;graphQLErrors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;locations&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
            &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
              &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[GraphQL error]:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
                &lt;span class="s2"&gt;`Message: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;,`&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
                &lt;span class="s2"&gt;`Location: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;locations&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;,`&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
                &lt;span class="s2"&gt;`Path: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;networkError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`[Network error]: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;networkError&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;link&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ApolloLink&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;errorLoggingLink&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;mockLink&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;MockedProvider&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;otherProps&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;addTypename&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;mocks&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;mocks&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;link&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;link&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using the helper, we can easily spot missing mocks from the CI logs or the local shell you’re using to run tests:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[Network error]: Error: No more mocked responses for the query:
query getDogParent {
  parent {
    id
    name
  }
}
Expected variables: {}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When seeing this error, we know that Apollo &lt;code&gt;MockProvider&lt;/code&gt; received &lt;code&gt;query getDogParent&lt;/code&gt; from a component but no matching mock was found. The phrase “Expected variables” can be interpreted in different ways but it means*&lt;em&gt;:&lt;/em&gt;* “The attempted query had these variables: …”. Everything logged here refers to the attempted query, not to the mocks the MockedProvider &lt;em&gt;does&lt;/em&gt; have.&lt;/p&gt;

&lt;p&gt;We found out about this trick from &lt;a href="https://stackoverflow.com/questions/60100062/apollos-mockedprovider-doesnt-warn-clearly-about-missing-mocks"&gt;a StackOverflow question&lt;/a&gt;, kudos to Quentin!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Lr22e4i_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o0jyn8n0ic9ee0el03rb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Lr22e4i_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o0jyn8n0ic9ee0el03rb.png" alt="StackOverflow comments" width="880" height="213"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  2. &lt;strong&gt;Log the &lt;code&gt;error&lt;/code&gt; inside a component&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The previous tip helps to understand if an error with mocks exists in the first place. This second tip helps to dive deeper into the underlying problem.&lt;/p&gt;

&lt;p&gt;Sometimes the additional logging within component context is the final piece of the puzzle. Let’s say you have this code in a component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;setFooMutation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;loading&lt;/span&gt; &lt;span class="p"&gt;}]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useSetFooMutation&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can log the error within a component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;setFooMutation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;loading&lt;/span&gt; &lt;span class="p"&gt;}]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="nx"&gt;useSetFooMutation&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;got error from mutation:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This helps to further narrow the context of the error and allows logging additional details like component props.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Make sure the mocks match the queries made by a component &lt;em&gt;exactly&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;MockLink&lt;/code&gt; is responsible for checking if a request is mocked. The &lt;a href="https://github.com/apollographql/apollo-client/blob/607e32b11e433e0eef361df4a554910edd61908f/src/testing/core/mocking/mockLink.ts#L76-L91"&gt;logic&lt;/a&gt; it uses to detect matching mocks is pretty unforgiving. In practice, everything needs to match exactly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Query:&lt;/strong&gt; does the attempted GraphQL query match the mocked query? Even a single character typo will cause a mismatch.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Variables:&lt;/strong&gt; does the attempted query have the exact same variables? If the attempted query variables contain an array, the items need to be equal and even in the same order in the mock.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The number of mocks:&lt;/strong&gt; does each attempted query have a corresponding mock? Even if you are doing &lt;em&gt;the same query&lt;/em&gt; three times, you need three separate mock definitions in the &lt;code&gt;mocks&lt;/code&gt; array prop. Each attempted request that matches a mock, &lt;a href="https://github.com/apollographql/apollo-client/blob/607e32b11e433e0eef361df4a554910edd61908f/src/testing/core/mocking/mockLink.ts#L106"&gt;consumes&lt;/a&gt; the mocks that are left.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s say we have a mock like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;SetExcludedPullRequestsDocument&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;src/generated/graphql&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;mockSetExcludedPullRequests&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ids&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;SetExcludedPullRequestsDocument&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;variables&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ids&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;setExcludedPullRequests&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ids&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We then mock the query in a test case:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;VerboseMockedProvider&lt;/span&gt;
  &lt;span class="na"&gt;mocks&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;mockSetExcludedPullRequests&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="p"&gt;])]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And eventually the component calls the query with IDs in the wrong order:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;setExcludedPullRequestsMutation&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;variables&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;ids&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Boom. That little slip caused a &lt;em&gt;“No more mocked responses for the query: ...”&lt;/em&gt; error. The same would happen if the component had accidentally used &lt;code&gt;id&lt;/code&gt; variable instead of &lt;code&gt;ids&lt;/code&gt;. The same would also happen if we’d called &lt;code&gt;setExcludedPullRequestsMutation&lt;/code&gt; twice, when having only a single mock definition. The possibilities for mistakes are endless.&lt;/p&gt;

&lt;p&gt;The only solution is to make sure the mocked query has the &lt;em&gt;exact&lt;/em&gt; same query and variables as what the component attempts to send. Sometimes you need a magnifying glass and diffing tools to spot these.&lt;/p&gt;

&lt;p&gt;My preferred debugging approach is to log the mock query object &lt;em&gt;(i.e. what &lt;code&gt;mockSetExcludedPullRequests&lt;/code&gt; returns)&lt;/em&gt;, copy paste it to an editor and manually compare the mock request to the attempted query. If you’re brave enough, there’s a &lt;a href="https://github.com/apollographql/react-apollo/pull/2883#issuecomment-644907868"&gt;fork&lt;/a&gt; of &lt;code&gt;@apollo/react-testing&lt;/code&gt; which implements a jest-like diffing output for query variables.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Make sure you mock the &lt;em&gt;correct&lt;/em&gt; query
&lt;/h2&gt;

&lt;p&gt;This one sounds obvious but when you’re setting the mocks for &lt;code&gt;MockedProvider&lt;/code&gt;, make sure you’re using the correct mocks. The tip originates from a real issue that I once hit which caused a few hours of waste.&lt;/p&gt;

&lt;p&gt;We have shared query mock creator utilities to make them reusable across test suites, for example &lt;code&gt;mockGetSomething()&lt;/code&gt; and &lt;code&gt;mockSetSomething()&lt;/code&gt;. The setter mock creator took zero parameters, so TypeScript didn’t complain about it either.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;VerboseMockedProvider&lt;/span&gt;
  &lt;span class="na"&gt;mocks&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nx"&gt;mockGetSomething&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="c1"&gt;// The next item should've mocked the *setter*,&lt;/span&gt;
    &lt;span class="c1"&gt;// not the getter&lt;/span&gt;
    &lt;span class="nx"&gt;mockGetSomething&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There’s nothing wrong about the creator utility pattern, the lesson here is to be more careful with the mock definitions.&lt;/p&gt;

&lt;p&gt;One way to make sure that you’re calling the correct mock is to add logging to the result creator function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;SetSomethingDocument&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;src/generated/graphql&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;mockSetSomething&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;SetSomethingDocument&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;-- THIS SHOULD BE CALLED &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;setSomething&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you don’t see the log output in stdout, then you know something weird is happening.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Make sure only one &lt;code&gt;MockedProvider&lt;/code&gt; is mounted
&lt;/h2&gt;

&lt;p&gt;If multiple &lt;code&gt;MockedProvider&lt;/code&gt; components are mounted at the same time, the one that is deepest in the React component tree will be used for queries. This is an easy pitfall to step into when abstracting the numerous React context providers into utilities.&lt;/p&gt;

&lt;p&gt;We often use helper components to reuse the set of providers that are required in all test cases. A test suite sometimes uses the same data and mocks for each individual case to avoid repetition. The helper component could look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Providers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;ProviderProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;MemoryRouter&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* Mock requests relevant for the test cases */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;VerboseMockedProvider&lt;/span&gt; &lt;span class="na"&gt;mocks&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;mockGetSomething&lt;/span&gt;&lt;span class="p"&gt;()]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;VerboseMockedProvider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;MemoryRouter&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, the actual test cases don’t need to repeat all the providers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Providers&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;TestComponent&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Providers&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But sometimes, one might accidentally use two or more overlapping provider abstractions. This leads to mounting multiple &lt;code&gt;MockedProvider&lt;/code&gt; components at the same time. This is what a simplified example would look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Providers&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;VerboseMockedProvider&lt;/span&gt; &lt;span class="na"&gt;mocks&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;mockGetAnotherThing&lt;/span&gt;&lt;span class="p"&gt;()]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;TestComponent&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;VerboseMockedProvider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Providers&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When the &lt;code&gt;TestComponent&lt;/code&gt; attempts to call &lt;code&gt;query getSomething&lt;/code&gt;, it will fail to &lt;em&gt;“No more mocked responses…”&lt;/em&gt; error because the inner &lt;code&gt;VerboseMockedProvider&lt;/code&gt; catches all requests before they reach the outer provider defined in &lt;code&gt;Providers&lt;/code&gt; component.&lt;/p&gt;

&lt;p&gt;The simplest solution is to read through the whole React component tree in the test code and make sure there are no overlapping &lt;code&gt;MockedProvider&lt;/code&gt; components. An additional safety layer can be achieved by &lt;a href="https://eslint.org/docs/rules/no-restricted-imports"&gt;disallowing&lt;/a&gt; direct &lt;code&gt;MockedProvider&lt;/code&gt; imports using ESLint.&lt;/p&gt;

&lt;h2&gt;
  
  
  That’s it
&lt;/h2&gt;

&lt;p&gt;If you have any additional tips for Apollo mocking, let us know on &lt;a href="https://twitter.com/SwarmiaHQ"&gt;Twitter&lt;/a&gt;. Hope you found the tips useful!&lt;/p&gt;

</description>
      <category>graphql</category>
      <category>typescript</category>
      <category>programming</category>
      <category>testing</category>
    </item>
    <item>
      <title>16 best practices to make your code reviews better</title>
      <dc:creator>Kimmo Brunfeldt</dc:creator>
      <pubDate>Thu, 04 Nov 2021 10:42:15 +0000</pubDate>
      <link>https://forem.com/kimmobrunfeldt/16-best-practices-to-make-your-code-reviews-better-4m09</link>
      <guid>https://forem.com/kimmobrunfeldt/16-best-practices-to-make-your-code-reviews-better-4m09</guid>
      <description>&lt;p&gt;Code reviews are a widely accepted best practice for software development teams. In this post, we'll cover why the most successful teams use code reviews, how to adopt them in your development process, and what the best practices are.&lt;/p&gt;

&lt;p&gt;The goals of code reviews are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Sharing knowledge:&lt;/strong&gt; The depth of know-how shared depends on the thoroughness of the review, but some amount of information will always be transferred. The knowledge can be general tips about the framework or programming language or invaluable domain-specific information bits.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Spreading ownership:&lt;/strong&gt; Code reviews have a positive impact on mutual code ownership. It's easy to end up in a situation where one developer always deals with a certain part of the codebase because they're most familiar with it. It might be a short-term win but is often a long-term loss. When ownership is shared, teams become more motivated and autonomous.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Unifying development practices:&lt;/strong&gt; Every developer has their own tendencies and ways to implement software. Code reviews help to narrow the gap between individual development styles and make the codebase more unified. Unification happens through high-level discussions about architecture and software design and via micro-level continuous integration checks, such as coding style enforcement.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Quality control:&lt;/strong&gt; Studies have shown that code reviews can help with catching defects, but even more importantly, they surface software design issues while they are still relatively easy to change.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fryd52anj6nbm5x360w2x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fryd52anj6nbm5x360w2x.png" alt="The four whys of code reviews"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Adopting code reviews
&lt;/h2&gt;

&lt;p&gt;It's crucial to set the review process right. At worst, code reviews might feel like a hindrance. At best, code reviews help to sustain a good, stable team performance for many years.&lt;/p&gt;

&lt;p&gt;If your organization is new to code reviews, introducing them will be a big change in the development process. Whenever implementing changes to ways of working, it's a good idea to ensure that everyone agrees on the process and has had the chance to contribute to the decision. This will cause less friction.&lt;/p&gt;

&lt;p&gt;You, as a team or an organization, should agree on the philosophy and motivation behind code reviews before implementing them. You can write down an internal "what's a good code review" document together or refer to existing guides. It's a practical way to make sure everyone is aware of the whys.&lt;/p&gt;

&lt;p&gt;Social relationships can't be ignored when talking about peers giving feedback about each other’s work. There are no silver bullets. It's hard work that requires each individual's contribution. To have the best chance of success, make sure to thoroughly discuss and educate your team about communication practices.&lt;/p&gt;

&lt;h2&gt;
  
  
  Best practices for code reviews
&lt;/h2&gt;

&lt;p&gt;Blog posts about review practices often mention smaller details about branch names, commit message lengths, etc. While those tips are valuable too, this post focuses on more general recommendations.&lt;/p&gt;

&lt;p&gt;There are multiple perspectives to a code review process: the author's, the reviewer's, and the team's point of view. Each party has an equally important role in the process. Some best practices apply only to the author or the reviewer, but many of them are important for everyone in the team.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Let's go through what those practices are.&lt;/strong&gt; We'll focus on GitHub and pull request (PR) oriented review processes, but many of the tips apply in general as well.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Decide on a process
&lt;/h3&gt;

&lt;p&gt;Responsibility will bounce between the author and the reviewer(s). The more explicit the review process, the less likely the ball is dropped by any party.&lt;/p&gt;

&lt;p&gt;For example, our internal PR guidelines look something like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;DRAFT&lt;/code&gt; You can open a PR in a draft state to show progress or request early feedback.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;READY FOR REVIEW&lt;/code&gt; You can also skip the draft state and open a PR directly.

&lt;ul&gt;
&lt;li&gt;The review is done by another team member.&lt;/li&gt;
&lt;li&gt;Usually, there's no need to request a review; Swarmia automatically notifies the team. A manual review request can be useful if you, for example, want to request a design review from a certain designer.&lt;/li&gt;
&lt;li&gt;It's polite to have the PR ready so that you're not about to rebase everything 5 times while the reviewer tries to keep up.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;CHANGES REQUESTED&lt;/code&gt; Fix the requested changes, or discuss whether a fix is needed.

&lt;ul&gt;
&lt;li&gt;Preferably, create new commits after the review.&lt;/li&gt;
&lt;li&gt;You can directly &lt;a href="https://docs.github.com/en/github/collaborating-with-pull-requests/reviewing-changes-in-pull-requests/incorporating-feedback-in-your-pull-request#applying-suggested-changes" rel="noopener noreferrer"&gt;commit suggestions&lt;/a&gt; from the GitHub UI.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;APPROVED&lt;/code&gt; The author is responsible for merging their own PR.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5cxykw12dqjyxbkhd1s8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5cxykw12dqjyxbkhd1s8.png" alt="Sketch of our internal process"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Yours might look different, but as long as the team agrees on the process, all is good.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Focus on the right things
&lt;/h3&gt;

&lt;p&gt;To maintain code review standards across developers, it's a good idea to have guidelines for what to focus on in code reviews. Here's what we recommend focusing on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Functionality&lt;/strong&gt;: Does the code behave as the PR author likely intended? Does the code behave as users would expect?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Software design&lt;/strong&gt;: Is the code well-designed and fitted to the surrounding architecture?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Complexity&lt;/strong&gt;: Would another developer be able to easily understand and use the code?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tests&lt;/strong&gt;: Does the PR have correct and well-designed automated tests?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Naming&lt;/strong&gt;: Are names for variables, functions, etc. descriptive?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Comments&lt;/strong&gt;: Are the comments clear and useful?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Documentation&lt;/strong&gt;: Did the author also update relevant documentation?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Developers shouldn't spend their time reviewing things that can be automatically checked. More on that in &lt;em&gt;"Use continuous integration effectively"&lt;/em&gt; and &lt;em&gt;"Delegate nit-picking to a computer"&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Discuss the high-level approach early
&lt;/h3&gt;

&lt;p&gt;Before jumping into coding a complex feature, it's beneficial to discuss the high-level approach first. Usually, this is done when planning the feature.&lt;/p&gt;

&lt;p&gt;It's not nice for anyone if a PR ends up in a complete rewrite because the approach wasn't discussed beforehand. Rewrites of pull requests do happen every once in a while, but it's a sign that you might want to talk more before the implementation.&lt;/p&gt;

&lt;p&gt;Sometimes a proof-of-concept implementation is needed to ignite the discussion. An effective way to get started is to open a draft PR of the approach and make the architecture decision based on the gained information.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Optimize for the team
&lt;/h3&gt;

&lt;p&gt;This idea is explained well in &lt;a href="https://google.github.io/eng-practices/review/reviewer/speed.html" rel="noopener noreferrer"&gt;Google's Engineering Practices&lt;/a&gt; document:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;We optimize for the speed at which a team of developers can produce a product together, as opposed to optimizing for the speed at which an individual developer can write code.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Speedy reviews increase team performance in multiple ways: iteration becomes faster, developers don't need to do time-costly context switches as often, etc. Make sure the team understands the implications of fast reviews and agrees on a suitable maximum time for responding to a PR. The key is to minimize the response lag between the author and the reviewer, even if the whole review process takes long. For example, it might be invaluable for the author to know that their PR will be reviewed, for example, tomorrow morning.&lt;/p&gt;

&lt;p&gt;That said, developers shouldn't interrupt their focus to do reviews. Instead, they should prioritize them whenever there's a fitting gap—for example after lunch.&lt;/p&gt;

&lt;p&gt;Review speed is definitely not solely the reviewer's responsibility—the author has an important role too. The easier it is to pick a pull request and review it, the faster the work flows. Our help article &lt;a href="https://help.swarmia.com/review-code-faster" rel="noopener noreferrer"&gt;"Review Code Faster"&lt;/a&gt; covers how to leverage Swarmia to speed up reviews.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Default to action
&lt;/h3&gt;

&lt;p&gt;Sometimes reviews can stall for various reasons. During those times, you should have a bias for action. One can approve a PR even if there's some input left for the author to consider.&lt;/p&gt;

&lt;p&gt;If a tech decision lingers and work becomes blocked, deciding something relatively quickly is better than slowly concluding to an "ideal" decision. Reserve enough time for technical decisions, but move on before you reach analysis paralysis. Developers should be inclined to merge code instead of primarily focusing on poking holes in the implementation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7hk26jxcss0np4oby6q4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7hk26jxcss0np4oby6q4.png" alt="Ship it!"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Keep pull requests small
&lt;/h3&gt;

&lt;p&gt;Smaller batches are easier to design, test, review, and merge. There are studies &lt;a href="https://jserd.springeropen.com/articles/10.1186/s40411-018-0058-0" rel="noopener noreferrer"&gt;[1]&lt;/a&gt; &lt;a href="https://smartbear.com/learn/code-review/best-practices-for-peer-code-review/" rel="noopener noreferrer"&gt;[2]&lt;/a&gt; about the optimal amount of changed lines, but it's not an exact science. &lt;a href="https://google.github.io/eng-practices/review/developer/small-cls.html" rel="noopener noreferrer"&gt;Google's recommendations&lt;/a&gt; put it well:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;There are no hard and fast rules about how large is “too large.” 100 lines is usually a reasonable size for a CL, and 1000 lines is usually too large, but it’s up to the judgment of your reviewer. The number of files that a change is spread across also affects its “size.” A 200-line change in one file might be okay, but spread across 50 files it would usually be too large.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;It's almost always possible to split a large change into smaller chunks—for example, with a separate refactoring PR that sets the stage for a cleaner implementation. Practicing slicing also helps to detect minimal shippable increments of your product.&lt;/p&gt;

&lt;p&gt;Feature gates or feature flags might be necessary to gain the ability to ship half-ready product features along with the existing ones.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8q76z4pact7rwhldtuvo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8q76z4pact7rwhldtuvo.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  7. Foster a positive feedback culture
&lt;/h3&gt;

&lt;p&gt;Effective communication, in general, is really hard. Giving feedback about a colleague's work is one of the most challenging forms of communication. Acknowledge this in code reviews.&lt;/p&gt;

&lt;p&gt;Here's a list of suggestions to improve discussions in code reviews:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Give feedback about the code, not about the author.&lt;/li&gt;
&lt;li&gt;Pick your battles.&lt;/li&gt;
&lt;li&gt;Accept that there are multiple correct solutions to a problem.&lt;/li&gt;
&lt;li&gt;You're in the same boat.&lt;/li&gt;
&lt;li&gt;PR authors are humans with feelings (except dependabot 🤖).&lt;/li&gt;
&lt;li&gt;Provide reasons, not feelings, to support your position.&lt;/li&gt;
&lt;li&gt;Use the &lt;a href="https://developerhood.com/blog/yes-and-moves-the-conversation-forward/" rel="noopener noreferrer"&gt;"Yes, and..."&lt;/a&gt; technique to keep an innovative atmosphere. It can be an ungracious pattern to dismiss fresh and fragile ideas in a draft PR stage.&lt;/li&gt;
&lt;li&gt;Keep the feedback balanced with positive comments. It's always delightful to receive praise from the reviewer.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the pull request discussion becomes heated, schedule a call to discuss the topic. It usually helps to relieve the tension.&lt;/p&gt;

&lt;h3&gt;
  
  
  8. Use continuous integration effectively
&lt;/h3&gt;

&lt;p&gt;GitHub &lt;a href="https://github.com/features/actions" rel="noopener noreferrer"&gt;Actions&lt;/a&gt; and &lt;a href="https://docs.github.com/en/github/collaborating-with-pull-requests/collaborating-on-repositories-with-code-quality-features/about-status-checks" rel="noopener noreferrer"&gt;status checks&lt;/a&gt; are widely used for building a robust CI pipeline. However, no matter the tools, it's crucial to invest in setting up a CI solution to automate as many quality checks as possible.&lt;/p&gt;

&lt;p&gt;Automated checks allow reviewers to focus on more important topics such as software design, architecture, and readability. Checks can include tests, test coverage, code style enforcements, commit message conventions, static analysis, and much more.&lt;/p&gt;

&lt;p&gt;A variety of metrics produced by continuous integration can help the reviewer to quantify the quality of a PR. Test coverage and code complexity metrics might reveal interesting insights that otherwise would be hard to estimate. These metrics don't necessarily need to be hard pass or fail checks but rather additional data for the review process.&lt;/p&gt;

&lt;p&gt;Instead of slowing down the review process to catch more bugs, try to improve the automated checks to enable fast movement.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxjnuzy96valovlv76ilc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxjnuzy96valovlv76ilc.png" alt="GitHub pull request checks for Swarmia's frontend repository"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  9. Delegate nit-picking to a computer
&lt;/h3&gt;

&lt;p&gt;Whenever a reviewer spends their time nit-picking on small details, consider if it could be an automated check. Automatic check will always be enforced, while the human process relies on the reviewers' memories and moods to reject an anti-pattern.&lt;/p&gt;

&lt;p&gt;For example, our &lt;a href="https://github.com/swarmia/eslint/blob/master/rules/use-consistent-spelling.js" rel="noopener noreferrer"&gt;ESLint rules&lt;/a&gt; enforce a consistent usage of certain terminology across the product. This is far more effective than documentation that would list the correct spelling of each word.&lt;/p&gt;

&lt;p&gt;Code formatting is an example of a controversial topic in which almost all solutions are correct. Spending time debating stylistic choices rarely provides much value to the product, as long as a set of rules are adopted. Consistent unpleasing styles &lt;em&gt;(to some individuals)&lt;/em&gt; are better than a mixture of multiple styles.&lt;/p&gt;

&lt;p&gt;Your team can also adopt pre-existing practices, for example, a TypeScript project could adopt &lt;a href="https://prettier.io/" rel="noopener noreferrer"&gt;Prettier&lt;/a&gt; defaults instead of re-inventing their own.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fibby859c9o5ozjqc10yq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fibby859c9o5ozjqc10yq.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  10. Communicate explicitly
&lt;/h3&gt;

&lt;p&gt;When reviewing a piece of code, be explicit about the action you request from the author. Let's say a reviewer has commented, "This could be done in Postgres in favor of application code" on a line of code. Are they requesting a change, suggesting to refactor it later, or just making the author aware of other solutions? It's often hard to judge. GitHub provides tools to be more explicit: for example, "Request changes" in a review.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk7j53p1vbdljwxoushwf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk7j53p1vbdljwxoushwf.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Tip for the PR author: dismissing a review resets the pull request state to indicate that the reviewer can review again. It's up to you, the PR author, to decide if it feels important enough to use the feature, but especially in remote teams, it might help to make the process even more explicit.&lt;/p&gt;

&lt;h3&gt;
  
  
  11. Use explicit review requests
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://docs.github.com/en/github/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/requesting-a-pull-request-review" rel="noopener noreferrer"&gt;Review requests&lt;/a&gt; in GitHub are a convenient way to let others know that your code is ready for review. While a review can be requested manually, we recommend setting up a &lt;a href="https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners" rel="noopener noreferrer"&gt;CODEOWNERS&lt;/a&gt; file to automate requesting a review. The method is robust and doesn't rely on individual authors remembering to request reviews.&lt;/p&gt;

&lt;p&gt;Reviews can also be requested from a team, via CODEOWNERS or manually, which distributes the responsibility among team members. Make sure reviews are done evenly by all developers instead of siloing reviews to a single person.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frss04db4qmzlrn2zq26v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frss04db4qmzlrn2zq26v.png" alt="Example of a CODEOWNERS file from Swarmia's frontend repository telling GitHub to notify @swarmia/engineers team whenever a new PR is opened"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flbb59xzie4kw1wtsyll1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flbb59xzie4kw1wtsyll1.png" alt="Example of an email sent from a PR based on a CODEOWNERS file"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  12. Review your own code
&lt;/h3&gt;

&lt;p&gt;Before submitting a PR for a review, go through the changes yourself. This helps to catch accidentally included changes, typos, and other simple mistakes that potentially waste the reviewer's time.&lt;/p&gt;

&lt;h3&gt;
  
  
  13. Document as much as possible in code
&lt;/h3&gt;

&lt;p&gt;When receiving a comment or suggestion, aim for documenting the discussion in code. If the reviewer is not sure what the validateUsers function does, elaborate on the functionality ideally by renaming the function or writing a comment in the code. This way, the next developer that reads the code will understand the functionality without reading the PR discussions.&lt;/p&gt;

&lt;p&gt;In some cases, the author can copy-paste their PR discussion response as is to comment in the code.&lt;/p&gt;

&lt;h3&gt;
  
  
  14. Write clear PR descriptions
&lt;/h3&gt;

&lt;p&gt;The reviewer forms a mental picture of a pull request from multiple information sources: feature planning, description in the issue tracker, PR description, commit messages, chat history, etc. The more coherent the picture is, the faster and higher quality the review is. Decide on the team’s preferred channels to communicate certain information.&lt;/p&gt;

&lt;p&gt;At Swarmia, we use PR descriptions to fill the technical gaps that the Jira issue description didn't cover. The additional details often include information such as what setup is needed to test the PR, surprising implementation details, and anything that makes the reviewer's job smoother. There are also other ways to add information: code comments, commit messages, commenting on individual lines in a PR as the author, etc.&lt;/p&gt;

&lt;p&gt;Demo in any visual form is a nice touch. The format can be a screenshot, a screen capture, terminal output pasted in a code block, or anything that captures the change well. GitHub supports both &lt;a href="https://github.blog/2021-05-13-video-uploads-available-github/" rel="noopener noreferrer"&gt;videos&lt;/a&gt; and GIFs in the PR descriptions.&lt;/p&gt;

&lt;p&gt;In addition to a static demo video, it's a great practice to build preview versions of your application per PR branch. The ability to interactively test the application preview without setting up anything in a local development environment saves time and increases the likelihood of someone manually testing a pull request.&lt;/p&gt;

&lt;p&gt;Remember that the fidelity of descriptions required depends on the context.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frlcqu4rvtvgc896kcggk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frlcqu4rvtvgc896kcggk.png" alt="The spectrum of descriptions"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You, as a team, need to figure out the perfect balance between explaining nothing or everything.&lt;/p&gt;

&lt;p&gt;GitHub also supports issue and &lt;a href="https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/creating-a-pull-request-template-for-your-repository" rel="noopener noreferrer"&gt;pull request templates&lt;/a&gt; if you want to standardize parts of the descriptions.&lt;/p&gt;

&lt;h3&gt;
  
  
  15. Use the shared repository model
&lt;/h3&gt;

&lt;p&gt;For most private repositories, we recommend starting with the &lt;a href="https://docs.github.com/en/github/collaborating-with-pull-requests/getting-started/about-collaborative-development-models#shared-repository-model" rel="noopener noreferrer"&gt;Shared repository model&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;In the shared repository model, collaborators are granted push access to a single shared repository and topic branches are created when changes need to be made.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This model makes many aspects of the review process in GitHub simpler than the forking model that is popular among open-source projects.&lt;/p&gt;

&lt;h3&gt;
  
  
  16. Keep discussions public
&lt;/h3&gt;

&lt;p&gt;It's convenient to have a quick chat about a pull request in the office, but be mindful of colleagues working remotely. It's polite to add a summary of face-to-face discussion as a PR comment.&lt;/p&gt;

&lt;p&gt;Pull request discussions are searchable and easily accessible by all developers. They act as a history log of discussion which might be incredibly valuable when debugging a production incident later on.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;That concludes our complete guide for code reviews.&lt;/p&gt;

&lt;p&gt;If you're interested in improving your code reviews beyond what GitHub can offer, take a look at what we've built in &lt;a href="https://www.swarmia.com/product/code/" rel="noopener noreferrer"&gt;Swarmia&lt;/a&gt;. PR view enables convenient access to your open pull requests, Slack notifications help your teams review code faster, and working agreements help you follow the practices that you've agreed on together with your team.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4hn7t19k6zn6b5kxqewh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4hn7t19k6zn6b5kxqewh.png" alt="Swarmia's pull request view showing open PRs as well as key metrics like cycle and review time"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Additional reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://google.github.io/eng-practices/" rel="noopener noreferrer"&gt;Google's Engineering Practices&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://stackoverflow.blog/2019/09/30/how-to-make-good-code-reviews-better/" rel="noopener noreferrer"&gt;How to Make Good Code Reviews Better&lt;/a&gt; by Gergely Orosz&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://mtlynch.io/code-review-love/" rel="noopener noreferrer"&gt;How to Make Your Code Reviewer Fall in Love with You&lt;/a&gt; by Michael Lynch&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://phauer.com/2018/code-review-guidelines/" rel="noopener noreferrer"&gt;Code Review Guidelines for Humans&lt;/a&gt; by Philipp Hauer&lt;/li&gt;
&lt;li&gt;&lt;a href="https://help.swarmia.com/pull-request-cycle-time-in-swarmia" rel="noopener noreferrer"&gt;Reducing Pull Request Cycle Time with Swarmia&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
  </channel>
</rss>
