<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Adrien TRAUTH</title>
    <description>The latest articles on Forem by Adrien TRAUTH (@nioufe).</description>
    <link>https://forem.com/nioufe</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F183691%2Fe09d1413-8173-46e5-884f-83680ca44675.jpeg</url>
      <title>Forem: Adrien TRAUTH</title>
      <link>https://forem.com/nioufe</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/nioufe"/>
    <language>en</language>
    <item>
      <title>You should not use lodash for memoization</title>
      <dc:creator>Adrien TRAUTH</dc:creator>
      <pubDate>Fri, 26 Jul 2019 14:18:20 +0000</pubDate>
      <link>https://forem.com/nioufe/you-should-not-use-lodash-for-memoization-3441</link>
      <guid>https://forem.com/nioufe/you-should-not-use-lodash-for-memoization-3441</guid>
      <description>&lt;p&gt;A few days ago, I tracked down a bug causing a react component to never update. Debugging showed that the cause was the &lt;code&gt;memoize&lt;/code&gt; function of lodash.&lt;/p&gt;


&lt;div class="runkit-element"&gt;
  &lt;code&gt;
    


  &lt;/code&gt;
  &lt;code&gt;
    
const lodash = require('lodash');

const add = function(a, b){return a + b};
const memoizedAdd = lodash.memoize(add);

console.log('1 + 1 = 1 + 2', memoizedAdd(1,2) === memoizedAdd(1,1));

  &lt;/code&gt;
&lt;/div&gt;
This is not really what I expected
 



&lt;p&gt;In frontend projects we use memoization for different optimizations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Avoid component rendering - &lt;code&gt;React.memo&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Avoid re-computing internal component state - &lt;code&gt;useMemo&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Avoid re-computing information derived from the redux state - &lt;code&gt;createSelector&lt;/code&gt; from reselect&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The goal is always the same: do not redo an expensive computation if inputs are the same as the previous call. It is faster to just return the last computed result directly. &lt;a href="https://en.wikipedia.org/wiki/Memoization"&gt;More about memoization on Wikipedia&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Using memoize in a react app
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;useMemo&lt;/code&gt;, &lt;code&gt;React.memo&lt;/code&gt;, and &lt;code&gt;createSelector&lt;/code&gt; are usually enough for all your memoization needs. However hooks don't work in &lt;em&gt;class components&lt;/em&gt;. If you still have some in your codebase, you need a custom memoization function to replicate the functionality of &lt;code&gt;useMemo&lt;/code&gt;. One implementation is described in the &lt;a href="https://reactjs.org/blog/2018/06/07/you-probably-dont-need-derived-state.html#what-about-memoization"&gt;react docs&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// function component with memoization&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ComponentWithMemo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nx"&gt;propA&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;propB&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;memoizedValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useMemo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;computeExpensiveValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;propA&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;propB&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; 
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;propA&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;propB&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;memoizedValue&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="c1"&gt;//class component with memoization&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;memoize&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;memoize-one&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;ComponentWithMemo&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="c1"&gt;// Need to define a memoized function in the component&lt;/span&gt;
   &lt;span class="nx"&gt;memoizedCompute&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;memoize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;computeExpensiveValue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

   &lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;propA&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;propB&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
       &lt;span class="c1"&gt;// and call it on render&lt;/span&gt;
       &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;memoizedValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;memoizedCompute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;propA&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;propB&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
       &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;memoizedValue&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
2 implementations of memoize to avoid re-computing on render




&lt;p&gt;Lodash being very common, using &lt;code&gt;lodash/memoize&lt;/code&gt; seems like a good option to implement the pattern without adding (yet) another dependency.  &lt;/p&gt;
&lt;h2&gt;
  
  
  Problem 1: Lodash uses only the first parameter
&lt;/h2&gt;

&lt;p&gt;Here is how the first example is interpreted by lodash internally:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;memoizedAdd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;memoize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;add&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// cache = {}&lt;/span&gt;
&lt;span class="nx"&gt;memoizedAdd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// cache[1] = 2; return 2;&lt;/span&gt;
&lt;span class="nx"&gt;memoizedAdd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// return cache[1]; &amp;lt;== My :bug: is here&lt;/span&gt;
&lt;span class="nx"&gt;memoizedAdd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// cache[2] = 3; return 3;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
Step-by-step of the memoized add example




