<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[Blogboard Journal]]></title><description><![CDATA[Lessons from top engineering blogs]]></description><link>https://blogboard.io/blog/</link><image><url>https://blogboard.io/blog/favicon.png</url><title>Blogboard Journal</title><link>https://blogboard.io/blog/</link></image><generator>Ghost 4.48</generator><lastBuildDate>Thu, 16 Apr 2026 18:00:56 GMT</lastBuildDate><atom:link href="https://blogboard.io/blog/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[A/B Testing for Practical Significance]]></title><description><![CDATA[When doing statistical hypothesis testing, the math behind it gives us the toolset to determine the statistical significance of our observations. But if we're doing a two-sample test on a simple hypothesis, rejecting it won't tell us anything about the magnitude of the difference.]]></description><link>https://blogboard.io/blog/ab-testing-practical-significance/</link><guid isPermaLink="false">64d77ed00ff01149e74e1d39</guid><category><![CDATA[probability]]></category><category><![CDATA[statistics]]></category><dc:creator><![CDATA[Drazen Zaric]]></dc:creator><pubDate>Wed, 07 Apr 2021 13:30:00 GMT</pubDate><content:encoded><![CDATA[<p>When doing statistical hypothesis testing, the math behind it gives us the toolset to determine the <em>statistical significance</em> of our observations. But if we&apos;re doing a two-sample test on a simple hypothesis, eg. &#xA0;$H_{0}:\mu_{1}=\mu_{2}$ vs. $H_{1}:\mu_{1}\ne\mu_{2}$ rejecting it won&apos;t tell us anything about the magnitude of the difference.</p><p>Usually, aside from making sure that the difference in measurements you observed are statistically significant, you want your observed differences to be <em>practically</em> significant as well. That means you don&apos;t want to test simply if your statistics (e.g. averages) differ, but you want them to differ by some margin, $\epsilon$. The size of the margin is dependent on the application - if you want to increase a click-through rate you probably have a business goal clearly specified, saying something like <em>Increase CTR by 10 percentage points</em>.</p><p>So how do we do test for a margin of difference? We&apos;ll need to run what&apos;s called a <em>composite hypothesis test</em>. </p><p>It&apos;s a fun practice in fundamentals of hypothesis testing to derive the formulas behind it, so let&apos;s first derive the test for the case of a single sample, comparing its mean to a constant. Then we&apos;ll modify it to make a two-sample test, enabling us to compare averages of two samples.</p><h2 id="one-sample-test">One-sample test</h2><p>Let&apos;s assume our data points $X_{1},X_{2},...,X_{n}$ come as iid observations from some unknown distribution, with mean $\mu$ and variance $\sigma^2$. We want to test with the following null and alternative hypotheses</p><p>\[ \begin{eqnarray*} H_{0}:\left|\mu-\mu_{0}\right| &amp; \le &amp; \epsilon\\ H_{1}:\left|\mu-\mu_{0}\right| &amp; &gt; &amp; \epsilon \end{eqnarray*} \]</p><p>where $\epsilon &gt; 0$ is a constant quantifying our desired <em>practical significance</em>.</p><p>Unrolling this, we get</p><p>$H_{0}:(\mu\ge\mu_{0}-\epsilon)\ and\ (\mu\le\mu_{0}+\epsilon)$<br>$H_{1}:(\mu&lt;\mu_{0}-\epsilon)\ and\ (\mu&gt;\mu_{0}+\epsilon)$</p><p>which should make it obvious why it&apos;s called a composite hypothesis test.</p><p>As usual, we&apos;ll partition the parameter space $\Theta$ into two subspaces, corresponding to parameter spaces for $H_0$ and $H_1$:</p><p>$\Theta_{0}=\left\{ \mu\in\mathbb{\mathbb{R}}\mid(\mu\ge\mu_{0}-\epsilon)\ and\ (\mu\le\mu_{0}+\epsilon)\right\} $<br>$\Theta_{1}=\left\{ \mu\in\mathbb{\mathbb{R}}\mid(\mu&lt;\mu_{0}-\epsilon)\ and\ (\mu&gt;\mu_{0}+\epsilon)\right\} $</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blogboard.io/blog/content/images/2024/04/plot1.png" class="kg-image" alt loading="lazy" width="1033" height="620" srcset="https://blogboard.io/blog/content/images/size/w600/2024/04/plot1.png 600w, https://blogboard.io/blog/content/images/size/w1000/2024/04/plot1.png 1000w, https://blogboard.io/blog/content/images/2024/04/plot1.png 1033w" sizes="(min-width: 720px) 720px"><figcaption>Parameter space partitioning into accept and reject regions</figcaption></figure><p>Since we want to test the mean, we&apos;ll use sample average as the estimate for &#xA0;$\mu$:</p><p>\[<br>\hat{\mu}=\bar{X}_{n}=\frac{1}{n}\sum_{i=1}^{n}X_{i}<br>\]</p><p>Central limit theorem tells us that as $n$ grows, $\bar{X}_n$ converges in distribution to a normal random variable:<br></p><p>\[<br> n\rightarrow\infty:\ \sqrt{n}(\bar{X}_{n}-\mu)\overset{i.d}{\rightarrow}\mathcal{N}\left(0,\sigma^{2}\right)<br> \]</p><p>and the Continuous mapping theorem allows us to go back and forth and get that:</p><p>\[n\rightarrow\infty:\ \bar{X}_{n}\overset{i.d}{\rightarrow}\mathcal{N}\left(\mu,\frac{\sigma^{2}}{n}\right)\]</p><p>So under $H_0$, $\bar{X}_n$ can be asymptotically distributed as any of the $\mathcal{N}\left(\mu,\frac{\sigma^{2}}{n}\right)$ for $\mu\in\Theta_{0}$</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blogboard.io/blog/content/images/2024/04/plot2.png" class="kg-image" alt loading="lazy" width="1033" height="620" srcset="https://blogboard.io/blog/content/images/size/w600/2024/04/plot2.png 600w, https://blogboard.io/blog/content/images/size/w1000/2024/04/plot2.png 1000w, https://blogboard.io/blog/content/images/2024/04/plot2.png 1033w" sizes="(min-width: 720px) 720px"><figcaption>Possible asymptotic distributions of the sample statistic under $H_0$</figcaption></figure><p>We want to design a test with significance level $\alpha$, limiting the <em>Type 1 error</em>. Let&apos;s consider the following test for some $z \ge \epsilon$:</p><p>\[\psi=\begin{cases}1\ (H_{0}\ rejected) &amp; if\ (\hat{\mu}\le\mu_{0}-z)\ or\ (\hat{\mu}\ge\mu_{0}+z)\\0\ (H_{0}\ not\ rejected) &amp; otherwise \end{cases}\]</p><figure class="kg-card kg-image-card"><img src="https://blogboard.io/blog/content/images/2024/04/plot3.png" class="kg-image" alt loading="lazy" width="1033" height="620" srcset="https://blogboard.io/blog/content/images/size/w600/2024/04/plot3.png 600w, https://blogboard.io/blog/content/images/size/w1000/2024/04/plot3.png 1000w, https://blogboard.io/blog/content/images/2024/04/plot3.png 1033w" sizes="(min-width: 720px) 720px"></figure><p>We denote as <em>Type I error</em> &#xA0;the error of falsely rejecting the null hypothesis. Formally, we define the Type I error rate $\alpha_\psi$ as the probability of rejecting the null hypothesis when it was in fact true.</p><p>$\alpha_\psi=P_\mu(\psi=1); \mu\in\Theta_0$</p><figure class="kg-card kg-image-card"><img src="https://blogboard.io/blog/content/images/2024/04/plot4-1.png" class="kg-image" alt loading="lazy" width="1033" height="620" srcset="https://blogboard.io/blog/content/images/size/w600/2024/04/plot4-1.png 600w, https://blogboard.io/blog/content/images/size/w1000/2024/04/plot4-1.png 1000w, https://blogboard.io/blog/content/images/2024/04/plot4-1.png 1033w" sizes="(min-width: 720px) 720px"></figure><p>The <strong><em>level</em></strong> $\alpha$ of a test is the largest <em>Type I error</em> that we&apos;ll get for any $\mu\in\Theta_0$. Formally, a statistical test has <em>level</em> $alpha$ if:</p><p>$\alpha_\psi=P_\mu(\psi=1)\le\alpha, \forall\mu\in\Theta_0$</p><p>Thus, for our test $\psi$, we have the level</p><p>\[ \begin{eqnarray*} \alpha &amp; = &amp; \underset{\mu\in\Theta_{0}}{sup}P_{\mu}\left(\psi=1\right)\\ &amp; = &amp; \underset{\mu\in\Theta_{0}}{sup}P_{\mu}\left((\hat{\mu}&lt;\mu_{0}-z)\ or\ (\hat{\mu}&gt;\mu_{0}+z)\right)\\ &amp; = &amp; \underset{\mu\in\Theta_{0}}{sup}P_{\mu}\left((\hat{\mu}-\mu_{0}&lt;-z)\ or\ (\hat{\mu}-\mu_{0}&gt;z)\right)\\ &amp; \overset{by\ CLT}{\sim} &amp; \underset{\mu\in\Theta_{0}}{sup}\left\{ P\left(\mathcal{N}\left(\mu-\mu_{0},\frac{\sigma^{2}}{n}\right)&lt;-z\right)\ +\ P\left(\mathcal{N}\left(\mu-\mu_{0},\frac{\sigma^{2}}{n}\right)&gt;z\right)\right\} \\ &amp; = &amp; \underset{\mu\in\Theta_{0}}{sup}\left\{ P\left(\mathcal{N}\left(0,1\right)&lt;\sqrt{n}\frac{-z-(\mu-\mu_{0})}{\sigma}\right)\ +\ P\left(\mathcal{N}\left(0,1\right)&gt;\sqrt{n}\frac{z-(\mu-\mu_{0})}{\sigma}\right)\right\} \\ &amp; = &amp; \underset{\mu\in\Theta_{0}}{sup}\left\{ \Phi\left(\sqrt{n}\frac{-z-(\mu-\mu_{0})}{\sigma}\right)+1-\Phi\left(\sqrt{n}\frac{z-(\mu-\mu_{0})}{\sigma}\right)\right\} \\ \end{eqnarray*} \]</p><p>Where $\Phi$ is the cumulative distribution function of a standard Gaussian.</p><p>Let&apos;s see how $\alpha_\psi$ behaves as we move $\mu$ over $\Theta_0$, that is from $\mu_0-\epsilon$ to $\mu_0+\epsilon$. We&apos;ll take the derivative of $\alpha_\psi$ with respect to $\mu$:</p><p>\[ \begin{eqnarray*} \frac{\partial}{\partial\mu}\alpha_{\psi}(\mu) &amp; = &amp; \frac{\partial}{\partial\mu}\left(P_{\mu}\left(\psi=1\right)\right)\\ &amp; = &amp; -\phi\left(\sqrt{n}\frac{-z-(\mu-\mu_{0})}{\sigma}\right)\cdot\frac{\sqrt{n}}{\sigma}+\phi\left(\sqrt{n}\frac{z-(\mu-\mu_{0})}{\sigma}\right)\cdot\frac{\sqrt{n}}{\sigma}\\ &amp; = &amp; \frac{\sqrt{n}}{\sigma}\left(\phi\left(\sqrt{n}\frac{z-(\mu-\mu_{0})}{\sigma}\right)-\phi\left(\sqrt{n}\frac{-z-(\mu-\mu_{0})}{\sigma}\right)\right) \end{eqnarray*} \]</p><p>Where $\phi(x)=\frac{\partial}{\partial{x}}\Phi(x)$ is the pdf of a standard Gaussian.</p><p>We can show by symmetry of $\phi$ that $\frac{\partial}{\partial\mu}\alpha_{\psi}(\mu)=0$ when $\mu=\mu_0$, and using properties of the Gaussian pdf prove that regardless of $n$ and $\sigma$:</p><p>$\frac{\partial}{\partial\mu}\alpha_{\psi}(\mu)&lt;0\ for\ \mu&lt;\mu_0$ <br>$\frac{\partial}{\partial\mu}\alpha_{\psi}(\mu)&gt;0\ for\ \mu&gt;\mu_0$</p><p>Concretely, this means that our $\alpha_\psi$ is the smallest at $\mu=\mu_0$ and grows as we move away from $\mu_0$. It&apos;s easily shown that $\alpha_\psi(\mu_0-\epsilon)=\alpha_\psi(\mu_0+\epsilon)$, ie. it has the same (largest) value at the edges of $\Theta_0$, i.e. when $\mu=\mu_0\pm\epsilon$, or formally:</p><figure class="kg-card kg-image-card"><img src="https://blogboard.io/blog/content/images/2024/04/plot5.png" class="kg-image" alt loading="lazy" width="1033" height="620" srcset="https://blogboard.io/blog/content/images/size/w600/2024/04/plot5.png 600w, https://blogboard.io/blog/content/images/size/w1000/2024/04/plot5.png 1000w, https://blogboard.io/blog/content/images/2024/04/plot5.png 1033w" sizes="(min-width: 720px) 720px"></figure><p>\[ \begin{eqnarray*} \underset{\mu\in\Theta_{0}}{argsup}P_{\mu}\left(\psi=1\right) &amp; = &amp; \mu_{0}\pm\epsilon\\ \underset{\mu\in\Theta_{0}}{sup}P_{\mu}\left(\psi=1\right) &amp; = &amp; \Phi\left(\sqrt{n}\frac{-z-\epsilon}{\sigma}\right)+1-\Phi\left(\sqrt{n}\frac{z-\epsilon}{\sigma}\right) \end{eqnarray*} \\ \\ \]</p><p>So far, we&apos;ve shown that with our test defined as:</p><p>\[\psi=\begin{cases}1\ (H_{0}\ rejected) &amp; if\ (\hat{\mu}&lt;\mu_{0}-z)\ or\ (\hat{\mu}&gt;\mu_{0}+z)\\0\ (H_{0}\ not\ rejected) &amp; otherwise \end{cases}\]</p><p>and for an arbitrary $z\ge\epsilon$, our test has level $\alpha=\Phi\left(\sqrt{n}\frac{-z-\epsilon}{\sigma}\right)+1-\Phi\left(\sqrt{n}\frac{z-\epsilon}{\sigma}\right)$.</p><p>Let&apos;s now go the other way and pick $z$ for a desired level $\alpha$. Looking at the equation for $\alpha$ above, it doesn&apos;t look obvious how to find $z$. To avoid solving this equation, we&apos;ll note the following: as we move $z$ farther from $\epsilon$ our $\alpha$ gets smaller. That means we can find $z_\alpha$ numerically by bisection method.</p><p>However, since getting the <em>p-value</em> is enough for a test, we don&apos;t actually need to solve for $z_\alpha$. Note that as $z$ increases, $\alpha$ decreases, and from the definition of our test we have that the largest $z$ at which we&apos;ll ever reject is $z=\left|\hat{\mu}-\mu_{0}\right|$. This means that the smallest level at which we can reject is given by:</p><p>\[ \text{p-value}=\underset{z\in[\epsilon,\infty]}{min}\alpha=\Phi\left(\sqrt{n}\frac{-\left|\hat{\mu}-\mu_{0}\right|-\epsilon}{\sigma}\right)+1-\Phi\left(\sqrt{n}\frac{\left|\hat{\mu}-\mu_{0}\right|-\epsilon}{\sigma}\right) \]</p><p>As a special case, consider the test with $\epsilon=0$. We&apos;ll have:</p><p>\[ \begin{eqnarray*} H_{0}:\left|\mu-\mu_{0}\right| &amp; = &amp; 0\Leftrightarrow\mu=\mu_{0}\\ H_{1}:\left|\mu-\mu_{0}\right| &amp; &gt; &amp; 0\Leftrightarrow\mu\ne\mu_{0} \end{eqnarray*} \]</p><p>and:</p><p>\[ \begin{eqnarray*} \text{p-value} &amp; = &amp; \underset{z\in[\epsilon,\infty]}{min}\alpha=\Phi\left(\sqrt{n}\frac{-\left|\hat{\mu}-\mu_{0}\right|}{\sigma}\right)+1-\Phi\left(\sqrt{n}\frac{\left|\hat{\mu}-\mu_{0}\right|}{\sigma}\right)\\ &amp; = &amp; 2\cdot\Phi\left(\sqrt{n}\frac{-\left|\hat{\mu}-\mu_{0}\right|}{\sigma}\right) \end{eqnarray*} \]</p><p>which is exactly the simple hypothesis two-sided test.</p><h2 id="two-sample-test">Two-sample test</h2><p>So far we&apos;ve just derived a one-sample test, so we need to modify it a bit to test the difference between means of two samples.</p><p>Given $n$ observations $X_1...X_n$ from a distribution with mean $\mu_X$ and variance $\sigma_X^2$, and $m$ observations $Y_1...Y_m$ from a distribution with mean $\mu_Y$ and variance $\sigma_Y^2$ , we formulate the following null and alternative hypotheses:</p><p>\[ \begin{eqnarray*} H_{0} &amp; : &amp; \left|\mu_{1}-\mu_{2}\right|\le\epsilon\\ H_{1} &amp; : &amp; \left|\mu_{1}-\mu_{2}\right|&gt;\epsilon \end{eqnarray*} \]</p><p>Which is basically saying $\mu_1$ is different from $\mu_2$ by at least a margin of $\epsilon$. We use $\epsilon$ here to state our desired <em>practical significance</em>.</p><p>Let&apos;s define $d$ as $d=\mu_1-\mu_2$. Then we can rewrite our hypotheses as:</p><p>\[ \begin{eqnarray*} H_{0} &amp; : &amp; \left|d-0\right|\le\epsilon\\ H_{1} &amp; : &amp; \left|d-0\right|&gt;\epsilon \end{eqnarray*} \]</p><p>We&apos;ll use $\hat{d}=\hat{\mu}_{1}-\hat{\mu}_{2}=\bar{X}_{n}-\bar{Y}_{n}$ as the estimator for $d$. From the Central limit theorem and the multivariate delta method, we get that:</p><p>\[ \hat{d}=\bar{X}_{n}-\bar{Y}_{n}\overset{i.d.}{\rightarrow}\mathcal{N}\left(\mu_{X}-\mu_{Y},\frac{\sigma_{X}^{2}}{n}+\frac{\sigma_{Y}^{2}}{m}\right) \]</p><p>Substituting $\hat{\mu}\rightarrow\hat{d}$, $\mu_0\rightarrow0$, $\frac{\sigma^{2}}{n}\rightarrow\frac{\sigma_{X}^{2}}{n}+\frac{\sigma_{Y}^{2}}{m}$ and plugging into our formula for p-value, we get:</p><p>\[ \text{p-value}=\Phi\left(\frac{-\left|\hat{d}\right|-\epsilon}{\sqrt{\frac{\sigma_{X}^{2}}{n}+\frac{\sigma_{Y}^{2}}{m}}}\right)+1-\Phi\left(\frac{\left|\hat{d}\right|-\epsilon}{\sqrt{\frac{\sigma_{X}^{2}}{n}+\frac{\sigma_{Y}^{2}}{m}}}\right) \]</p><p>Note once again that setting $\epsilon=0$ we get the familiar form for a simple two-sample two-sided test for difference of means.</p><h2 id="conclusion">Conclusion</h2><p>We&apos;ve shown a step-by-step exercise of deriving a two-sample two-sided Z-test with a margin of tolerance. It should be even simpler to derive a one-sided test, as it&apos;s just a modification of a simple hypothesis one-sided test with an extended range for $\Theta_0$.</p><p>Using the formulas above, in case we&apos;re rejecting $H_0$ we can also find the largest $\epsilon$ at which we can reject with a given p-value. This gives us an upper bound on the difference between means for a given statistical significance. </p>]]></content:encoded></item><item><title><![CDATA[Kano Model Examples - Build Great Products With a Simple Mental Model]]></title><description><![CDATA[When in 2007 Steve Jobs first showed the original iPhone it seemed out of this world. Watch the event video and pay attention to the crowd reaction when Jobs shows pinch-to-zoom or when the phone automatically switches to landscape mode when he flips it in his hand. It was unbelievable.]]></description><link>https://blogboard.io/blog/kano-model-how-to-build-great-products-with-a-simple-mental-model/</link><guid isPermaLink="false">60116fb9c065f548ce6d4b91</guid><dc:creator><![CDATA[Drazen Zaric]]></dc:creator><pubDate>Sun, 07 Feb 2021 23:18:23 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1576733594146-cccc8bef263e?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MXwxMTc3M3wwfDF8c2VhcmNofDUwfHxzaG9wfGVufDB8fHw&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=2000" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1576733594146-cccc8bef263e?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MXwxMTc3M3wwfDF8c2VhcmNofDUwfHxzaG9wfGVufDB8fHw&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=2000" alt="Kano Model Examples - Build Great Products With a Simple Mental Model"><p></p><p>When in 2007 Steve Jobs first showed the original iPhone it seemed out of this world. Watch the event video and pay attention to the crowd reaction when Jobs shows pinch-to-zoom or when the phone automatically switches to landscape mode when he flips it in his hand. It was unbelievable.</p><figure class="kg-card kg-image-card"><img src="https://blogboard.io/blog/content/images/2021/02/jobs_iphone.gif" class="kg-image" alt="Kano Model Examples - Build Great Products With a Simple Mental Model" loading="lazy" width="640" height="360"></figure><p>Few years later, there are <a href="https://qz.com/472767/there-are-now-more-than-24000-different-android-devices/">thousands</a> of smartphone models. Every single one has the pinch-to-zoom feature and switches to landscape mode automatically. You would seriously reconsider buying a phone lacking these features - it would feel weird.</p><p>This is a general property of any product or service - over time, amazing new features become basic, expected, boring attributes. Anyone offering a competitive product has to have these features for a satisfactory user experience. </p><p>It turns out there&apos;s a mental model that helps us thing about this dynamic. Dating back to 1980s, it originates from Japan and is known as the <strong><em>Kano Model</em></strong> after its original author, Noriaki Kano.</p><p>If you read on you&apos;ll find a brief description of Kano model, leaving out the details but more than enough to understand the intuition behind it. We&apos;ll then look at several Kano model examples, namely case studies showcasing how the model can be used in different settings.</p><p>In short, we&apos;ll see an example of a pyramid of customer needs, akin to Maslow&apos;s hierarchy, drawn from airline industry. Understanding products, services and feature ideas in terms of <em>Kano hierarchy of customer needs </em>can help us come up with product strategies and roadmap planning.</p><p>Then we&apos;ll look at how the Kano thinking can be used to understand Tesla&apos;s strategy to break into automotive industry and how we can use these ideas to find product-market fit.</p><p>Finally, we&apos;ll glance at how traditional hotels are fighting back against Airbnb and what they&apos;re doing wrong.</p><h2 id="what-is-the-kano-model">What is the Kano Model?</h2><p></p><p>Kano model posits that you can put any feature of any product or service into one of the following buckets:</p><ol><li><em><strong>Reverse quality</strong></em> - these are product attributes that when present are reducing customer satisfaction, and you&apos;d be better off removing them.</li><li><strong><em>Indifferent </em></strong>- attributes that don&apos;t affect satisfaction regardless of whether they&apos;re present or not</li><li><em><strong>Must-be</strong></em> - attributes that customers expect the product to have. Without these you don&apos;t have a satisfactory, competitive product.</li><li><strong><em>Performance </em></strong>(or <em>one-dimensional</em>) - attributes that make customers happy when they&apos;re present, and dissatisfied when absent. Also the <em>more-is-better</em> attributes like memory in computers, horsepower or miles-per-gallon in cars.</li><li><em><strong> Delighters </strong></em>(or <em>attractive</em>)<em><strong> </strong>- </em>when present these attributes cause delight, when absent customers won&apos;t care that much. Usually the features or services that you provide by going out of your way to please customers.</li></ol><p>An important idea coming with the model is the <em><strong>decay of delight </strong>- </em>over time <em>delighters</em> will turn into <em>performance</em> attributes, and <em>performance</em> attributes will shift to <em>must-be</em>. With products, this inevitably happens as new technology becomes commonplace, with services it will happen once most competitors implement what used to be delightful offerings.</p><p>There&apos;s a commonly used visual representation of these. Imagine evaluating each feature along two axes:</p><ul><li> <em>feature sophistication </em>(from <em>not present </em>to <em>best of breed</em>) </li><li><em>customer satisfaction </em>(from <em>dissatisfied </em>to <em>delighted</em>). </li></ul><p>You&apos;ll would the following chart:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blogboard.io/blog/content/images/2021/02/kano_model_png.png" class="kg-image" alt="Kano Model Examples - Build Great Products With a Simple Mental Model" loading="lazy" width="1480" height="1099" srcset="https://blogboard.io/blog/content/images/size/w600/2021/02/kano_model_png.png 600w, https://blogboard.io/blog/content/images/size/w1000/2021/02/kano_model_png.png 1000w, https://blogboard.io/blog/content/images/2021/02/kano_model_png.png 1480w" sizes="(min-width: 720px) 720px"><figcaption>Kano Model - Feature categories</figcaption></figure><p>Note that in practice you don&apos;t actually have a continuous measure for each of the axes. So the chart should be understood to depict qualitative categories and is an intuitive, rough way to capture the main idea of the Kano model.</p><p>There&apos;s theory and history behind the model, but the essence is easy to understand. As an example, let&apos;s say we&apos;re a smartphone company that wants to stop shipping chargers inside the box with new phones. We could ask a sample of our customers <em>how happy they are that their new phone came with a charger inside the box</em>. We would offer the following scale for answers:</p><ul><li>I like it</li><li>I expect it</li><li>I&apos;m neutral</li><li>I can tolerate it</li><li>I dislike it</li></ul><p>Most people would likely respond with a positive answer (<em>I expect it, I like it</em>). Some may have a charger at home that they can use anyway, so they could be <em>Neutral</em> about it. It&apos;s hard to imagine a significant number of buyers to be dissatisfied with a free charger.</p><p>Remember, we want to stop shipping chargers inside the box by default. We&apos;d like to know how the market will react? We could just ask our customers the obvious question: <em>&quot;If your new phone came without a charger in the box, how would you feel about it?&quot;. </em>We would offer the same answer scale.</p><p>In general, take any feature <em>f </em>of your product and ask your customers the following two questions:</p><ul><li><em>Functional question</em>: &#x201C;How would you feel if <em>f</em> was present/more extensive in the product?&#x201D; </li><li><em>Dysfunctional question</em>: &#x201C;How would you feel if <em>f</em> was absent/less extensive in the product?&#x201D;</li></ul><p>If customers overwhelmingly say they <em>expect</em> the feature <em>f, </em>and would <em>dislike it </em>if <em>f</em> was absent, then you have a <em>Must-be </em>feature. Remove it and your product will be unsatisfactory.</p><p>If they say they don&apos;t mind <em>f</em> being absent, but <em>like it</em> when it&apos;s present, then you have a <em>Delighter. </em>It&apos;s an unexpected feature that gives you a competitive edge on the market. However, satisfaction will not deteriorate if you exclude the feature.</p><p>There are many possible combinations of answers and the <em>Kano evaluation table </em>tells us how to assign features to categories based on survey answers.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blogboard.io/blog/content/images/2021/02/Screenshot-2021-02-03-at-00.11.19.png" class="kg-image" alt="Kano Model Examples - Build Great Products With a Simple Mental Model" loading="lazy" width="1184" height="590" srcset="https://blogboard.io/blog/content/images/size/w600/2021/02/Screenshot-2021-02-03-at-00.11.19.png 600w, https://blogboard.io/blog/content/images/size/w1000/2021/02/Screenshot-2021-02-03-at-00.11.19.png 1000w, https://blogboard.io/blog/content/images/2021/02/Screenshot-2021-02-03-at-00.11.19.png 1184w" sizes="(min-width: 720px) 720px"><figcaption>Kano decision matrix. Source and interactive version: <a href="https://kano.plus/about-kano#questionnaire">https://kano.plus/about-kano#questionnaire</a>)</figcaption></figure><p>That&apos;s the basics, and now that we know what Kano model is and where it comes from, let&apos;s look at how we can use it to think about products, innovation and market competition.</p><h2 id="kano-model-for-product-strategy-and-feature-prioritization">Kano Model for Product Strategy and Feature Prioritization</h2><p></p><p>In a 2003 paper, <em><a href="https://www.researchgate.net/publication/313250709_Kano_Model_A_Dynamic_Approach_for_Classifying_and_Prioritizing_Travellers%27_Requirements">Kano Model: A Dynamic Approach for Classifying and Prioritizing Travellers&apos; Requirements</a></em>, we learn about the service strategy of Scandinavian Airlines (SAS).</p><p>It&apos;s presented as a pyramid of services, with fundamentals at the bottom (transfer passengers and luggage safely, on time), support services in the middle and tailoring to individual needs at the top. It&apos;s not hard to map these onto Kano categories.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blogboard.io/blog/content/images/2021/02/kano_model_pyramid_sas.png" class="kg-image" alt="Kano Model Examples - Build Great Products With a Simple Mental Model" loading="lazy" width="1762" height="1295" srcset="https://blogboard.io/blog/content/images/size/w600/2021/02/kano_model_pyramid_sas.png 600w, https://blogboard.io/blog/content/images/size/w1000/2021/02/kano_model_pyramid_sas.png 1000w, https://blogboard.io/blog/content/images/size/w1600/2021/02/kano_model_pyramid_sas.png 1600w, https://blogboard.io/blog/content/images/2021/02/kano_model_pyramid_sas.png 1762w" sizes="(min-width: 720px) 720px"><figcaption>Image adapted from <em><a href="https://www.researchgate.net/publication/313250709_Kano_Model_A_Dynamic_Approach_for_Classifying_and_Prioritizing_Travellers%27_Requirements">Kano Model: A Dynamic Approach for Classifying and Prioritizing Travellers&apos; Requirements, Arash Shahin</a></em></figcaption></figure><p>When used to prioritize of feature implementation, the pyramid nicely fits the typical prioritization heuristic used with the Kano model: get the basic stuff right (must-be attributes), be competitive at the performance features, add in delighters on top. Miss any of the foundational elements and the entire pyramid crumbles down. Leave out the top and you don&apos;t have complete, shiny, pointy pyramid.</p><figure class="kg-card kg-image-card"><img src="https://blogboard.io/blog/content/images/2021/02/kano_model_priorities_png.png" class="kg-image" alt="Kano Model Examples - Build Great Products With a Simple Mental Model" loading="lazy" width="1380" height="1184" srcset="https://blogboard.io/blog/content/images/size/w600/2021/02/kano_model_priorities_png.png 600w, https://blogboard.io/blog/content/images/size/w1000/2021/02/kano_model_priorities_png.png 1000w, https://blogboard.io/blog/content/images/2021/02/kano_model_priorities_png.png 1380w" sizes="(min-width: 720px) 720px"></figure><p>In <a href="http://www.defmacro.org/2013/09/26/products.html">How to build great products</a>, Slava Akhmechet outlines an intuitive heuristic based on three buckets very similar Kano model categories:</p><blockquote>The most important aspect of product management is categorizing features into three buckets: gamechangers, showstoppers, and distractions. When I first started building products, all features looked roughly the same. Over time, I formed the three bucket model and now my mind automatically slots every feature into one of these buckets.</blockquote><p>Describing his heuristic using a case of building mobile phones, the author states his three feature buckets:</p><blockquote><strong>A gamechanger.</strong> People will want to buy your product because of this feature.<br><br><strong>A showstopper.</strong> People won&#x2019;t buy your product if you&#x2019;re missing this feature, but adding it won&#x2019;t generate demand.<br><br><strong>A distraction.</strong> This feature will make no measurable impact on adoption.<br><br><strong>Empirically, successful products have one to three gamechanging features, dozens of features that neutralize showstoppers, and very few features that are distractions.</strong> Your job is to build an intuition about your space to be able to tell these categories apart. That&#x2019;s still pretty subtle (is a built-in phone projector a gamechanger or a distraction?), but at least this model gives you a plan of attack.</blockquote><p>As Akhmechet suggests, building intuition around feature categories is an essential skill for anyone wanting to build successful products. On top of this, Kano model provides a systematic way of assessing and categorizing features. Besides the obvious, it can be a useful way of testing whether your intuition is aligned with your customers.</p><p>Removing features is another problem where Kano thinking can help. In software there&apos;s rarely reasons to remove functioning features. In service or manufacturing industries this is a massive cost-reduction mechanism. When thinking about which features to remove from your product or service, you&apos;ll likely end up going the opposite way from what we described above. You&apos;ll first consider removing delighters, reduce some performance attributes, and think very hard about must-be features.</p><p>The model is often studied as a tool for prioritization. However, mapping attributes of a product onto a pyramid like above can help prevent decay in quality of a product. Focusing too much on adding exciting new stuff and improving performance to stay competitive can cause attention to drift away from boring fundamentals.</p><h2 id="finding-a-market-for-your-product">Finding a Market for Your Product</h2><p></p><p>Kano categories for a feature can vary depending on the target market and customer segment. A delighter in a budget family car will often be a basic (<em>must-be</em>) feature in an upmarket segment.</p><p>The set of features you&apos;re able to deliver will determine the market segment you can compete in. The market you choose will determine the entry barrier (<em>must-be </em>features), the areas where you can outperform competition (<em>performance</em> features) and the room you have to leave your customers in awe (<em>delighters</em>).</p><p>At any time, the current state of technology inevitably dictates what features are possible in a product. Introduction of the first Tesla Roadster is a great example of choosing the right market under such constraints. In 2006, Elon Musk shared <a href="https://www.tesla.com/blog/secret-tesla-motors-master-plan-just-between-you-and-me">The Secret Tesla Motors Master Plan</a>. In it, Musk explains that with the new technology (electric motors, batteries) you can&apos;t play at the low-end market:</p><blockquote>Almost any new technology initially has high unit cost before it can be optimized and this is no less true for electric cars. The strategy of Tesla is to enter at the high end of the market, where customers are prepared to pay a premium, and then drive down market as fast as possible to higher unit volume and lower prices with each successive model. </blockquote><p>In <a href="https://www.tesla.com/blog/master-plan-part-deux">part two</a>, published in 2016, Musk adds:</p><blockquote>Also, a low volume car means a much smaller, simpler factory, albeit with most things done by hand. Without economies of scale, anything we built would be expensive, whether it was an economy sedan or a sports car. While at least some people would be prepared to pay a high price for a sports car, no one was going to pay $100k for an electric Honda Civic, no matter how cool it looked.</blockquote><p>Translating to Kano terminology, in economy-cars segment the price is a <em>reverse-quality</em> attribute, while luxury performance car buyers are mostly indifferent to high prices.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blogboard.io/blog/content/images/2021/02/image-3.png" class="kg-image" alt="Kano Model Examples - Build Great Products With a Simple Mental Model" loading="lazy" width="560" height="338"><figcaption>Tesla Roadster (first generation). Image credits: <a href="https://en.wikipedia.org/wiki/Tesla_Roadster_(first_generation)">Wikipedia</a></figcaption></figure><p>Also, as a sports car buyer you&apos;ll likely care less about practical attributes such as service network, availability of charging stations, battery range. For a budget family car owner, those are very much worth considering.</p><p>With its superior acceleration, an electric vehicle is a perfect competitor in high-performance car market. It&apos;s novelty and exclusivity are <em>delighters</em> that make the first generation of the Tesla roadster a perfect luxury item. So by using the technology that&apos;s not yet ready to satisfy the basic needs of the mass market, Tesla were able to cleverly craft a product that would satisfy all the basics, win on the performance and leverage novelty to delight buyers of high-performance cars.</p><p>By finding a market where your product can perfectly deliver the <em>must-be</em> attributes, outplay the competition in <em>performance</em>, and deliver enough <em>delighters </em>you can achieve product-market fit by choosing the market instead of changing the product.</p><h3></h3><h2 id="staying-competitive-in-a-tough-market">Staying Competitive in a Tough Market</h2><p></p><p>Airbnb is a famous example of disruption in a centuries-old industry. Offering unique apartments reflecting the local spirit, and at cheaper prices, Airbnb stole a large chunk of the market from traditional hotels.</p><p>The difference is well captured in a PostFunnel <a href="https://postfunnel.com/how-airbnb-changed-the-hospitality-industry/">article</a> titled <em>How Airbnb Changed the Hospitality Industry</em>:</p><blockquote>&#x201C;People who choose Airbnb are seeking an intimate, non-manufactured experience. [..] They want to be embedded in the fabric of a community, where they can feel the uniqueness of place. This desire for authenticity is driving today&#x2019;s hospitality design &#x2014; each hotel must tell a story; it must be a place of context, reflective of its neighborhood and community.&#x201D;</blockquote><p>The consistent, <em>manufactured</em>, feel of traditional hotels simply doesn&apos;t cut it. It might be an efficiency thing for hotels, making them easier to manage, equip and maintain. But for a huge segment of customers, bland hotels are unattractive. So, in Kano model terminology, this consistency would be categorized as a <em>reverse quality </em>attribute.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blogboard.io/blog/content/images/2021/08/image-4.jpg" class="kg-image" alt="Kano Model Examples - Build Great Products With a Simple Mental Model" loading="lazy" width="880" height="587" srcset="https://blogboard.io/blog/content/images/size/w600/2021/08/image-4.jpg 600w, https://blogboard.io/blog/content/images/2021/08/image-4.jpg 880w" sizes="(min-width: 720px) 720px"><figcaption><em>An Airbnb room in San Francisco. Photo credit: Airbnb</em></figcaption></figure><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blogboard.io/blog/content/images/2021/08/image-6.jpg" class="kg-image" alt="Kano Model Examples - Build Great Products With a Simple Mental Model" loading="lazy" width="1170" height="660" srcset="https://blogboard.io/blog/content/images/size/w600/2021/08/image-6.jpg 600w, https://blogboard.io/blog/content/images/size/w1000/2021/08/image-6.jpg 1000w, https://blogboard.io/blog/content/images/2021/08/image-6.jpg 1170w" sizes="(min-width: 720px) 720px"><figcaption>A hotel room in San Francisco. Image credit: https://www.omnihotels.com</figcaption></figure><p>Since it&apos;s becoming an expectation (<em>must-be</em>) among travellers, large hotel chains are starting to transition to more cozy, residential style accommodation, connected to local lifestyle and attractions.</p><p>An article titled <a href="https://hospitalitytech.com/4-hotel-strategies-remaining-competitive-age-airbnb"><em>4 Hotel Strategies for Remaining Competitive in the Age of Airbnb</em></a><em> </em>lists <em>technology, personalization </em>and<em> amenities</em> as the means for hotels to stay competitive. Referring to Kano model, this is would typically mean offering more <em>delighters. </em></p><p>In <a href="https://www.youtube.com/watch?v=Hr1rN3jibIk"><em>Building a Winning UX Strategy Using the Kano Model</em></a> Jared Spool opens his talk on Kano model with a story about Hyatt&apos;s random acts of generosity. It was a tactic intended on improving guest satisfaction and loyalty. Spool points out that we can predict such an effort to fail by observing it in the light of the Kano model. Simply put, it unlikely to help if you go out of your way to offer <em>delighters</em> on top of flawed <em>must-be</em> and subpar <em>performance</em> attributes.</p><hr><p>That concludes our discussion of the Kano model and its uses.</p><p>If you&apos;re interested in more product-related reads, make sure to check out <a href="https://blogboard.io/search?searchQuery=product%20management">Product management</a> on Blogboard search.</p>]]></content:encoded></item><item><title><![CDATA[Marketing Data Science - Case Studies from Airbnb, Lyft, Doordash]]></title><description><![CDATA[In this article we'll look at several case data science case studies from marketing optimization efforts at companies like Lyft, Airbnb, Netflix, Doordash, Wolt, Rovio Entertainment.]]></description><link>https://blogboard.io/blog/data-science-in-marketing-optimization/</link><guid isPermaLink="false">5ff10caec065f548ce6d468f</guid><dc:creator><![CDATA[Drazen Zaric]]></dc:creator><pubDate>Thu, 07 Jan 2021 00:20:44 GMT</pubDate><media:content url="https://blogboard.io/blog/content/images/2021/11/possessed-photography-_E1PQXKUkMw-unsplash.jpeg" medium="image"/><content:encoded><![CDATA[<img src="https://blogboard.io/blog/content/images/2021/11/possessed-photography-_E1PQXKUkMw-unsplash.jpeg" alt="Marketing Data Science - Case Studies from Airbnb, Lyft, Doordash"><p>In the first quarter of 2019, Airbnb spent $367 million on sales and marketing. When you think about this from a technical standpoint, two obvious problems come to mind:</p><ol><li>How do you scale your marketing processes to be able to spend $300+ million per quarter on ads?</li><li>Once you have systems in place to spend huge ad budgets, what&apos;s an optimal way to allocate the money?</li></ol><p>In this article we&apos;ll look at several case studies of data science in marketing, applied to optimize efforts at companies like Lyft, Airbnb, Netflix, Doordash, Wolt, Rovio Entertainment.</p><p>Summarizing articles from official blogs of these companies, we&apos;ll get a high level overview of marketing automation and then zoom in on the parts where data science and machine learning play their role.</p><p>If you read on, you&apos;ll find these three sections:</p><ol><li><strong>Marketing automation systems</strong> - what are they, what subsystems they comprise, where in the process is data science usually applied</li><li><strong>Performance estimation</strong> - why estimating the performance of your campaigns is the fundamental problem in marketing analytics and what is the data science tool set used for this</li><li><strong>Optimizing bidding and budget allocation</strong> - once your marketing efforts are at the scale of hundreds or thousands of concurrent campaigns, it&apos;s impossible to allocate you budget manually in an optimal way. This is where Marketing Data Science shines. We look at two simple algorithms for budget allocation, shared by DoorDash and Lyft engineers.</li></ol><h2 id="marketing-automation-systems">Marketing Automation Systems</h2><p>In large and analytically mature organizations, the <em>optimization</em> piece usually comes as a part of a larger <em>marketing automation</em> system, but as we&apos;ll see it&apos;s not always the case. Allocating budgets manually but aided by data science can be hugely profitable and might be a good first step towards a fully automated workflow.</p><p>Before diving into details, let&apos;s look at high level architecture of an automated process for online marketing.</p><p>Generally, all advertising platforms involve a common workflow. You set up the ad creative (text, visuals), choose the target audience, set bidding budget and strategy. As a result of streamlining this workflow, marketing automation systems are very similar in their high level architecture. Usually, these systems comprise the following:</p><ol><li>Data tracking system <br>Track conversion events (customer signups, payment events, subscriptions, micro-transactions, etc).</li><li>Attribution system<br>Connect conversion events with the user acquisition source. That is, for each user we want to know exactly the marketing channel and the campaign that brought them in.</li><li>Performance estimation system<br>Let&apos;s say a campaign brought in 1000 users. We want to know if it paid off. We know how much we spent on it, but how do we know how much revenue the users will bring us over their lifetime. LTV and conversion modelling comes into play here.</li><li>Campaign management system<br>Online ads are a very fertile field for variation testing and content generation. But even without testing multiple you variations of the same ad, companies typically target different segments in different ways, easily resulting in dozens or hundreds ads running simultaneously. Companies like Airbnb and Netflix invest heavily in systems that support ad creation and management ( <a href="https://medium.com/airbnb-engineering/growing-our-host-community-with-online-marketing-9b2302299324">Airbnb article</a>, <a href="https://netflixtechblog.com/https-medium-com-netflixtechblog-engineering-to-improve-marketing-effectiveness-part-2-7dd933974f5e">Netflix article</a>).</li><li>Automated bidding and budget optimization<br>The largest ad serving platforms provide you with near real-time feedback on your ad performance. Connect this with the spend and projected LTV and you can get your ROI predictions and adjust budgets accordingly. With dozens or hundreds of campaigns and variations, the benefits of automation and optimization at this steps can be huge.</li></ol><p>As we&apos;re interested in the role that data science can play in overall ad lifecycle, we&apos;ll focus on the two parts that tend to benefit the most from mixing in data science: 1) performance estimation and 2) automated bidding and budgeting.</p><p>Before diving in, it&apos;s important to understand the<em> channel/campaign </em>nomenclature. By <em>channel</em> we consider an advertising platform, such as Google AdWords, Facebook, Youtube, etc. A <em>campaign</em> is a single piece of advertising aimed at specific audience, according to segments available on the <em>channel, </em>with a preset starting and end time.</p><p>When evaluating marketing performance, we might want to look at investment and ROI at the level of a channel, a single campaign or a group of similar campaigns. We&apos;ll see how these different levels of granularity influence the amount and quality of available data, and in consequence how that determines the approaches that can be taken.</p><h2 id="performance-estimation">Performance Estimation</h2><p>Ideally, for the purpose of marketing data science optimization we&apos;re interested in LTV and CAC (Customer Acquisition Cost) as the factor in the ROI equation: $$ROI=\frac{LTV}{CAC}$$</p><p>LTV modelling is a fundamental problem in business analytics and it is far from trivial to get it completely right. The exact models depend heavily on the type of business and the intended application. LTV models are generally more valuable if we can give good estimates very early in the user lifetime. However, the earlier we do it the less data we have at our disposal.</p><p>In <a href="https://www.appsflyer.com/blog/overcoming-ltv-modeling-pitfalls/">Pitfalls of Modeling LTV and How to Overcome Them</a>, Dmitry Yudovsky outlines several challenges that make it impossible for a cookie-cutter approach for LTV estimation to exist:</p><ul><li>Machine learning approaches are sometimes completely inadequate.<br>There might be lack of data necessary for long term LTV predictions. Also, even if we do have a large business with tons of historical data, there are cases when training models on year old data doesn&apos;t work well - maybe the product or the entire market is very different than a year or two ago.</li><li>Depending on whether we want to use LTV estimates for ad optimization, CRM efforts or corporate financial projections, we might have different requirements for model accuracy and cohort granularity at which we&apos;re making predictions (eg. single user, single campaign, group of campaigns, all users, etc.)</li></ul><p>Of course the problem is not intractable, and there are several common approaches. We&apos;ll look at a few case studies found in tech blogs from DoorDash, Airbnb and Lyft Engineering teams.</p><p>In <a href="https://doordash.engineering/2020/07/31/optimizing-marketing-spend-with-ml/">Optimizing DoorDash&#x2019;s Marketing Spend with Machine Learning</a>, Doordash data scientists present their approach, where instead of directly estimating LTV, they model conversion rates as a function of marketing spend. We&apos;ll see later how these cost curves help to neatly optimize budget allocation across channels and campaigns.</p><p>Experience (data) tells us that any marketing channel will reach saturation at some point, so we can model cost curves, ie. $Conversion=f(Spend)$<em> </em>using a power function of the form $a\cdot Spend^{b}$.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blogboard.io/blog/content/images/2021/01/image.png" class="kg-image" alt="Marketing Data Science - Case Studies from Airbnb, Lyft, Doordash" loading="lazy" width="548" height="408"><figcaption>Cost curve of the shape $a\cdot Spend^{b}$. Image credit: <a href="https://doordash.engineering/2020/07/31/optimizing-marketing-spend-with-ml/">DoorDash Engineering</a></figcaption></figure><p>We can fit cost curves at any cohort level, and it&apos;s typically done at the granularity of a channel or campaign. Simply put, if for a given campaign we spent $x$ amount of money, and that brought us $y$ users, we have one data point, $(x, y)$.</p><p>However, when allocating budgets at a later stage, we might need to make decisions at the <em>campaign </em>level, which cause problems with insufficient amount of data. In the DoorDash Engineering article, Aman Dhesi explains this problem:</p><blockquote>For some channels like search engine marketing, we have thousands of campaigns that spend a small amount of money every week. This makes the weekly attribution data noisy. Some weeks these campaigns don&#x2019;t spend at all, which makes the data sparse. Using this data as-is will result in unreliable cost curves and in turn suboptimal (potentially wildly so) allocation.</blockquote><p>At DoorDash they solve this problem by training separate models which use similar campaigns to fill in the gaps in the dataset with synthetic data. This approach brings with itself certain tradeoffs, described in the <a href="https://doordash.engineering/2020/07/31/optimizing-marketing-spend-with-ml/">original article</a>.</p><p>In a similar manner, as described in <a href="https://eng.lyft.com/lyft-marketing-automation-b43b7b7537cc">Building Lyft&#x2019;s Marketing Automation Platform</a>, data scientists at Lyft would fit an LTV curve of the shape $LTV=a\cdot Spend^{b}$. However, they incorporate an additional degree of randomness by modelling $a$ and $b$ as random variables and estimating their parameters $(\mu_a, \sigma_a)$ and $(\mu_b, \sigma_b)$ from historical data. This helps them implement an explore-exploit approach in the bidding step, by instantiating LTV curves after sampling $a$ and $b$ from their respective distributions. We&apos;ll revisit this approach briefly at the end of next section.</p><p>As described in <a href="https://medium.com/airbnb-engineering/growing-our-host-community-with-online-marketing-9b2302299324">Growing Our Host Community with Online Marketing</a>, at Airbnb they face a problem stemming from the nature of their product and the market. When predicting LTV for an Airbnb home listing, two major problems are:</p><ol><li>Ad conversions for hosts are a very rare event. This poses problems with building large enough data sets. It also influences data tracking and attribution, where these systems have to be as precise as possible in order not to lose or wrongly attribute any data points.</li><li>Time from ad impression (user seeing an ad) to conversion (home listed on Airbnb) can be very long, sometimes weeks. This is a problem if you want to optimize and re-budget your campaigns soon after rollout - you simply don&apos;t have enough data yet.</li></ol><p>In the same post, Tao Cui describes the architecture of each part of Airbnb&apos;s marketing platform as well as the motivation for building the entire thing, along with choices of tech stack. </p><p>In another article dating from 2017, <a href="https://medium.com/airbnb-engineering/using-machine-learning-to-predict-value-of-homes-on-airbnb-9272d3d4739d">Using Machine Learning to Predict Value of Homes On Airbnb</a>, Robert Chang describes how they use machine learning (ending up using XGBoost in production) to estimate LTV of each listing. Framing it as a typical regression problem, they use hundreds of features, such as <em>location data, price with all the partial costs (eg. cleaning fee, discounts), availability, previous bookings, </em>to predict revenue from a listing after some fixed amount of time (eg. 1-year revenue). If you&apos;re curious, the post also describes some of the pieces of infrastructure used by the system and gives a high-level code examples of training pipeline construction.</p><p>In <a href="https://www.appsflyer.com/resources/gaming/predictive-modeling-app-marketers-guide/pros-and-cons-of-different-ltv-based-predictive-models-insights-from-top-marketers/">Insights on the Pros and Cons of LTV-based Predictive Models</a> an article from AppsFlyer, we can find a summary of pros and cons of the three common LTV modelling approaches for app-based businesses:</p><ol><li>Retention/ARPDAU model<br>If we have a fairly old and stable product with some historical data, we can leverage the fact that we know the shape of the retention curve and can fit a power curve to several early-retention data points. We also know the <em>Average Revenue Per Daily Active User (ARPDAU) </em>which tends to be stable over time for most freemium and micro-transaction apps (such as free to play games). With some math we can arrive at an estimate of the expected LTV using these two measures. For example, to estimate LTV by day 90 of user&apos;s lifetime we would use the following equation: &#xA0;$$LTV_{90}=ARPDAU\cdot\sum_{d=0}^{90}retention[d]$$</li><li>LTV ratio model<br>As a simple example, in order to get $LTV_{90}$ we&apos;ll use historical data to estimate the ratio $\frac{LTV_{90}}{LTV_{7}}$ and use the observed 7-day LTV to predict the 90-day LTV</li><li>Behavior driven/user-level models<br>We&apos;d use user-level features to train our favorite machine learning model for regression. This is the approach mentioned above in the Airbnb case.</li></ol><p>The article further discusses pros and cons of each approach in depth, considering the type of business and the intended use cases for the LTV model.</p><p>Now, back to the big picture - we needed LTV estimation in order to predict performance of our marketing campaigns. Once we have satisfactory models in place we can use them to make decisions concerning ad budgets. </p><h2 id="optimizing-bidding-and-budget-allocation">Optimizing bidding and budget allocation</h2><p>Once we have the estimates of performance (ROI) for each campaign, we want to allocate our marketing budget across campaigns so that we maximize the total return on investment.</p><p>Depending on the degree of automation, we can use the data science-backed systems to either aid manual budgeting or to automate real-time bidding decisions in a fully automated system.</p><p>In the first case, we have a static problem where at some point in time we&apos;re looking at a set of channels/campaigns with their predicted ROIs. A set of sortable tables, visualizations and derived metrics can invaluably help campaign managers to optimize their efforts.</p><p>On the other hand, in a fully automated system, we can have algorithms bidding and deciding how to spend each dollar in an optimal way. Looking into articles from <a href="https://doordash.engineering/2020/07/31/optimizing-marketing-spend-with-ml/">DoorDash</a> and <a href="https://eng.lyft.com/lyft-marketing-automation-b43b7b7537cc">Lyft</a> engineering teams, we learn about two variations of an approach that sequentially maximizes marginal value of each dollar spent.</p><p>In <a href="https://doordash.engineering/2020/07/31/optimizing-marketing-spend-with-ml/">Optimizing DoorDash&#x2019;s Marketing Spend with Machine Learning</a> the proposed approach looks at cost curves for each channel/campaign, representing the function $Conversion=f(Spend)$. We note that the slope of the curve is monotonically decreasing as we increase spend, meaning that for each additional dollar spent our marginal value decreases - we get fewer conversions per $ spent.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blogboard.io/blog/content/images/2021/01/image-3.png" class="kg-image" alt="Marketing Data Science - Case Studies from Airbnb, Lyft, Doordash" loading="lazy" width="674" height="500" srcset="https://blogboard.io/blog/content/images/size/w600/2021/01/image-3.png 600w, https://blogboard.io/blog/content/images/2021/01/image-3.png 674w"><figcaption>Cost curves with monotonically decreasing slopes. Image credit: <a href="https://doordash.engineering/2020/07/31/optimizing-marketing-spend-with-ml/">DoorDash Engineering</a></figcaption></figure><p>With such problem in place, in order to optimally allocate a fixed budget we can use a simple greedy algorithm:</p><ol><li>For each channel/campaign $c$ set $spend\left[c\right]:=0$</li><li>For each \$ until budget is exhausted: <br><br>2.1. Find the channel/campaign $c_{best}$ with the largest marginal return (ie. the largest slope) at it&apos;s current spend. More formally: $c_{best}=\underset{c}{argmax}\left\{ \frac{\partial}{\partial spend}Conversion[c](spend[c])\right\} $<br><br>2.2. Assign the next \$ to campaign $c_{best}$, ie. $spend\left[c\right]:=spend\left[c\right]+1$</li></ol><p>Of course, models and budget allocations can (and should) be periodically updated using performance data obtained from the advertising platform APIs. That brings us to the approach relying on continuously experimenting and updating the model in an explore-exploit fashion.</p><p>In <a href="https://eng.lyft.com/lyft-marketing-automation-b43b7b7537cc">Building Lyft&#x2019;s Marketing Automation Platform</a>, a Multi-armed bandit approach is described. Instead of modeling $Conversion$, they fit an LTV curve, that essentially has the same power-function properties that we described above (monotonically decreasing slope). As mentioned in the previous section, they incorporate an additional degree of randomness by modelling $a$ and $b$ as random variables and estimating their parameters $(\mu_a, \sigma_a)$ and $(\mu_b, \sigma_b)$. </p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blogboard.io/blog/content/images/2021/01/image-4.png" class="kg-image" alt="Marketing Data Science - Case Studies from Airbnb, Lyft, Doordash" loading="lazy" width="700" height="917" srcset="https://blogboard.io/blog/content/images/size/w600/2021/01/image-4.png 600w, https://blogboard.io/blog/content/images/2021/01/image-4.png 700w"><figcaption>Cost curves with model parameters modelled as random variables, enabling Thompson sampling approach to optimization. Image credit <a href="https://eng.lyft.com/lyft-marketing-automation-b43b7b7537cc">Lyft Engineering</a></figcaption></figure><p>Then they use <em>Thompson sampling, </em>a simple algorithm for Multi-armed bandit problem with a Bayesian model. An excelent introduction to Bayesian bandits and Thompson sampling can be found in Chris Stucchio&apos;s article from 2013 - <a href="https://www.chrisstucchio.com/blog/2013/bayesian_bandit.html">Bayesian Bandits - optimizing click throughs with statistics</a>.</p><hr><p>In this article we&apos;ve covered several case studies in using marketing data science to optimize <em>online marketing</em> with several different approaches. Sources vary in their depth and detail, but it&apos;s nevertheless inspiring to learn about all the different ways to solve common problems. </p><p>If you&apos;re curious about more case studies, make sure to checkout <a href="https://blogboard.io/more-like-this?articleId=19981143660456">articles similar to<strong> </strong><em>Optimizing DoorDash&#x2019;s Marketing Spend with Machine Learning</em></a></p><!--kg-card-begin: html--><div style="background-color: rgb(203 234 251 / 40%); padding: 2em 1em 1em; margin: 10px; width: 70%;">
<p style="text-align: center">Discover the best <a href="https://blogboard.io/topic/Machine%20Learning">Machine Learning</a> and <a href="https://blogboard.io/topic/Data%20Science">Data Science</a> articles from leading tech companies</p><p style="text-align: center"> <strong><a href="https://blogboard.io/search?searchQuery=data%20science">blogboard.io</a></strong></p>
</div>

    <!--kg-card-end: html--><p></p><p></p><p><strong><strong>&#x1F44B; </strong></strong>Liked the article? Let&apos;s get in touch - follow me on Twitter <strong><strong><a href="https://twitter.com/drazenxyz">@drazenxyz</a></strong></strong></p><p><br></p><p></p>]]></content:encoded></item><item><title><![CDATA[Designing Your Engineering Interview Process? Here's What You Need to Consider]]></title><description><![CDATA[If you simply take the standard format for the interviews, you could soon find yourself thinking about how to improve the process. You might find it slow and tedious; you could start seeing evaluations for the same candidate that widely differ or get negative feedback from candidates.]]></description><link>https://blogboard.io/blog/rethinking-engineering-interviews/</link><guid isPermaLink="false">5fe0a4c35e65844e7bbe85b5</guid><dc:creator><![CDATA[Drazen Zaric]]></dc:creator><pubDate>Wed, 23 Dec 2020 00:49:37 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1590945213328-ab2d0bbd1e88?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MXwxMTc3M3wwfDF8c2VhcmNofDM3fHxlbXB0eSUyMGNoYWlyfGVufDB8fHw&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=2000" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1590945213328-ab2d0bbd1e88?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MXwxMTc3M3wwfDF8c2VhcmNofDM3fHxlbXB0eSUyMGNoYWlyfGVufDB8fHw&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=2000" alt="Designing Your Engineering Interview Process? Here&apos;s What You Need to Consider"><p>On the surface, software engineering interviews look pretty much the same in any company. You usually have a phone call with a recruiter, followed by either a short technical round or a set of take home exercises. If you pass that you&apos;re invited for several rounds of on-site interviews, focusing on your technical abilities and behavioral cues that could predict your job performance and how you&apos;ll get along with the team.</p><p>However, if you simply take this format, pick a set of technical questions for the specific role and go with it, you could soon find yourself thinking about how to improve the process. You might find it slow and tedious for the interviewers; you could start seeing evaluations for the same candidate that widely differ depending on the interviewer; you could get feedback from the candidates that the process requires too much of a time investment for them.</p><p>In this post we&apos;ll summarize lessons shared on official engineering blogs of several companies. Namely, the advice falls down into three sections:</p><ol><li>Know what you are looking for</li><li>Be ready to iterate</li><li>Techniques to avoid bias</li></ol><p>If you&apos;re curious and want to find more stories about engineering interviews and hiring process, you should try <a href="https://blogboard.io/search?searchQuery=engineering%20interviews">Blogboard search</a>.</p><h2 id="know-what-you-are-looking-for">Know what you are looking for</h2><p>You want to hire an engineer, and you want to hire a great one. But the exact definition of &quot;great&quot; can depend on many factors, so a one-size-fits-all list of traits is unlikely to exist. </p><p>Are you a big company or a startup, what&apos;s the current state of the project and the team, are you hiring for a junior or a senior role? These are some of the obvious things to consider when thinking about the best fit for the role. Once you&apos;re clear on this you can work out the details and the exact qualities you&apos;re looking for in a candidate. Finally, all this will determine what you screen for and what your interview scorecards need to look like.</p><p>In a Lyft Engineering blog post <a href="https://eng.lyft.com/how-lyft-designs-the-machine-learning-software-engineering-interview-bbbb9fc8bb28">How Lyft Designs the Machine Learning Software Engineering Interview</a>, Hao Yi Ong states the following three questions to ask in order to understand what you actually want from a role you&apos;re hiring for:</p><blockquote>1. What are Lyft&#x2019;s challenges (and can a specific role help)?<br>2. What should the role be with respect to the organization&#x2019;s goals?<br>3. What are the desired skills, knowledge, and talents given the expectations for the role?</blockquote><p>Companies are more or less transparent about detailed requirements for the roles. The above-mentioned article briefly describes them as follows:</p><blockquote>Our desired talents are <em><em>recurring patterns of thought, feeling, and behavior that can be productively applied</em></em> in the context of Lyft&#x2019;s ML SWE role. What we&#x2019;re looking for here is a bit more complicated than simply work done in the past by a candidate. Faced with the same stimuli, people react and behave differently. When we look for role and values fit, we do mean just that. Beyond skills and knowledge, will a candidate&#x2019;s unique way of responding to the problems thrown up in Lyft&#x2019;s business context help that candidate succeed? So while conventional wisdom might suggest it, we&#x2019;re not always looking for the Michael Jordans of machine learning (be it I. or J.). The narrow sort of talents associated with celebrated excellence can be important but in most cases the interviewers are listening for predictive clues of how a candidate will react when posed Lyft-specific problems on the job.</blockquote><p>Speaking about high level qualities of successful engineers, here&apos;s what Ted Tomlinson of Databricks shares in his article <a href="https://databricks.com/blog/2020/01/22/engineering-intervews-a-hiring-managers-guide.html">Engineering Interviews &#x2014; A Hiring Manager&#x2019;s Guide to Standing Out</a>:</p><blockquote>At a startup like Databricks, the most important quality I&#x2019;ve seen in successful engineers is ownership. We are growing quickly, which brings a lot of new challenges every week, but it&#x2019;s not always clear how responsibilities divide across teams and priorities get determined. Great engineers handle this ambiguity by surfacing the most impactful problems to work on, not just those limited to their current team&#x2019;s responsibilities. Sometimes this means directly helping to build the solution, but often it&#x2019;s motivating others to prioritize the work.<br><br>The second quality we focus on, particularly for those earlier in their career, is the ability to learn and grow. The derivative of knowledge is often more important than a candidate&#x2019;s current technical skills. Many of the engineering problems we are solving don&#x2019;t have existing templates to follow. That means continually breaking through layers of abstraction to consider the larger system &#x2013; from the lowest level of cpu instructions, up to how visualizations are rendered in the browser.</blockquote><p>Going back to tailoring the requirements to the needs of your company, notice that Ted points out that <em>ownership</em> is <em>the most important quality at a startup like Databricks, </em>suggesting that wouldn&apos;t necessarily be equally important at a different place.</p><p>Once you&apos;ve figured out the qualities you&apos;re looking for, you can go deeper and break them down into fine-grained categories that you can actually screen for in an interview. Medium Engineering shares a great example of how this can be done. In <a href="https://medium.engineering/engineering-interviews-what-we-screen-for-af2d84122417">Engineering interviews: what we screen for</a>, Jamie Talbot explains how at Medium they&apos;re looking for three things: (1) Can they build software? (2) Can they learn and teach? (3) Are they aligned with our values?</p><p>Each of these high level requirements is then broken down into six sub-categories. For example <em>ability to build software </em>covers the following categories:</p><ul><li>Problem solving</li><li>Code fluency</li><li>Autonomy</li><li>Basic computer science knowledge</li><li>System design</li><li>Resoluteness</li></ul><p>If you&apos;re curious, each capability is described in detail in the <a href="https://medium.engineering/engineering-interviews-what-we-screen-for-af2d84122417">blog post</a>. In addition to that, the team at Medium devised a detailed grading guideline for each category, helping interviewers decide on the scale of <em>Strong No &gt; No &gt; Mixed &gt; Yes &gt; Strong Yes. </em>They describe it in another article <a href="https://medium.engineering/engineering-interviews-grading-rubric-8b409bec021f">here</a>.</p><p>With any problem, hiring being no exception, it helps to know why you&apos;re doing it and what your environment and constraints are. Only then you can come up with creative and more effective solutions.</p><p>Speaking of constraints, they&apos;re likely to change over time, rendering your existing interview process inefficient.</p><h2 id="be-ready-to-iterate">Be ready to iterate</h2><p>There&apos;s several reasons for being flexible and ready to adapt your technical interview process. </p><p>In the previous part we discussed how you need to tailor your interviews to fit your company, project and team needs. Inevitably, these things will change over time, and with that your interview process will likely need to change as well.</p><p>On that note, when reading through company blogs a recurring theme is <em>redesign</em> of the interview process. It usually happens because circumstances change, but often (as with any process) you can find room for improvement even when the environment hasn&apos;t changed much. </p><p>At Medium they noticed more than a few things they thought need improvement. As elaborated in <a href="https://medium.engineering/engineering-interviews-refining-our-process-52fbc9510e91">Engineering interviews: refining our process</a> they wanted to address lack of clarity in capability requirements, inconsistencies in candidate evaluation, which traits are considered important and which less so, how they approach personality traits and non-technical qualities.</p><p>At The New York Times, they recognized the need to standardize the hiring process across the company, as it&apos;s recognized to be the key determining factor for the culture. One of the things where a consolidated interview process helped is increased trust for internal mobility. Due to lack of trust among teams, it could happen that an engineer would be required to pass a technical interview if they were to change teams. You can read about this on the NYT Open, the official behind-the-scenes blog of The New York Times (namely these two articles: <a href="https://open.nytimes.com/how-we-designed-our-front-end-engineer-hiring-process-9b8f20cc31fb">How We Designed Our Front-End Engineer Hiring Process</a>, <a href="https://open.nytimes.com/how-we-hire-front-end-engineers-at-the-new-york-times-e1294ea8e3f8">How We Hire Front-End Engineers at The New York Times</a>).</p><p>In <a href="https://slack.engineering/refactoring-backend-engineering-hiring-at-slack/">Refactoring Backend Engineering Hiring at Slack</a>, Slack engineers share the story of why and how they optimized the take-home exercise. Although it had many points in its favor, the exercise was a bottleneck in their hiring process. Candidates, wanting to show off the best of their skills, would take too much time to complete the exercise. Slack, on the other hand, was in state of rapid growth and the projected time for staffing all the necessary positions simply was too long:</p><blockquote>The end result was that, by our estimates, it would have taken a year to fill our existing open headcount, future growth aside. This timeframe clearly would not allow us to grow at the speed we needed. However, we were also unwilling to sacrifice quality. We needed an approach that would give us good signal and help us hire great engineers, but at a reduced time cost to the candidate and to us. <br><br>To satisfy these needs, we decided to create two new take-home exercises: an API design exercise and a code review exercise. In creating these exercises, we sought to create a problem that was not an onerous time investment on the part of the candidate. We wanted something that would give us good signal on the attributes we cared about while taking at most two hours to complete.</blockquote><p>Finally, the team at Slack came up with a new format for the challenge as well as internal apps and GitHub automations to streamline the process, resulting in significant measurable improvement:</p><blockquote>In the end, we saw tangible improvements against our goals. We saw a decrease in our time-to-hire&#x200A;&#x2014;&#x200A;the time from when a recruiter first reaches out, to the candidate&#x2019;s first day in the office. The time-to-hire metric decreased from an average of 200 days to below 83 days&#x200A;&#x2014;&#x200A;and it continues to drop. We&#x2019;ve seen positive feedback from candidates and employees in all parts of the process.</blockquote><p>At Soundcloud, the team attacked the same part of the interview funnel - the take-home exercise, since they noticed it often takes far too long to complete it. As they point out <a href="https://developers.soundcloud.com/blog/rethinking-the-backend-code-challenge#fnref-1">in this article</a>, there&apos;s a very subtle reason to be careful about time investment on the candidate side:</p><blockquote>Many great candidates have good jobs and busy personal lives. We want to talk to as many qualified candidates as possible, but to do that, we need to minimize the chances that our interview process itself gets in the way.</blockquote><p>So not only does a tedious process slow down your hiring, it might cause the best candidates to simply give up because they&apos;re already too busy.</p><h2 id="how-to-avoid-bias-and-variance">How to avoid bias and variance?</h2><p>It&apos;s no secret that interviewers can easily fall victim to all sorts of biases. A good first impression can make you give better score to a candidate&apos;s technical abilities than you might do otherwise.</p><p>In <a href="https://hbr.org/2017/06/7-practical-ways-to-reduce-bias-in-your-hiring-process">7 Practical Ways to Reduce Bias in Your Hiring Process</a>, Rebecca Knight outlines the ways in which bias can hurt your hiring and offers several ways to overcome this inherently human problem:</p><blockquote>Unconscious biases have a critical and &#x201C;problematic&#x201D; effect on our judgment, says Francesca Gino, professor at Harvard Business School. &#x201C;They cause us to make decisions in favor of one person or group to the detriment of others.&#x201D; In the workplace, this &#x201C;can stymie diversity, recruiting, promotion, and retention efforts.&#x201D;</blockquote><p>In more concrete terms, Medium Engineering team <a href="https://medium.engineering/engineering-interviews-what-we-dont-screen-for-4381cfdfa703">share their means</a> for fighting bias by standardizing the hiring process. As described in the first section, they&apos;ve laid out in detail all the qualities they&apos;re seeking, as well as those they don&apos;t find predictive of work performance, such as school, GPA, previous employments, open source contributions. And not only they&apos;re not good predictors of the performance, they&apos;re the usual suspects of causing unconscious biases. Having identified these categories, interviewers then avoid penalizing anyone based on these criteria. You can read about this in <a href="https://medium.engineering/engineering-interviews-what-we-dont-screen-for-4381cfdfa703">Engineering interviews: what we don&#x2019;t screen for</a>. </p><p>Having <a href="https://medium.engineering/engineering-interviews-grading-rubric-8b409bec021f">clearly defined qualities and grading rubrics</a> helps interviewers standardize evaluation and decisions across interviewers and candidates. This helps eliminate both bias and variance in the process. Simply put, eliminating bias will make sure that a single interviewer will evaluate equally two candidates with the same skillset. On the other hand, you want to eliminate the variance among interviewers t00, so that a candidate would be evaluated the same regardless of who interviews them.</p><p>Writing about their take-home test in <a href="https://www.intercom.com/blog/engineer-interview-assignments/">How to prepare for engineering interview assignments</a>, Intercom engineers Lorcan Coyle and Alex Mooney point out that at this first stage of the technical interview they don&apos;t care about anything but the solution itself:</p><blockquote>Unconscious bias is a well-researched problem in our field, and it&#x2019;s important for reviewers to eliminate as many potential sources of bias as possible. It&#x2019;s crucial to be clear about what we&#x2019;re looking for when reviewing an interview assignment, and it&#x2019;s just as important to know what we&#x2019;re not looking for. When assessing a technical submission, we don&#x2019;t care about:<br><br>- The candidate&#x2019;s experience level.<br>- The position they are applying for.<br>- Their CV or professional history.<br><br>None of these details are relevant at this stage. All we assess is the take-home test itself &#x2013; we only care about your code!</blockquote><p>At Slack, <a href="https://slack.engineering/refactoring-backend-engineering-hiring-at-slack/">they automate parts of the take-home task review</a> so that a script converts a GitHub pull request into an anonymized markdown file, ensuring that graders are unaware of the candidate&apos;s identity on GitHub.</p><p>Finally, at the New York Times, the engineering team makes sure that at each step of the process a candidate is evaluated by multiple interviewers in order to prevent blind spots. They&apos;ve tried anonymized resume reviews, where you look at a resume with some fields removed, such as the identity of the candidate and names of their previous employers. They share their thoughts on this in <a href="https://open.nytimes.com/how-we-designed-our-front-end-engineer-hiring-process-9b8f20cc31fb">How We Designed Our Front-End Engineer Hiring Process</a>.</p><hr><p>Dig deeper with Blogboard search:</p><blockquote><a href="https://blogboard.io/search?searchQuery=engineering%20interviews">Engineering interviews</a></blockquote><blockquote><a href="https://blogboard.io/search?searchQuery=technical%20interviews">Technical interviews</a></blockquote><blockquote><a href="https://blogboard.io/search?searchQuery=hiring%20engineers">Hiring engineers</a></blockquote><!--kg-card-begin: html--><p style="background-color: rgb(203 234 251 / 40%); padding: 2.5em 1em;"><strong><a href="https://blogboard.io">blogboard.io</a> </strong>-<strong> </strong>Engineering blogs from top tech companies. Search, discover, follow.</p>

    <!--kg-card-end: html--><p></p>]]></content:encoded></item><item><title><![CDATA[Code Review Best Practices - Lessons from the Trenches]]></title><description><![CDATA[In this article we'll go over learnings shared by engineers from companies such as PayPal, Palantir, Medium, Shopify. Why do code reviews and how they help your team develop?]]></description><link>https://blogboard.io/blog/code-review-best-practices/</link><guid isPermaLink="false">5fce4c02d0e7864c1fa21f29</guid><dc:creator><![CDATA[Drazen Zaric]]></dc:creator><pubDate>Mon, 07 Dec 2020 16:22:29 GMT</pubDate><media:content url="https://blogboard.io/blog/content/images/2021/08/markus-spiske-cvBBO4PzWPg-unsplash.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blogboard.io/blog/content/images/2021/08/markus-spiske-cvBBO4PzWPg-unsplash.jpg" alt="Code Review Best Practices - Lessons from the Trenches"><p>There&apos;s a ton of resources scattered around the web dealing with code review fundamentals, best practices, tools, etc. In this article we&apos;ll summarize the lessons from a dozen of official company engineering blogs. You can find links to the original articles in <a href="http://localhost:8080/blog/code-reviews"><a href="https://blogboard.io/search?searchQuery=code%20review">this blogboard search</a></a>.</p><h2 id="what-s-in-this-article">What&apos;s in this article?</h2><p>We&apos;ll cover several topics:</p><ol><li>Why do code reviews?<br>Besides the obvious, quality assurance, there are other benefits to code reviews</li><li>Code reviews as quality assurance<br>We&apos;ll cover the general recommendations on what to look for in a code review, why having a review checklist is beneficial, and you&apos;ll get a fairly long checklist that you can use as a base for your own list</li><li>Code reviews as a team improvement tool<br>If you&apos;ve done more than a few code reviews, you know they&apos;re useful for more than just preventing bugs. We&apos;ll summarize common views on how reviews are beneficial as a learning and team bonding tool</li><li>Preparing a pull request for review<br>Lessons for pull request authors. There are rules of thumb consistently pointed out that help to prepare a PR for a smooth review</li><li>Reviewing code - Be human!<br>Lessons for reviewers on how wording and tone of your comments can make a huge difference in effectiveness of the whole review effort.</li></ol><p>The topics are covered fairly independently, so if you&apos;re curious about a particular topic feel free to skip ahead.</p><h2 id="why-do-code-reviews">Why do code reviews?</h2><p>It should be obvious that the primary purpose of code review is to assess quality of the changes being introduced. I mean, the dictionary definition of <em>review </em>says precisely that</p><blockquote><strong>review</strong> <em>(noun) - </em>a formal assessment of something with the intention of instituting change if necessary.</blockquote><p>Of course, code being code, there&apos;s a lot of things that can be checked and tested automatically, so there&apos;s nuance to what actually needs to be checked in an actual code review. We cover that in the next section.</p><p>On the other hand, code review is a form of communication between the <em><strong>author</strong> </em>of the change (these days usually <em>a pull request</em>) and one or several <em><strong>reviewers</strong>. </em>So it has side effects that go beyond preventing bugs from slipping in or keeping the codebase consistent in terms of style and architecture. </p><p>When done well, code reviews help accelerate learning across the team, create psychological safety for all team members, help establish and communicate best practices, teach proper communication and improve team dynamics. When done poorly, they can help deteriorate all of the above.</p><h2 id="code-reviews-as-quality-assurance">Code reviews as quality assurance </h2><p>There are a bunch of ways in which code reviews help maintain the quality bar for the codebase and the product. In the end it comes down to catching mistakes at the level which can hardly be automatically tested, such as architectural inconsistencies. Also, the code for automated tests should be reviewed, so there&apos;s a meta level at which reviews help with QA. </p><p>In <a href="https://engineering.gusto.com/high-leverage-code-reviews/">Giving High Leverage Code Reviews</a>, Casey Rollins advocates for having a checklist with all the usual things that need attention. </p><blockquote>When I&#x2019;m reviewing a pull request, I often do multiple &#x201C;passes&#x201D; where I focus on one attribute at a time. I start at the beginning and review the pull request with a single attribute in mind before moving on to the next. When I&#x2019;ve worked through the checklist, I submit the review.<br><br>This checklist moves from general to specific checks because it&#x2019;s important to focus on the high-level attributes first. It doesn&#x2019;t make sense to offer a variable name suggestion if you&#x2019;re also suggesting that an entire class or function be refactored.</blockquote><p>You can have your own checklist or make it a shared list for the team or a project. There&apos;s a ton of material written on the usefulness of checklists. In <em><a href="https://en.wikipedia.org/wiki/Getting_Things_Done">Getting Things Done</a>, </em>David Allen puts forward a simple idea -<em> </em>our minds are great at processing information, but terrible at storing and recalling it. That&apos;s why checklists are a great way of externally storing and breaking down a planned or repetitive task.</p><p>Compiled from several articles (<a href="https://medium.com/paypal-engineering/effective-code-reviews-53d62a203b2f">1</a>, <a href="https://engineering.gusto.com/high-leverage-code-reviews/">2</a>, <a href="https://medium.com/palantir/code-review-best-practices-19e02780015f">3</a>) here&apos;s a high-level list of things to be concerned about when reviewing a code change:</p><ul><li>Story alignment - does the change meet the requirements of the task at all; ie. does the code implement any and all of the specified functionalities?</li><li>Consistency across the codebase</li><li>Architectural considerations - how does the new piece of code fit the existing architecture. Can the new feature architecture be improved, is it too generic or not extensible enough?</li><li>Simplicity/over-engineering</li><li>Performance concerns - are there specific cases (eg. peak load times) when the code will break? Do the queries pull more data than necessary? Could new queries benefit from adding new indexes to the database?</li><li>Accidental errors such as typos or errors in math formulas - these can be either obvious or really tricky to notice, especially with math heavy code</li><li>Compliance with laws and regulations - depending on the business this might be the most important thing</li><li>Security concerns - are there any exploitable pieces of code being introduced? Are any secrets being shared or stored unsafely?</li><li>Readability and style - a seemingly perfect piece of code might not be immediately understandable and readable to a different pair of eyes. Is it possible to understand the changes without the author explaining them?</li><li>Best practices - programming languages usually have their best practices - are they met in the pull request? Also, with time any project, team and company will evolve their own set of best practices - code reviews are a way to enforce and spread knowledge about them</li><li>Localization - are all language dependent resources localized properly?</li><li>Dependencies - are there external libraries or APIs being introduced? Are there other simpler/faster/better ways to do this with different dependencies or without any?</li><li>Interactions and side effects - how does the new piece of code interact with the rest of the codebase; does the new function implementation break any existing functionality; are all relevant unit tests updated/added</li><li>Logging - it&apos;s practically impossible to debug server code properly without good logging. Is everything logged/traced correctly</li><li>Error handling - how are the errors handled on the backend; how are they communicated to the user; are fallbacks activated where possible?</li><li>Testability/Test coverage - is the new piece of code covered with automated tests? Have all the suspicious test cases been checked either automatically or manually? Is the code written in a way that&apos;s suitable for unit testing?</li><li>External documentation - in case it&apos;s necessary is the external documentation updated to reflect the change?</li></ul><p>It&apos;s a pretty long list. In addition to it, a recurring piece of advice is not to use code reviews in place of static code analysis tools. If your review is mostly about code formatting, variable naming and alphabetical ordering, it might be a good time to include an automated code analysis tool into your development workflow.</p><h2 id="code-reviews-as-a-team-improvement-tool">Code reviews as a team improvement tool</h2><p>In <em><a href="https://medium.com/paypal-engineering/effective-code-reviews-53d62a203b2f">Effective Code Reviews: Bettering Products, Teams, and Engineers</a> </em>from PayPal engineering<em>, </em>Gabriel McAdams points out several important benefits of code reviews related to team dynamics:</p><ul><li>Team cohesion - by making everyone&apos;s code subject to peer review, code review process promotes <em>individual accountability, healthy conflict</em> and the idea that everyone&apos;s<em> working together</em> to make the product better. As said in <a href="https://medium.com/palantir/code-review-best-practices-19e02780015f">Code Review Best Practices</a>: <em>Code reviews are classless: being the most senior person on the team does not imply that your code does not need review.</em><br>In summary, McAdams puts it nicely: <em>Trust + healthy conflict + individual accountability + working together to better the team = team cohesion.</em></li><li>Free career improvement training - simply by virtue of reviewing other people&apos;s code you become more skilled at reading and understanding new code. I&apos;ve heard it said that one of the foremost traits of great engineers is the ability to dive into and dissect a completely unfamiliar piece of code. Over time you learn how to spot common practices, little tricks, pieces of syntactic sugar, architectural abstractions and how to appreciate different mental models used to solve the same problem.</li></ul><p>In <a href="https://medium.com/palantir/code-review-best-practices-19e02780015f">Code Review Best Practices</a> from the Palantir Blog, Robert Fink lists several ways in which knowledge sharing and social side-effects happen via code reviews:</p><ul><li>Authors are motivated by the peer review process to do all the necessary pre-checks, tighten the loose ends and generally tidy up the code before sending to review</li><li>A code review explicitly communicates changes made to product functionality to team members</li><li>The author maybe used a technique, abstraction or an algorithm that reviewers are unfamiliar with. The opposite can also be the case - reviewers might be aware of a more appropriate way to solve a given problem</li><li>Positive communication strengthens social bonds within the team (might especially be true for remote teams)</li></ul><h2 id="preparing-a-pull-request-for-review-help-the-reviewer">Preparing a pull request for review - help the reviewer</h2><p>Code reviews should be seen as a team effort. Once you view them that way it becomes clear that both sides - the author and the reviewers - have their distinct sets of responsibilities.</p><p>In <a href="https://medium.engineering/the-code-review-mindset-3280a4af0a89">this short post</a> on Medium Engineering blog, Xiao Ma describes how a different perspective changes the way code reviews are done, how feedback is taken and how people on each side benefit by adopting a <em>positive mindset</em> about code reviews.</p><p>When we talk about the responsibilities of the pull request author, there are several key things recurring in all code review guides.</p><ol><li><strong>Make pull requests as atomic as possible</strong><br><a href="https://shopify.engineering/great-code-reviews">At Shopify</a> they advise to keep <em>your pull requests small </em>- it helps the reviewer dive into it and finish it as an atomic piece of work in their workday. In practice this can mean keeping your pull requests limited to <em>a single concern. </em>A single concern here means a single bug fix, a feature, an API change etc. Don&apos;t mix refactoring that doesn&apos;t alter behavior with bug fixes or new features. This is beneficial both for the ease of doing the code review but also helps keep the codebase maintainable (for example, atomic pull requests are easier to rollback). <br>You can find practically the same advice in posts from <a href="https://kickstarter.engineering/a-guide-to-mindful-communication-in-code-reviews-48aab5282e5e">Kickstarter Engineering</a>, <a href="https://engineering.gusto.com/high-leverage-code-reviews/">Gusto Engineering</a> and <a href="https://medium.com/palantir/code-review-best-practices-19e02780015f">Palantir</a>.</li><li><strong>Provide a helpful pull request description</strong><br><em>&quot;Give your reviewers a map&quot;.</em> &#xA0;It&apos;s true that you should pick the teammates that are the most familiar with the part of code you&apos;ve changed. But even a few sentences describing why/what/where of the pull request can greatly help the reviewer to navigate your pull request. </li><li><strong>Test before review</strong><br>Make sure you&apos;ve reviewed and tested the pull request before submitting for review. You want to make sure that all relevant files are included, that the PR passes the build and automated tests, that all suggestions from automated review tools are addressed.</li></ol><h2 id="reviewing-code-be-human-">Reviewing code - Be Human!</h2><p>The most frequently recurring piece of advice, and perhaps the least obvious, is the importance of the tone of communication in code reviews.</p><p>In a Kickstarter Engineering article <a href="https://kickstarter.engineering/a-guide-to-mindful-communication-in-code-reviews-48aab5282e5e">A Guide to Mindful Communication in Code Reviews</a>, Amy Ciavolino lists many tips for improving communication on both sides of a code review. In Amy&apos;s words: <em>&quot;Technical skills are needed to review code thoroughly and quickly. But beyond that, reviewing code is also a form of communication, teaching, and learning. Either as the author or the reviewer of code, being mindful in your communications can make code reviews more valuable for everyone.&quot;</em></p><p>The article contains tips on how to be mindful of the author and the purpose of the process when doing the review:</p><ul><li>Don&apos;t jump to conclusions, ask questions - assume the author knew what they were doing even when it seems completely wrong at first sight</li><li>No nitpicking - the fact that you are noticing tiny things like formatting inconsistencies is likely a sign you should consider using a linter on your project. In <a href="https://engineering.gusto.com/high-leverage-code-reviews/">Giving High Leverage Code Reviews</a>, Casey Rollins links nitpicking to the phenomenon of <em><a href="http://bikeshed.com/">bikeshedding</a> (</em>or<em> <a href="https://en.wikipedia.org/wiki/Law_of_triviality">Parkinson&apos;s Law of triviality</a>). </em>Long story short - just because it&apos;s easy to spot tiny mistakes doesn&apos;t mean that you have to insist on them being fixed. Be mindful and pragmatic.</li><li>Be biased towards approving; make it clear if something can be fixed later - as a reviewer you&apos;re not necessarily a gatekeeper with the power to block any pull request. Maybe an architectural concern or a far-in-future problem can be addressed in the next sprint, while pushing the fix to production as soon as possible.</li><li>Include example code or documentation - especially if you&apos;ve looked it up anyway. An important point is that by acknowledging that you needed to look something up can help junior members with <a href="https://en.wikipedia.org/wiki/Impostor_syndrome"><em>impostor syndrome</em></a><em>.</em></li></ul><h3 id="wording-makes-a-world-of-difference">Wording makes a world of difference</h3><p>A bug is a bug, a typo is a typo and there&apos;s no way around it. But even if it&apos;s an obvious mistake, there are often multiple ways to deliver the message. A code review ridden with comments like <em>This is duplicate; Fix this...; Feels slow. Make it faster; Read the style guidelines </em>can come as too harsh no matter who the author is.</p><p>This is nicely pointed out in <a href="https://engineering.gusto.com/high-leverage-code-reviews/">Giving High Leverage Code Reviews</a>:</p><blockquote><em>At the core of a code review, you&#x2019;re providing feedback to your peers, which might be hard. But receiving feedback is harder. Everyone on your team is trying to do their best work, so take care in delivering your message. For example, if you&#x2019;re pointing out an error or asking a question, make it a team effort, not their fault. This might look like: &#x201C;Can we remove some of the duplication in this file?&#x201D; instead of &#x201C;You missed an edge case&#x201D;.</em></blockquote><p>Alejandro Lujan Toro <a href="https://shopify.engineering/great-code-reviews">offers several practical examples</a> of harsh comments that you can easily change to a more constructive tone:</p><!--kg-card-begin: html--><table width="100%" style="box-sizing: border-box; border-collapse: collapse; color: rgb(33, 35, 38); "><tbody style="box-sizing: border-box;"><tr style="box-sizing: border-box;"><td style="box-sizing: border-box; border: 1px solid rgb(66, 71, 76); padding: 16px; width: 223px;"><strong style="box-sizing: border-box;">Less of These</strong></td><td style="box-sizing: border-box; border: 1px solid rgb(66, 71, 76); padding: 16px; width: 458px;"><strong style="box-sizing: border-box;">&#xA0;More of These</strong></td></tr><tr style="box-sizing: border-box;"><td style="box-sizing: border-box; border: 1px solid rgb(66, 71, 76); padding: 16px; width: 223px;"><div style="box-sizing: border-box;"></div>Move this to Markdown</td><td style="box-sizing: border-box; border: 1px solid rgb(66, 71, 76); padding: 16px; width: 458px;"><div style="box-sizing: border-box;"></div>How about moving this documentation into our Markdown README file? That way we can more easily share with other users.<strong style="box-sizing: border-box;"></strong></td></tr><tr style="box-sizing: border-box;"><td style="box-sizing: border-box; border: 1px solid rgb(66, 71, 76); padding: 16px; width: 223px;"><div style="box-sizing: border-box;"></div>Read the Google Python style guidelines</td><td style="box-sizing: border-box; border: 1px solid rgb(66, 71, 76); padding: 16px; width: 458px;"><div style="box-sizing: border-box;"></div>We should avoid single-character variables. How about board_size or size instead?</td></tr><tr style="box-sizing: border-box;"><td style="box-sizing: border-box; border: 1px solid rgb(66, 71, 76); padding: 16px; width: 223px;"><div style="box-sizing: border-box;"></div>This feels too slow. Make it faster. Lightning fast.</td><td style="box-sizing: border-box; border: 1px solid rgb(66, 71, 76); padding: 16px; width: 458px;">&#xA0;This algorithm is very easy to read but I&#x2019;m concerned about performance. Let&#x2019;s test this with a large dataset to gauge its efficiency.</td></tr><tr style="box-sizing: border-box;"><td style="box-sizing: border-box; border: 1px solid rgb(66, 71, 76); padding: 16px; width: 223px;"><div style="box-sizing: border-box;"></div>Bool or int?</td><td style="box-sizing: border-box; border: 1px solid rgb(66, 71, 76); padding: 16px; width: 458px;"><div style="box-sizing: border-box;"></div>Why did you choose a list of bool values instead of integers?</td></tr></tbody></table><!--kg-card-end: html--><p>The trick is to approach code reviews as a team effort. Try to use more <em>we</em> instead of <em>you</em> when suggesting changes. <a href="https://kickstarter.engineering/a-guide-to-mindful-communication-in-code-reviews-48aab5282e5e">Amy Ciavolino suggests</a> that you shouldn&apos;t even start reviewing if you&apos;re not in the right mood to give considerate feedback:</p><blockquote><em>When you&#x2019;re checking in, also consider how you&#x2019;re feeling in general. Giving kind and considered feedback takes time and energy. If you&#x2019;re hungry, tired, in a hurry, have a lot of meetings, etc., don&#x2019;t review code or send out a review. You need to fix those things first. If you don&#x2019;t care for yourself, you can&#x2019;t take care of others.</em></blockquote><p><strong>Don&apos;t forget to give praise!</strong></p><p>Once you realize that code reviews are not simply about finding bugs, this should come naturally. Maybe you&apos;ve learned something from the pull request, or the author has invested a great effort and showed impressive attention to detail. Let them know that.</p><p>Giving praise in code reviews is especially important with newcomers. In <a href="https://stackoverflow.blog/2019/09/30/how-to-make-good-code-reviews-better/">How to Make Good Code Reviews Better</a>, Gergely Orosz suggests that code reviews need to be a <em>positive experience</em> for a newcomer:</p><blockquote><em><strong>Better code reviews</strong> pay additional attention to making the first few reviews for new joiners a great experience. Reviewers are empathetic to the fact that the recent joiner might not be aware of all the coding guidelines and might be unfamiliar with parts of the code. These reviews put additional effort into explaining alternative approaches and pointing to guides. They are also very positive in tone, celebrating the first few changes to the codebase that the author is suggesting.</em></blockquote><hr><!--kg-card-begin: html--><p style="background-color: rgb(203 234 251 / 40%); padding: 2.5em 1em;"><strong><a href="https://blogboard.io">blogboard.io</a> </strong>-<strong> </strong>Engineering blogs from top tech companies. Search, discover, follow.</p>

    <!--kg-card-end: html--><p></p><p><strong>&#x1F44B; </strong>Liked the article? Let&apos;s get in touch - follow me on Twitter <strong><a href="https://twitter.com/drazenxyz">@drazenxyz</a> </strong></p>]]></content:encoded></item></channel></rss>