&lt;p&gt;This happens because the memoize function from lodash is only using the first parameter as a cache key by default. So, as long as the same first parameter is passed, the function always returns the same result. &lt;/p&gt;

&lt;p&gt;On the other side, &lt;code&gt;memoize-one&lt;/code&gt; and the other implementations running in &lt;code&gt;react&lt;/code&gt; or &lt;code&gt;reselect&lt;/code&gt; re-compute the function when any parameter is changed, thus it always returns the right result. &lt;/p&gt;

&lt;p&gt;The problem is not caused by a lodash behavior being undocumented. In fact the documentation states clearly that they're using the first parameter as a cache key. The root cause of those errors is that it's &lt;strong&gt;very different from the other implementations&lt;/strong&gt; that often live in the same project and are supposed to provide the same functionality. &lt;/p&gt;
&lt;h2&gt;
  
  
  Problem 2: You don't need an unlimited cache
&lt;/h2&gt;

&lt;p&gt;While the first difference may lead to visible bugs, this one may affect performances. This is usually hard to detect but it can have a big impact on the user experience. &lt;/p&gt;


&lt;div class="runkit-element"&gt;
  &lt;code&gt;
    
//
const lodash = require('lodash');

const add = function(a, b){return a + b};
const lodashAdd = lodash.memoize(add);

  &lt;/code&gt;
  &lt;code&gt;
    
// use the memoized add 1000 times

for(let i = 0; i&amp;lt;1000; i++){
    lodashAdd(i,2);
}

console.log('lodash cache size: ', lodashAdd.cache.size);

  &lt;/code&gt;
&lt;/div&gt;



&lt;p&gt;Running the memoized functions 1000 times saves 1000 results in the cache. Does that mean that memoize is a good cache? Kind of. But this is not what we need from a memoize function.&lt;/p&gt;

&lt;p&gt;Lodash uses a &lt;code&gt;Map&lt;/code&gt; to cache all function results associated with a key.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// from https://github.com/lodash/lodash/blob/master/memoize.js&lt;/span&gt;
&lt;span class="nx"&gt;memoized&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cache&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;cache&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="nx"&gt;memoize&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Cache&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Map&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This means that ALL keys and return values will be saved (by default) &lt;em&gt;forever&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;If you don't have a lot of different keys, you won't see the difference. If you are using unique IDs, this can become problematic. Memory leaks are hard to track as they may only happen in specific use cases like a page that stays open for a long time. Using a cache that by default can create leaks is thus not recommended.&lt;/p&gt;

&lt;p&gt;You could configure lodash cache to limit the number of saved values. I would argue that in a frontend application &lt;strong&gt;the best limit for a memoize cache is just one value: the latest computed one&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Memoization is used to avoid recomputing expensive things and make rendering faster. But the bottleneck is not recomputing just one thing. Performance issues happen when an application recomputes every expensive operation on every change. &lt;/p&gt;

&lt;p&gt;Memoization with a cache containing just the last value allows your application to only do the few expensive computations that are impacted by a change. This should be enough in most cases.  &lt;/p&gt;

&lt;p&gt;Note: If you have expensive operations that are too slow to be done even once, then memoization is not the right tool to solve that problem anyway. &lt;/p&gt;

&lt;h2&gt;
  
  
  Postmortem: lodash/memoize is no more
&lt;/h2&gt;

&lt;p&gt;The first option to fix the bug is to configure lodash memoize to match the &lt;code&gt;react&lt;/code&gt;, &lt;code&gt;reselect&lt;/code&gt;, &lt;code&gt;memoize-one&lt;/code&gt;... implementations.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;cacheKey&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;cacheResult&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// replace the cache to save one value&lt;/span&gt;
&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;memoize&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Cache&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;set&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;cacheKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nx"&gt;cacheResult&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; 
    &lt;span class="nl"&gt;get&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cacheKey&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;cacheResult&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;// ... other map functions&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;



&lt;span class="c1"&gt;// create a resolver that maps all parameters to a key&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;keyResolver&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;add&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// use the resolver in a memoized function&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;memoizedAdd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;memoize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;add&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;keyResolver&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;While replacing the cache can be done once and for all, the &lt;code&gt;keyResolver&lt;/code&gt; to use all parameters as the cache key needs to be added to each new memoized function. &lt;/p&gt;

&lt;p&gt;This made me choose a second option: Replace the memoize function by another-more straightforward- implementation. The easy part about having to switch from one memoize to another one is that there are already a lot of available implementations in most projects. &lt;/p&gt;

&lt;p&gt;I used &lt;code&gt;defaultMemoize&lt;/code&gt; from &lt;a href="https://github.com/reduxjs/reselect#defaultmemoizefunc-equalitycheck--defaultequalitycheck"&gt;reselect&lt;/a&gt; as a short-term replacement and will then either introduce &lt;code&gt;memoize-one&lt;/code&gt; or convert the component to be able to use hooks. The other change I'd like to do is adding a linting rule to warn users when they import &lt;code&gt;lodash/memoize&lt;/code&gt;.  &lt;/p&gt;

&lt;p&gt;As a more long-term fix for the whole community, we may want to rename the lodash function to something along the lines of &lt;code&gt;cacheResults(fn, generateKey)&lt;/code&gt; so that the name matches better the default behavior and not clash with the common memoize implementations.  &lt;/p&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>debugging</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Things I learn at standups</title>
      <dc:creator>Adrien TRAUTH</dc:creator>
      <pubDate>Wed, 10 Jul 2019 16:18:38 +0000</pubDate>
      <link>https://forem.com/nioufe/things-i-learn-at-standups-1d9c</link>
      <guid>https://forem.com/nioufe/things-i-learn-at-standups-1d9c</guid>
      <description>&lt;p&gt;A few days ago, someone told me that they felt that &lt;strong&gt;standups do not bring a lot of value for their team&lt;/strong&gt;. It got to a point that his team members were getting disengaged.&lt;/p&gt;

&lt;p&gt;I've always been a big proponent of this meeting and feel kind of lost when I miss it for a few days. So I took this as an good opportunity to  explore what makes me feel that way and wanted to share with you:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Why it’s an important part of my day. &lt;/li&gt;
&lt;li&gt;A few tips to make the most out of those 15 minutes.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fz0ol9aj8ha2nbvvvvfaq.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fz0ol9aj8ha2nbvvvvfaq.jpg" alt="Wizard of oz"&gt;&lt;/a&gt;&lt;/p&gt;
The team, going to a standup



&lt;h3&gt;
  
  
  A valuable standup
&lt;/h3&gt;

&lt;p&gt;We often evaluate if we should keep a meeting by comparing the value it brings to the time spent. Standup being the most recurring meeting, it's understandable that it needs to help the team quite a lot to be &lt;em&gt;worth it&lt;/em&gt;. However, I do feel like it has some real hidden benefits for a team. &lt;/p&gt;

&lt;h4&gt;
  
  
  It's a social event
&lt;/h4&gt;

&lt;p&gt;My team has remote developers and we're not all working on the same things. The standup is sometimes the only opportunity of the day we get to see and interact with each other. It's a mini team-building moment where we get to: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Share our problems.&lt;/li&gt;
&lt;li&gt;Get support from the team.&lt;/li&gt;
&lt;li&gt;Congratulate each other on achievements.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Team cohesion becomes a critical factor as your team grows and takes on bigger projects. It helps boost morale, streamline exchanges and helps pursuing the common goals of the team. Most of us spend our day working on a piece of code with headphones on. I do believe we need these kind of moments to create cohesion. &lt;/p&gt;

&lt;h4&gt;
  
  
  Everybody is available
&lt;/h4&gt;

&lt;p&gt;Being forced to all stand in the room has some perks, the first of which is that everybody is ready to listen to anything that is said. It makes it a perfect moment to bother people with small things that don't require interrupting a teammate during the day.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Do you have 5 minutes to demo that to me today?", &lt;br&gt;
"Can I send you this PR? I'd like to have your opinion on the pattern I used." &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;These types of questions are all easier to ask (and do get better answers) at a standup than if they were sent as slack notifications. People can also ask for more details and get their answers instantly: it's interactive and fun :-) .&lt;/p&gt;

&lt;h4&gt;
  
  
  Pull requests do not cover the full story
&lt;/h4&gt;

&lt;p&gt;I used to think that I could know everything that's happening within my team just by reading the pull requests and RFCs. While those artifacts cover the &lt;em&gt;result&lt;/em&gt; of peoples' work, they don't always cover how the author got there and what he/she plans to do next.* It's also unlikely that everybody on the team is reading all the PRs-Emails-RFCs. At standup, you can be fairly sure that people are listening.&lt;/p&gt;

&lt;p&gt;I learn a lot from hearing what my teammates tried before choosing a final implementation, and I also find it easier to understand the "next steps" when a teammate is explaining them out loud.  &lt;/p&gt;

&lt;p&gt;&lt;small&gt;*: Unless the team writes amazing pull request descriptions, in that case: bravo.&lt;/small&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  My teammates have secret talents
&lt;/h4&gt;

&lt;p&gt;And our projects have secret dependencies.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Hey! I worked on something similar, maybe I can help&lt;/code&gt; is my favorite thing to hear at a standup. Sometimes I forget that somebody worked on the subject, or discover that they worked on the same thing at their previous company: in either case it's a welcome help. &lt;/p&gt;

&lt;p&gt;The other side of that coin is the infamous&lt;br&gt;&lt;code&gt;Be careful I'm working on the same file, we'll probably have to handle conflicts&lt;/code&gt;. Not as exciting to hear that one, but it's still better than learning about it when authors are in rebase hell trying to get their PRs merged.&lt;/p&gt;

&lt;h4&gt;
  
  
  It helps me structure my days
&lt;/h4&gt;

&lt;p&gt;I take a minute before the meeting to think about what my priorities of the day will be. I feel like this is a good habit and it helps me focus on what's important.&lt;/p&gt;

&lt;p&gt;As a way to make sure the meeting stays beneficial as we grow, I usually give our new hires a few pointers before their first standup.&lt;/p&gt;

&lt;h3&gt;
  
  
  Making the most out of 15 minutes
&lt;/h3&gt;

&lt;p&gt;Also known as: &lt;em&gt;our internal guidelines to a successful standup.&lt;/em&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Be precise
&lt;/h4&gt;

&lt;p&gt;You should never say the same thing two days in a row. If you are working on the same subject, then give some details on what you did yesterday that was different from the day before. Your coworkers are all familiar with the context, it's okay to expect them to understand detailed explanations on your subject. The more precise you can be in the time you have, the more value you bring to your teammates.&lt;/p&gt;

&lt;h4&gt;
  
  
  Make it interactive
&lt;/h4&gt;

&lt;p&gt;Being precise opens the discussion for questions and interactions. The meeting has more value when everyone can ask questions or ask for some details on the part that interests them the most. It makes the meeting more lively and keeps people interested, it's also a good way to discover dependencies or how people can help.&lt;/p&gt;

&lt;p&gt;Of course the goal is not to discuss something for 30 minutes. If the question requires a long answer, it should be postponed to either the end of the standup-so the uninterested can leave and get on with their day-  or be scheduled as a separate meeting.&lt;/p&gt;

&lt;h4&gt;
  
  
  It's okay to have a bad day
&lt;/h4&gt;

&lt;p&gt;Sometimes you don't have much to say because &lt;a href="https://www.youtube.com/watch?v=gH476CxJxfg" rel="noopener noreferrer"&gt;you had a bad day&lt;/a&gt; for any number of reasons. It's okay to not have a lot to say at standup, it's not a performance review. As long as you're precise about whatever you did yesterday your team will still get value from hearing you. In fact, sometimes explaining &lt;em&gt;why&lt;/em&gt; you had a bad day might give your teammates an insight that would allow them to help unstick you.&lt;/p&gt;

&lt;h4&gt;
  
  
  Focus on the team
&lt;/h4&gt;

&lt;p&gt;I try to highlight the part of my day that was related to the team. If I  write a new feature and do a candidate interview, I'll focus more on the pull request because the team is directly impacted by that change.&lt;/p&gt;

&lt;h3&gt;
  
  
  Own your standup
&lt;/h3&gt;

&lt;p&gt;I hope this can help other teams enjoy that moment as much as I do. &lt;/p&gt;

&lt;p&gt;I highly encourage you to spend time making sure your standup meeting is as valuable as possible for your team. It's often a required meeting anyway. &lt;br&gt;
&lt;strong&gt;Write your own guidelines, try things, iterate #devopslife&lt;/strong&gt; &lt;/p&gt;

</description>
      <category>agile</category>
      <category>career</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
