<?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:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Artem Sapegin on Medium]]></title>
        <description><![CDATA[Stories by Artem Sapegin on Medium]]></description>
        <link>https://medium.com/@sapegin?source=rss-b031a508ddaf------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*lyUViCL5X9ahMgGOqUTc_Q.jpeg</url>
            <title>Stories by Artem Sapegin on Medium</title>
            <link>https://medium.com/@sapegin?source=rss-b031a508ddaf------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Fri, 13 Nov 2026 21:54:08 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@sapegin/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[Washing your code: avoid loops]]></title>
            <link>https://medium.com/@sapegin/avoid-loops-da0a72d74dec?source=rss-b031a508ddaf------2</link>
            <guid isPermaLink="false">https://medium.com/p/da0a72d74dec</guid>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[clean-code]]></category>
            <category><![CDATA[washing-code]]></category>
            <dc:creator><![CDATA[Artem Sapegin]]></dc:creator>
            <pubDate>Tue, 07 May 2019 00:00:00 GMT</pubDate>
            <atom:updated>2019-05-16T07:37:02.421Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/300/0*nWhvCFYepCzsCT-Y.jpg" /></figure><p><em>You’re reading an excerpt of my upcoming book on clean code, “Washing your code: write once, read seven times.” </em><a href="https://leanpub.com/washingcode/"><em>Preorder it on Leanpub</em></a><em> or </em><a href="https://github.com/sapegin/washingcode-book/blob/master/manuscript/book.md"><em>read a draft online</em></a><em>.</em></p><p>Traditional loops, like for or while, are too low-level for common tasks. They are verbose and prone to <a href="https://en.wikipedia.org/wiki/Off-by-one_error">off-by-one error</a>. You have to manage the index variable yourself, and I always make typos with lenght. They don&#39;t have any particular semantic value except that you&#39;re doing some operation probably more than once.</p><h3>Replacing loops with array methods</h3><p>Modern languages have better ways to express iterative operations. <a href="http://exploringjs.com/impatient-js/ch_arrays.html#methods-iteration-and-transformation-.find-.map-.filter-etc">JavaScript has may useful methods</a> to transform and iterate over arrays, like .map() or .find().</p><p>For example, let’s convert an array of strings to kebab-case with a for loop:</p><pre>const names = [&#39;Bilbo Baggins&#39;, &#39;Gandalf&#39;, &#39;Gollum&#39;];<br>for (let i = 0; i &lt; names.length; i++) {<br>  names[i] = _.kebabCase(names[i]);<br>}</pre><p>And now with the .map() method:</p><pre>const names = [&#39;Bilbo Baggins&#39;, &#39;Gandalf&#39;, &#39;Gollum&#39;];<br>const kebabNames = names.map(name =&gt; _.kebabCase(name));</pre><p>We can shorten it even more if our processing function accepts only one argument, and <a href="https://lodash.com/docs#kebabCase">kebabCase from Lodash</a> does:</p><pre>const names = [&#39;Bilbo Baggins&#39;, &#39;Gandalf&#39;, &#39;Gollum&#39;];<br>const kebabNames = names.map(_.kebabCase);</pre><p>But this may be a bit less readable than the expanded version, because we don’t see what exactly we’re passing to a function. ECMAS cript 6’s arrow functions made callbacks shorter and less cluttered, compared to the old anonymous function syntax:</p><pre>const names = [&#39;Bilbo Baggins&#39;, &#39;Gandalf&#39;, &#39;Gollum&#39;];<br>const kebabNames = names.map(function(name) {<br>  return _.kebabCase(name);<br>});</pre><p>Or let’s find an element in an array with a for loop:</p><pre>const names = [&#39;Bilbo Baggins&#39;, &#39;Gandalf&#39;, &#39;Gollum&#39;];<br>let foundName;<br>for (let i = 0; i &lt; names.length; i++) {<br>  if (names[i].startsWith(&#39;B&#39;)) {<br>    foundName = names[i];<br>    break;<br>  }<br>}</pre><p>And now with the .find() method:</p><pre>const names = [&#39;Bilbo Baggins&#39;, &#39;Gandalf&#39;, &#39;Gollum&#39;];<br>const foundName = names.find(name =&gt; name.startsWith(&#39;B&#39;));</pre><p>In both cases I much prefer versions with array methods than with for loops. They are shorter and we&#39;re not wasting half the code on iteration mechanics.</p><h3>Implied semantics of array methods</h3><p>Array methods aren’t just shorter and more readable; each method has its own clear semantic:</p><ul><li>.map() says we&#39;re transforming an array into another array with the same number of elements;</li><li>.find() says we&#39;re <em>finding</em> a single element in an array;</li><li>.some() says we&#39;re testing that the condition is true for <em>some</em> array elements;</li><li>.every() says we&#39;re testing that the condition is true for <em>every</em> array element.</li></ul><p>Traditional loops don’t help with understanding what the code is doing until you read the whole thing.</p><p>We’re separating the “what” (our data) from the “how” (how to loop over it). More than that, with array methods we only need to worry about our data, which we’re passing in as a callback function.</p><p>When you use array methods for all simple cases, traditional loops signal to the code reader that something unusual is going on. And that’s good: you can reserve brain resources for better understanding the unusual, more complex cases.</p><p>Also don’t use generic array methods like .map() or .forEach() when more specialized array methods would work, and don&#39;t use .forEach() when .map() would work:</p><pre>const names = [&#39;Bilbo Baggins&#39;, &#39;Gandalf&#39;, &#39;Gollum&#39;];<br>const kebabNames = [];<br>names.forEach(name =&gt; {<br>  kebabNames.push(_.kebabCase(name));<br>});</pre><p>This is a more cryptic and less semantic implementation of .map(), so better use .map() directly like we did above:</p><pre>const names = [&#39;Bilbo Baggins&#39;, &#39;Gandalf&#39;, &#39;Gollum&#39;];<br>const kebabNames = names.map(name =&gt; _.kebabCase(name));</pre><p>This version is much easier to read because we know that the .map() method transforms an array by keeping the same number of items. And unlike .forEach(), it doesn&#39;t require a custom implementation nor mutate an output array. Also the callback function is now pure: it doesn&#39;t access any variables in the parent function, only function arguments.</p><h3>Dealing with side effects</h3><p>Side effects make code harder to understand because you can no longer treat a function as a black box: a function with side effects doesn’t just transform input to output, but can affect the environment in unpredictable ways. Functions with side effects are also hard to test because you’ll need to recreate the environment before each test and verify it after.</p><p>All array methods mentioned in the previous section, except .forEach(), imply that they don&#39;t have side effects, and that only the return value is used. Introducing any side effects into these methods would make code easy to misread since readers wouldn&#39;t expect to see side effects.</p><p>.forEach() doesn&#39;t return any value, and that&#39;s the right choice for handling side effects when you really need them:</p><pre>errors.forEach(error =&gt; {<br>  console.error(error);<br>});</pre><p>for of loop is even better:</p><ul><li>it doesn’t have any of the problems of regular for loops, mentioned in the beginning of this chapter;</li><li>we can avoid reassignments and mutations, since we don’t have a return value;</li><li>it has clear semantics of iteration over all array elements, since we can’t manipulate the number of iterations, like in a regular for loop. (Well, almost, we can abort the loops with break.)</li></ul><p>Let’s rewrite our example using for of loop:</p><pre>for (const error of errors) {<br>  console.error(error);<br>}</pre><h3>Sometimes loops aren’t so bad</h3><p>Array methods aren’t always better than loops. For example, a .reduce() method often makes code less readable than a regular loop.</p><p>Let’s look at this code:</p><pre>const tableData = [];<br>if (props.item &amp;&amp; props.item.details) {<br>  for (const client of props.item.details.clients) {<br>    for (const config of client.errorConfigurations) {<br>      tableData.push({<br>        errorMessage: config.error.message,<br>        errorLevel: config.error.level,<br>        usedIn: client.client.name<br>      });<br>    }<br>  }<br>}</pre><p>My first reaction would be to rewrite it with .reduce() to <em>avoid loops</em>:</p><pre>const tableData =<br>  props.item &amp;&amp;<br>  props.item.details &amp;&amp;<br>  props.item.details.clients.reduce(<br>    (acc, client) =&gt; [<br>      ...acc,<br>      ...client.errorConfigurations.reduce(<br>        (inner, config) =&gt; [<br>          ...inner,<br>          {<br>            errorMessage: config.error.message,<br>            errorLevel: config.error.level,<br>            usedIn: client.client.name<br>          }<br>        ],<br>        []<br>      )<br>    ],<br>    []<br>  );</pre><p>But is it really more readable?</p><p>After a cup of coffee and a chat with a colleague, I’ve ended up with a much cleaner code:</p><pre>const tableData =<br>  props.item &amp;&amp;<br>  props.item.details &amp;&amp;<br>  props.item.details.clients.reduce((acc, client) =&gt;<br>    acc.concat(<br>      ...client.errorConfigurations.map(config =&gt; ({<br>        errorMessage: config.error.message,<br>        errorLevel: config.error.level,<br>        usedIn: client.client.name<br>      }))<br>    )<br>  );</pre><p>I think I still prefer the double for version, but I&#39;ll be happy with both versions, the original and the second rewrite, if I had to review such code.</p><p><em>(Though </em><em>tableData is a really bad variable name.)</em></p><h3>Iterating over objects</h3><p>There are <a href="https://stackoverflow.com/a/5737136/1973105">many ways to iterate over objects</a> in JavaScript. I equally dislike them all, so it’s hard to choose the best one. Unfortunately there’s no .map() for objects, though Lodash does have three methods for object iteration, so it&#39;s a good option if you&#39;re already using Lodash in your project.</p><pre>const allNames = {<br>  hobbits: [&#39;Bilbo&#39;, &#39;Frodo&#39;],<br>  dwarfs: [&#39;Fili&#39;, &#39;Kili&#39;]<br>};<br>const kebabNames = _.mapValues(allNames, names =&gt;<br>  names.map(name =&gt; _.kebabCase(name))<br>);</pre><p>If you don’t need the result as an object, like in the example above, Object.keys(), Object.values() and Object.entries() are also good:</p><pre>const allNames = {<br>  hobbits: [&#39;Bilbo&#39;, &#39;Frodo&#39;],<br>  dwarfs: [&#39;Fili&#39;, &#39;Kili&#39;]<br>};<br>Object.keys(allNames).forEach(race =&gt;<br>  console.log(race, &#39;-&gt;&#39;, allNames[race])<br>);</pre><p>Or:</p><pre>const allNames = {<br>  hobbits: [&#39;Bilbo&#39;, &#39;Frodo&#39;],<br>  dwarfs: [&#39;Fili&#39;, &#39;Kili&#39;]<br>};<br>Object.entries(allNames).forEach(([race, value]) =&gt;<br>  console.log(race, &#39;-&gt;&#39;, names)<br>);</pre><p>I don’t have a strong preference between them. Object.entries() has more verbose syntax, but if you use the value ( names in the example above) more than once, the code would be cleaner than Object.keys(), where you&#39;d have to write allNames[race] every time or cache this value into a variable at the beginning of the callback function.</p><p>If I stopped here, I’d be lying to you. Most of the articles about iteration over objects have examples with console.log(), but in reality you&#39;d often want to convert an object to another data structure, like in the example with _.mapValues() above. And that&#39;s where things start getting uglier.</p><p>Let’s rewrite our example using .reduce():</p><pre>const kebabNames = Object.entries(allNames).reduce(<br>  (newNames, [race, names]) =&gt; {<br>    newNames[race] = names.map(name =&gt; _.kebabCase(name));<br>    return newNames;<br>  },<br>  {}<br>);</pre><p>With .forEach():</p><pre>const allNames = {<br>  hobbits: [&#39;Bilbo&#39;, &#39;Frodo&#39;],<br>  dwarfs: [&#39;Fili&#39;, &#39;Kili&#39;]<br>};<br>const kebabNames = {};<br>Object.entries(allNames).forEach(([race, names]) =&gt; {<br>  kebabNames[race] = names.map(name =&gt; name.toLowerCase());<br>});</pre><p>And with a loop:</p><pre>const kebabNames = {};<br>for (let [race, names] of Object.entries(allNames)) {<br>  kebabNames[race] = names.map(name =&gt; name.toLowerCase());<br>}</pre><p>And again .reduce() is the least readable option.</p><p>In later chapters I’ll urge you to avoid not only loops but also reassigning variables and mutation. Like loops, they <em>often</em> lead to poor code readability, but <em>sometimes</em> they are the best choice.</p><h3>But aren’t array methods slow?</h3><p>You may think that using functions is slower than loops, and likely it is. But in reality it doesn’t matter unless you’re working with millions of items.</p><p>Modern JavaScript engines are very fast and optimized for popular code patterns. Back in the day we used to write loops like this, because checking the array length on every iteration was too slow:</p><pre>var names = [&#39;Bilbo Baggins&#39;, &#39;Gandalf&#39;, &#39;Gollum&#39;];<br>for (var i = 0, namesLength = names.length; i &lt; namesLength; i++) {<br>  names[i] = _.kebabCase(names[i]);<br>}</pre><p>It’s not slow anymore. And there are other examples where engines optimize for simpler code patterns and make manual optimization unnecessary. In any case, you should measure performance to know what to optimize, and whether your changes really make code faster in all important browsers and environments.</p><p>Also .every(), .some(), .find() and .findIndex() will short circuit, meaning they won&#39;t iterate over more array elements than necessary.</p><p>Start thinking about:</p><ul><li>Replacing loops with array methods, like .map() or .filter().</li><li>Avoiding side effects in functions.</li></ul><p><em>If you have any feedback, </em><a href="https://twitter.com/iamsapegin"><em>tweet me</em></a><em>, </em><a href="https://github.com/sapegin/washingcode-book/issues"><em>open an issue</em></a><em> on GitHub, or email me at </em><a href="/service/mailto:artem@sapegin.ru"><em>artem@sapegin.ru</em></a><em>. </em><a href="https://leanpub.com/washingcode/"><em>Preorder the book on Leanpub</em></a><em> or </em><a href="https://github.com/sapegin/washingcode-book/blob/master/manuscript/book.md"><em>read a draft online</em></a><em>.</em></p><p><em>Originally published at </em><a href="https://blog.sapegin.me/all/avoid-loops/"><em>https://blog.sapegin.me</em></a><em> on May 7, 2019.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=da0a72d74dec" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[React Finland 2019]]></title>
            <link>https://medium.com/component-driven/react-finland-2019-e3a9843b9464?source=rss-b031a508ddaf------2</link>
            <guid isPermaLink="false">https://medium.com/p/e3a9843b9464</guid>
            <category><![CDATA[conference]]></category>
            <category><![CDATA[react-finland]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[react]]></category>
            <dc:creator><![CDATA[Artem Sapegin]]></dc:creator>
            <pubDate>Thu, 02 May 2019 00:00:00 GMT</pubDate>
            <atom:updated>2019-05-06T07:46:09.089Z</atom:updated>
            <content:encoded><![CDATA[<p><a href="https://react-finland.fi/">A conference</a> was held on April 24–26 in Helsinki, Finland. I was there with a workshop on <a href="https://react-finland.fi/workshops/#design-systems-for-react-developers">design systems for React developers</a> and a talk. <a href="https://blog.sapegin.me/all/react-finland-2018/">Check out my notes</a> on the last year.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*p4-QqNxJhFPoUWiq.jpg" /></figure><h3>The conference</h3><p>React Finland is one of my favorite conferences. It was my second time and both times I felt good as a speaker. Talks were great: two days with big breaks to have enough time to talk to your friends. I liked the selection of talks: design systems, animation, architecture. The venue (a building with a tower on a photo above) was also good.</p><h3>The talks</h3><h4>MobX — The Journey by <a href="https://twitter.com/mweststrate">Michel Weststrate</a></h4><p><a href="https://docs.google.com/presentation/d/12Dd8iYxcA8Wl2yaOE_FNb-MaB7cktUE82JFXVlrO-6U/edit#slide=id.p">Slides</a>, <a href="https://www.youtube.com/watch?v=MIh1qSHi_Fc">video</a>.</p><ul><li>If you can’t sell the library, sell the problem.</li><li>“MobX […] tries to enable you to go home early each day.”</li><li>Always keep learning: stay slightly out of your comfort zone.</li><li>Open source good parts: learning, happy users, core contributors, beautiful conferences, awesome people, video tutorials, workshops, book, getting a raise, seeing others succeed.</li><li>Open source bad parts: making your library work with all other libraries, no holidays, now you have two jobs.</li><li>When filing issues, remember: you are asking for free help on something you are being paid for.</li><li>Guard your heart and live a balanced life.</li></ul><h3>Artem Sapegin ☕ on Twitter</h3><p>First #ReactFinland talk by @mweststrate.</p><h4>Append-only development with React: An intro to Behavioral programming by <a href="https://twitter.com/lmatteis">Luca Matteis</a></h4><p><a href="https://lmatteis.github.io/finland-talk/assets/player/KeynoteDHTMLPlayer.html">Slides</a>, <a href="https://www.youtube.com/watch?v=cXuvCMG21Ss">video</a>.</p><ul><li>“Programming language are practically irrelevant in making products.”</li><li>Code maintenance is the root of the problem.</li><li>Make changes without having to read and maintain the code.</li><li>Newly added code can change how old code is executed.</li><li><a href="https://github.com/lmatteis/behavioral">Behavioral programming for JavaScript</a>.</li></ul><h4>Mind-Reading with Adaptive and Intelligent UIs in React by <a href="https://twitter.com/DavidKPiano">David Khourshid</a></h4><p><a href="https://slides.com/davidkhourshid/mind-reading-react-finland#/">Slides</a>, <a href="https://www.youtube.com/watch?v=ppvi09LIUnU">video</a>.</p><ul><li>Adapt to people, not just devices.</li><li>Microsoft Clippy is the first adaptive UI.</li><li>A/B tests are ineffective.</li><li>Collect stats on state changes and optimize flows.</li></ul><h3>Artem Sapegin ☕ on Twitter</h3><p>Clippy in @DavidKPiano talk at #ReactFinland.</p><h4>A Common Design Language. Let Designers and Developers talk to each other by <a href="https://twitter.com/okonetchnikov">Andrey Okonetchnikov</a></h4><p><a href="https://speakerdeck.com/okonet/a-common-design-language">Slides</a>, <a href="https://www.youtube.com/watch?v=a6DtiGhKMdk">video</a>.</p><ul><li>Design: typography, color and spacing.</li><li>Developers talk in code.</li><li>Designers talk in UI primitives.</li><li>Design tools talk in shapes, like arrow and triangles.</li><li>Common language: UI primitives.</li><li><a href="https://component-driven.io/">component-driven.io</a>: component-driven design &amp; development for the modern web.</li></ul><h3>Artem Sapegin ☕ on Twitter</h3><p>That guy again! @okonetchnikov at #ReactFinland.</p><h4>A practical guide to building your design system infrastructure by <a href="https://twitter.com/varya_en">Varya Stepanova</a></h4><p><a href="http://varya.me/react-finland-2019/">Slides</a>, <a href="https://www.youtube.com/watch?v=5_lYTicLUbk">video</a>.</p><ul><li>Design system is shared practices, tools, processes and community.</li><li>Living style guides: <a href="https://react-styleguidist.js.org/">React Styleguidist</a>, <a href="https://storybook.js.org/">Storybook</a>.</li><li>Visual regression tests.</li><li>Uses Styleguidist to document plain HTML components.</li><li>Design system site: single source of truth.</li><li>Automate everything.</li><li>Welcome contributions: edit on GitHub button, list of contributors.</li><li>Blogging with WordPress as a backend and Gatsby.</li></ul><h3>Artem Sapegin ☕ on Twitter</h3><p>@varya_en @varya_en is using @styleguidist to generate documentation for plain CSS/HTML components with @styleguidist.</p><h4>12 Tips for More Accessible React Apps by <a href="https://twitter.com/mmatuzo">Manuel Matuzovic</a></h4><p><a href="https://www.matuzo.at/blog/12-tips-for-more-accessible-react-apps-slides-react-finland-2019/">Slides</a>, <a href="https://www.youtube.com/watch?v=NL6XKcX4sxc">video</a>.</p><ol><li>Create a sound document outline: start with h1 and don&#39;t skip levels.</li><li>Hide content correctly: display: none, visibility: hidden and hidden are hiding content from screen readers, use <a href="https://medium.com/@matuzo/writing-css-with-accessibility-in-mind-8514a0007939">a combination of CSS properties</a> that hides content only visually or <a href="https://github.com/reach/reach-ui/tree/master/packages/visually-hidden">VisuallyHidden</a> component from Reach UI.</li><li>Use &lt;button&gt; if you need a button: they are focusable by default and support keyboard events.</li><li>Use fragments to avoid invalid HTML: &lt;tr&gt;&lt;div&gt;&lt;td&gt; → &lt;tr&gt;&lt;&gt;&lt;td&gt;.</li><li>Take care of focus management: can be a problem for modals, put focus inside a modal on open and don’t let it leave the modal.</li><li>Make notifications accessible to everyone: use role=&quot;alert&quot; or role=&quot;status&quot; to make screen readers announce notifications.</li><li>Announce page changes: on single page applications screen readers should read the page title on navigation. Check out <a href="https://reach.tech/router">Reach Router</a>.</li><li>Test your React code automatically: use <a href="https://github.com/dequelabs/react-axe">React-Axe</a> and <a href="https://github.com/evcohen/eslint-plugin-jsx-a11y">eslint-plugin-jsx-a11y</a>.</li></ol><h3>Artem Sapegin ☕ on Twitter</h3><p>@mmatuzo Automating heading levels, @mmatuzo at #ReactFinland.</p><h4>Delightful UI animations by understanding the brain by <a href="https://twitter.com/brunnolou">Bruno Lourenço</a></h4><p><a href="https://www.youtube.com/watch?v=TszRBCc6DQ4">Video</a>.</p><ul><li>Animation — an illusion of movement.</li><li><a href="https://github.com/brunnolou/react-morph">React Morph</a>: morphing UI transitions.</li><li>Creates a clone of an element and uses <a href="https://aerotwist.com/blog/flip-your-animations/">FLIP technique</a> to do the morphing animation.</li></ul><h3>Artem Sapegin ☕ on Twitter</h3><p>@brunnolou I&#39;m definitely going to try react-morph, it looks incredible! #ReactFinland</p><h4>Custom CSS is the path to inconsistent UI by <a href="https://twitter.com/iamsapegin">Artem Sapegin</a></h4><p><a href="https://stopwritingcss.netlify.com/">Slides</a>, <a href="https://www.youtube.com/watch?v=_CsBRkRTzIA">video</a>.</p><ul><li>We use custom styles mostly for typography, whitespace and layout.</li><li>This leads to inconsistent UI because CSS is too expressive.</li><li>Design tokens are the first step to achieve UI consistency.</li><li>But not all combinations of design tokens are good: you may create unreadable text for example.</li><li>UI primitives (primitive components) is the solution.</li><li><a href="https://github.com/component-driven/component-driven-development/tree/master/src/components/core/Text">Text</a> and <a href="https://github.com/component-driven/component-driven-development/tree/master/src/components/core/Heading">Heading</a> components to render all text in an application.</li><li><a href="https://rebassjs.org/grid/">Box, Flex</a> and <a href="https://github.com/sapegin/stack-styled">Grid (Stack)</a> components to define whitespace and layouts.</li><li>Use <a href="https://styled-system.com/">styled-system</a> to create such components: works with any CSS in JS library.</li></ul><h3>James Stone on Twitter</h3><p>CSS is too expressive&quot; - @iamsapegin #ReactFinland</p><h4>Creating layouts that last by <a href="https://twitter.com/kettanaito">Artem Zakharchenko</a></h4><p><a href="https://www.youtube.com/watch?v=_HrXUB97xQs">Video</a>.</p><ul><li>Spacing is important to build maintainable layout.</li><li>Defining margins and padding directly on components isn’t the most maintainable way.</li><li><a href="https://github.com/kettanaito/atomic-layout">Atomic layout</a> is a library to create declarative layouts with CSS Grid.</li><li><a href="https://redd.gitbook.io/atomic-layout/general/getting-started/workflow#define-layout-areas">Define layout areas</a> as a string template.</li><li><a href="https://redd.gitbook.io/atomic-layout/fundamentals/responsive-props">Responsive props</a>.</li><li>Render areas using <a href="https://redd.gitbook.io/atomic-layout/general/getting-started/workflow#render-areas">a render prop</a>.</li></ul><h3>Artem Sapegin ☕ on Twitter</h3><p>More layouts, more spacing by @kettanaito at #ReactFinland.</p><h4>Scalable (Design) Systems with TypeScript by <a href="https://twitter.com/TejasKumar_">Tejas Kumar</a></h4><p><a href="https://tejaskumar.com/static/talks/react-finland-typescript-design-systems.pdf">Slides</a>, <a href="https://www.youtube.com/watch?v=ZsBW4S8hYMU">video</a>.</p><ul><li>TypeScript is a good choice for design systems: enforces contracts, confidence to make changes, allows you to scale.</li><li>Uses <a href="https://react-styleguidist.js.org/">React Styleguidist</a> and TypeScript for their design system.</li><li>Hacked Styleguidist to use TypeScript and Monaco editor in component examples.</li></ul><h3>Artem Sapegin ☕ on Twitter</h3><p>@TejasKumar_ TypeScript editor with autocomplete in @styleguidist by @TejasKumar_ at #ReactFinland - super cool!</p><h4>Building resilient frontend architecture by <a href="https://twitter.com/monicalent">Monica Lent</a></h4><p><a href="https://monicalent.com/building-resilient-frontend-architecture.pdf">Slides</a>, <a href="https://www.youtube.com/watch?v=brMZLmZ1HR0">video</a>.</p><ul><li>Refactoring only temporarily helps with technical debt.</li><li>Second system effect: the tendency of small, elegant, and successful systems to be succeeded by over-engineered, bloated systems because of inflated expectations and overconfidence.</li><li>“‘Legacy code’” often differs from its suggested alternative by actually working and scaling.” — Bjarne Stroustrup.</li><li>The real cost of software is not the initial development, but maintenance over time.</li><li>Architecture as enabling constraints: constraints about how we use data and code that help us move faster over time.</li><li>Shared dependencies: add them to the design system or copy-paste.</li><li>Decoupled code is better than DRY.</li></ul><p>Three constraints you can use today for more resilient frontend architecture:</p><ol><li>Source code dependencies must point inward: don’t depend on other team’s code.</li><li>Be conservative about code reuse: avoid coupling code that diverges over time.</li><li>Enforce your boundaries: don’t let people depend on your code (with <a href="https://github.com/sverweij/dependency-cruiser">dependency-cruiser</a>).</li></ol><h3>Artem Sapegin ☕ on Twitter</h3><p>@monicalent Monica&#39;s @monicalent talk was my favorite at #ReactFinland - really resonates with me 🤓</p><h4>“Intuitive” Tooling by <a href="https://twitter.com/carolstran">Carolyn Stransky</a></h4><p><a href="https://speakerdeck.com/carolstran/intuitive-tooling">Slides</a>, <a href="https://www.youtube.com/watch?v=nBy8y39Pvp4">video</a>.</p><ul><li>Hard to learn things: TypeScript, Redux, GraphQL, Gatsby, Flexbox.</li><li>“We mistake familiarity for simplicity” — <a href="https://www.youtube.com/watch?v=1vvjiJFsT-Y&amp;t=2367s">Jim Fisher</a>.</li><li><a href="http://noelle-neumann.de/scientific-work/spiral-of-silence/">Spiral of silence</a>.</li><li>Empathy matters more in education.</li><li>Start an internal mentorship program.</li><li>Ban words like “easy” from your vocabulary.</li><li>Just because you understand something doesn’t mean that someone else will too.</li></ul><h3>Artem Sapegin ☕ on Twitter</h3><p>@carolstran Flexbox is hard to learn - definitely agree with @carolstran #ReactFinland.</p><h3>Links</h3><ul><li><a href="https://ebaytech.berlin/react-finland-2019-sketch-notes-64316793809e">Sketch notes</a> by Patrick Hund</li><li><a href="https://gist.github.com/just-boris/c5489afd181bb0bbd2501cfbbe9f56b7">The first day</a> and <a href="https://gist.github.com/just-boris/2080a0595464c1554ea8b03005984f09">the second day</a> notes by Boris Serdiuk (includes lightning talks)</li><li><a href="https://photos.app.goo.gl/YEQ8VaCbzKGbZw8m7">My photos</a></li><li><a href="https://photos.app.goo.gl/4tJskvEd1haKyBX1A">Shared photo album</a></li></ul><p><strong>Subscribe to my newsletter: </strong><a href="https://tinyletter.com/sapegin"><strong>https://tinyletter.com/sapegin</strong></a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=e3a9843b9464" width="1" height="1" alt=""><hr><p><a href="https://medium.com/component-driven/react-finland-2019-e3a9843b9464">React Finland 2019</a> was originally published in <a href="https://medium.com/component-driven">component-driven</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[️How to get your code reviewed faster]]></title>
            <link>https://medium.com/hackernoon/%EF%B8%8Fhow-to-get-your-code-reviewed-faster-7eb39a8a5899?source=rss-b031a508ddaf------2</link>
            <guid isPermaLink="false">https://medium.com/p/7eb39a8a5899</guid>
            <category><![CDATA[code-review]]></category>
            <dc:creator><![CDATA[Artem Sapegin]]></dc:creator>
            <pubDate>Mon, 25 Mar 2019 18:17:15 GMT</pubDate>
            <atom:updated>2019-03-27T11:09:52.280Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*Y8p0faujGDQkr5tm" /><figcaption>Photo by <a href="https://unsplash.com/@lalonchera?utm_source=medium&amp;utm_medium=referral">lalo Hernandez</a> on <a href="https://unsplash.com/?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><p>Developers and code reviewers have seemingly conflicting goals: developers want to ship their code fast, reviewers want high code quality. But in my opinion these are two sides of the same goal: keep development velocity high by shipping high quality and maintainable code. Reviewers want to help developers to ship less bugs to production and make code easier to understand so feature improvements can be done faster.</p><p>By following these recommendations you’ll be able to reduce number of code review iterations and ship code faster.</p><h3>Before you start</h3><p>Every team has its own standards and best practices. In good teams they are well documented. Reading such documentation in advance will save you many code review iterations.</p><p>If you’re new to a team, technologies or an area of the codebase, <a href="https://medium.com/@oleg008/pair-programming-will-save-you-money-98d3f2fd0bca">pairing with someone</a> more experienced could be a great way to learn and complete your task faster.</p><p>Split big tasks into several diffs. Just reading 1000 lines of code will take a reviewer more than an hour and a cup of coffee. And each iteration will require another hour. It’s hard to say when a diff becomes too big, but the general rule of thumb is: the less experience you have, the smaller your diffs should be.</p><p>By splitting a big task into smaller ones, you’ll get feedback faster, before you’ve spent too much time on a less than ideal implementation. Even better if you discuss, how you’re going to implement a complex feature, with a more experienced developer before you start working.</p><h3>Make sure your code is ready</h3><p>Before sending your code to review, check it for debug code, commented out code and TODO comments, make sure all kinds of automated tests, type checks and linters are passing. Make sure there are no new lint warnings, and code is formatted, if you’re using a tool like Prettier.</p><p>Manual code reviews are great for improving readability, architecture or accessibility. When reviewers are distracted by catching typos and minor issues that could have been caught by automated checks, they’ll be more likely to miss important problems.</p><h3>Do a self review</h3><p>Think what may be unclear to a person reading the code, what kind of questions they may have, if they don’t know everything you know about the task. Answer these questions by making code more clear or by adding comments explaining why some code was written and why it was written in a certain way.</p><p>If there are obvious simpler alternatives that won’t work for your case, explain why.</p><p>These kinds of changes and comments will help everyone who’s going to read the code, not only code reviewers. Good comments may also save your code from accidental “refactoring” that makes code simpler but removes important functionality, when it’s not clear why this “extra” code is needed.</p><h3>Show what you’ve done</h3><p>It helps a lot to see what the code in the diff is actually doing. Mention related tickets, add screenshots or even GIFs for all UI changes.</p><p><em>Tip: </em><a href="https://getkap.co/"><em>Kap</em></a><em> is a nice free app to record GIFs on macOs.</em></p><h3>Ask questions</h3><p>Code review is a great way of sharing knowledge between developers. It works in both directions: from a reviewer to a developer and from a developer to a reviewer. Code review is a dialog where two, or sometimes more, people are working together on improving a piece of code. To make it work, you need to understand each comment and the reasoning behind it.</p><p>Keep asking questions until everything is clear: why something is a problem and what is the proposed solution. Code review comments aren’t always the best place to have long discussions, sometimes it’s better to talk to your reviewer in Slack or even better in person. It’s a good idea to add a short summary of such discussion as a comment to your diff.</p><p><em>Live review</em> can be another way to improve communication. In that case the developer and the reviewer will sit together and go though the code. The reviewer will explain all the problems in details and make sure there’s no misunderstanding.</p><h3>Don’t do changes for the sake of changes</h3><p>Reviewers don’t know as much as you do about your task, so some of their suggestions will not make any sense for what you’re doing. There’s no rule that code reviewer is always right, unless it’s a team standard, and even standards have exceptions sometimes. Sometimes suggestions sound good but don’t work in reality.</p><p>Use your own judgement, don’t do changes if you see that they aren’t improving the code. Explain why you think that the suggestion doesn’t work for you.</p><p>Even if you’ve done the change but don’t like the result, revert it before the next review iteration. A good reviewer will likely notice this too, and asks you to revert the change.</p><h3>Don’t ignore comments</h3><p>You don’t have to agree with everything code reviewer is saying or to apply all their suggestions, but if you just ignore some comments, a code reviewer will likely write it again.</p><p>If you’re not going to do a particular suggestion or have tried and it didn’t work, reply to a review comment with a short explanation to avoid any possible misunderstanding.</p><h3>Make it clear when you’re done with the changes</h3><p>Every developer works differently: some will commit all the changes at once, some will commit each change separately. It’s hard for reviewers to know when you’re done with all their feedback and ready for another iteration.</p><p>Writing a short comment like “Ready for another iteration” will make it clear, and you’ll get that another iteration sooner.</p><h3>Make the next step</h3><p>Development is an iterative process, so is code reviewing. Code review suggestions are possible improvements to the current state of the code, not it’s final state. Often one improvement makes another improvement obvious, and a good code reviewer will let you know about it.</p><p>But you don’t have to wait and loose another iteration: do one more self-review and see what could be the next thing.</p><p>For example a reviewer has asked you to simplify three functions and make code more consistent. But after you’ve done it, it’s now clear that all three functions are doing the same thing, and you can replace them with a single function.</p><h3>Conclusion</h3><p>Don’t treat code reviews as a distraction. They are here to help you ship better code and spend less time on future changes. Help reviewers help you.</p><p>Start reviewing someone else’s code yourself, even if you can’t approve it. You’ll improve your own coding skills by reading more code and thinking how to make it better.</p><p><strong>Subscribe to my newsletter: </strong><a href="https://tinyletter.com/sapegin"><strong>https://tinyletter.com/sapegin</strong></a></p><p><em>Thanks to Anita Kiss, </em><a href="https://oliverjash.me/"><em>Oliver Joseph Ash</em></a><em>, </em><a href="https://matthamlin.me/"><em>Matt Hamlin</em></a><em>, </em><a href="https://twitter.com/oleg008"><em>Oleg Isonen</em></a><em>, Alex Orange.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=7eb39a8a5899" width="1" height="1" alt=""><hr><p><a href="https://medium.com/hackernoon/%EF%B8%8Fhow-to-get-your-code-reviewed-faster-7eb39a8a5899">️How to get your code reviewed faster</a> was originally published in <a href="https://medium.com/hackernoon">HackerNoon.com</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[What’s wrong with snapshot tests]]></title>
            <link>https://medium.com/@sapegin/whats-wrong-with-snapshot-tests-37fbe20dfe8e?source=rss-b031a508ddaf------2</link>
            <guid isPermaLink="false">https://medium.com/p/37fbe20dfe8e</guid>
            <category><![CDATA[frontend]]></category>
            <category><![CDATA[jest]]></category>
            <category><![CDATA[testing]]></category>
            <category><![CDATA[react]]></category>
            <category><![CDATA[snapshot]]></category>
            <dc:creator><![CDATA[Artem Sapegin]]></dc:creator>
            <pubDate>Thu, 17 Jan 2019 08:19:46 GMT</pubDate>
            <atom:updated>2019-03-27T19:15:23.512Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*7fQUB_Y0X-BHUIxY" /><figcaption>Photo by <a href="https://unsplash.com/@sapegin?utm_source=medium&amp;utm_medium=referral">Artem Sapegin</a> on <a href="https://unsplash.com/?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><p>When Jest <a href="https://jestjs.io/blog/2016/07/27/jest-14">announced snapshot tests</a> in 2016, I was <a href="https://hackernoon.com/testing-react-components-with-jest-and-enzyme-41d592c174f">very excited</a>. It felt like a perfect solution for testing React component. Since then I’ve written fewer and fewer snapshot tests. In this article I’ll try to explain why.</p><p>I’ll talk mostly about testing React components, because that’s where I’ve used or have seen snapshots the most, but the same can be said about testing other things.</p><p><em>So, why snapshots are problematic?</em></p><h4>Easy to commit snapshots with bugs</h4><p>When you write expect(mycomponent).toMatchSnapshot(), Jest creates a snapshot file, like mytest.spec.js.snap, with all snapshots of your test file. You don’t see this file unless you really want to.</p><p>That’s a problem: you don’t know if your code is correct yet and, unless you carefully read each line of your snapshot file, you may commit code with a bug and a snapshot that ensures that the bug is still there.</p><h4>Failures are hard to understand</h4><p>It’s often hard to see what changed by looking at the snapshot failure diff: did the snapshot fail because of your intended changes or because you’ve introduced a bug?</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*74GMP-41ti-HfOBcc6JldQ.png" /></figure><h4>We tend to update snapshots without thinking</h4><p>On a big project a simple change can lead to failures in dozens of snapshots in different parts of the codebase. Understanding each failure takes a lot of time, so often developers just update snapshots without looking at them at all, especially if it’s not their code.</p><h4>Coupling with low level modules</h4><p>Snapshots — especially if you don’t use shallow rendering — often break on changes in low level components or on third-party packages updates.</p><p>A little change in a Button component may lead to a failure of hundreds of snapshots, even when everything works fine. A Button component is an implementation detail, and tests should pass if a button still behaves like a button.</p><h4>Test intentions are hard to understand</h4><p>Snapshot tests like “should render the default state of a component” are common but don’t really explain what exactly, if anything, they’re testing.</p><p>Such snapshots will break on <em>any</em> change to the markup, even if the behavior remains the same.</p><h4>A false sense of security</h4><p>Snapshots offer no guarantees that component <em>appearance</em> or <em>behavior</em> is correct. Despite this it’s easy to believe that they do, and write tests that don’t actually <em>test</em> anything, but give you high test coverage.</p><p>Snapshots only verify that the component renders (meaning its HTML, not how it looks in the browser) the same thing, which is rarely important knowledge.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*6Q3snHTt1sNqzs23jxt5-w.jpeg" /></figure><p><em>Hint: visual snapshot testing is a way to verify that your component’s appearance is the same as before. There are many tools, like </em><a href="https://percy.io/"><em>Percy</em></a><em>, </em><a href="https://www.chromaticqa.com/"><em>Chromatic</em></a><em> or </em><a href="https://shutter.sh/"><em>Shutter</em></a><em>, to do that.</em></p><h4>What to use instead of snapshots</h4><p>Let’s look at a typical test (I’ve written similar tests myself):</p><pre>test(&#39;show a success message after submission&#39;, () =&gt; {<br>  const { getByText } = render(&lt;Form /&gt;);<br>  expect(wrapper).toMatchSnapshot();<br>  fireEvent.click(getByText(&#39;Send an owl&#39;));<br>  expect(wrapper).toMatchSnapshot();<br>});</pre><p>We have two snapshots here: both will break on any markup change. Intention of both isn’t clear. The first is likely covered by other test cases, so we can remove it. In the second we likely want to know if the success message was shown instead of a form, which isn’t at all clear from the code. We can test exactly that:</p><pre>test(&#39;show success message after submission&#39;, () =&gt; {<br>  const { getByText, getByTestId } = render(&lt;Form /&gt;);<br>  fireEvent.click(getByText(&#39;Send an owl&#39;));<br>  // The form has gone<br>  expect(getByTestId(&#39;message-form&#39;)).not.toBeDefined();<br>  // The success message is here<br>  expect(<br>    getByTestId(&#39;message-alert&#39;).textContent<br>  ).toMatchInlineSnapshot(`Owl has been sent!`);<br>});</pre><p>The test intention is now clear: we click the submit button and instead of a form we see a success message. This test won’t fail because of primitive components or third-party dependencies updates. This test won’t fail because of the layout changes that don’t affect the behavior.</p><p><em>Hint: I’m using the </em><a href="https://github.com/kentcdodds/react-testing-library/"><em>react-testing-library</em></a><em> by Kent C. Dodds in this example.</em></p><h4>When to use snapshots</h4><p>I think snapshots are still useful in some cases:</p><ul><li>Very short output with clear intent, like class names or error messages:</li></ul><pre>expect(className).toMatchInlineSnapshot(<br>  `Box Text Text--align-center Text--variation-warning`<br>);</pre><ul><li>When you <em>really</em> whant to verify that the output is the same:</li></ul><p>Babel plugins are a good example of that, see <a href="https://github.com/babel-utils/babel-plugin-tester">babel-plugin-tester</a>:</p><pre>exports[`macros basic usage: basic usage 1`] = `<br>&quot;<br>import wcImport from \\&quot;../macro\\&quot;;<br>const asyncModule = wcImport(\\&quot;./MyComponent\\&quot;);<br><br>      ↓ ↓ ↓ ↓ ↓ ↓<br><br>const asyncModule = import(/* webpackChunkName: MyComponent */ \\&quot;./MyComponent\\&quot;);<br><br>&quot;<br>`;</pre><h4>Snapshot dos</h4><ul><li>Use <a href="https://jestjs.io/docs/en/snapshot-testing.html#inline-snapshots">inline snapshots</a> to make snapshots visible inside the test file and to help you to keep them small.</li></ul><pre>expect(error).toMatchInlineSnapshot(`Error: Out of cheese!`);</pre><ul><li>Use <a href="https://jestjs.io/docs/en/snapshot-testing.html#property-matchers">snapshot property matchers</a> to avoid storing generated values, like dates or IDs.</li></ul><pre>expect(user).toMatchSnapshot({<br>  createdAt: expect.any(Date),<br>  id: expect.any(Number)<br>});</pre><p><em>Hint: </em><a href="https://github.com/jest-community/eslint-plugin-jest"><em>eslint-plugin-jest</em></a><em> have two rules, </em><a href="https://github.com/jest-community/eslint-plugin-jest/blob/master/docs/rules/prefer-inline-snapshots.md"><em>prefer-inline-snapshots</em></a><em> and </em><a href="https://github.com/jest-community/eslint-plugin-jest/blob/master/docs/rules/no-large-snapshots.md"><em>no-large-snapshots</em></a><em>, that may help you keep your snapshots healthy.</em></p><h4>Snapshot don’ts</h4><ul><li>Avoid snapshotting file paths: they’ll fail on other platforms because of different delimiters (\ vs /).</li><li>Avoid snapshotting dates and times: even if the date depends only on the input, it may be different in another time zone, and your tests will fail.</li></ul><h4>Conclusion</h4><p>Snapshots are very useful in <em>some rare</em> cases, but often they give you a false sense of security while making the codebase harder to change.</p><p>Check out the <a href="https://blog.kentcdodds.com/effective-snapshot-testing-e0d1a2c28eca">Effective Snapshot Testing</a> article by Kent C. Dodds for more ideas on how to use snapshot tests.</p><p>P. S. <a href="https://github.com/sapegin/jest-cheat-sheet">Jest cheat sheet</a> and <a href="https://react-testing-examples.com/">React Testing Examples</a> will answer most questions you may have when writing Jest tests.</p><p><strong>Subscribe to my newsletter: </strong><a href="https://tinyletter.com/sapegin"><strong>https://tinyletter.com/sapegin</strong></a></p><p>❤️ Thanks to <a href="https://medium.com/u/52d34769ab0c">Oliver Joseph Ash</a>, <a href="https://medium.com/u/781d032b61cf">Ovidiu Cherecheș</a>, <a href="https://medium.com/u/5ffc750a8b59">Manjula Dube</a>, <a href="https://medium.com/u/5b3f5de9138">Matt Hamlin</a>, <a href="https://medium.com/u/b9ce8600312b">Patrick Hund</a>, <a href="https://medium.com/u/7c635fc6907">Oleg Isonen</a>, <a href="https://twitter.com/pixelmorgan">Morgan Packard</a>, <a href="https://medium.com/u/9aeb70f759bb">Oliver Turner</a> and <a href="https://medium.com/u/97268045db5c">Andy Wermke</a> for their feedback.</p><figure><a href="https://usejournal.com/?utm_source=medium.com&amp;utm_medium=noteworthy_blog&amp;utm_campaign=guest_post_image"><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*f2IVAl0TbsfES9cFGYr40g.png" /></a></figure><p><strong>This story is published in Noteworthy, where 10,000+ readers come every day to learn about the people &amp; ideas shaping the products we love.</strong></p><p><strong>Follow our publication to see more product &amp; design stories featured by the </strong><a href="https://usejournal.com/?utm_source=medium.com&amp;utm_medium=noteworthy_blog&amp;utm_campaign=guest_post_text"><strong>Journal</strong></a><strong> team.</strong></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=37fbe20dfe8e" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[React 16.0–16.6 new features for every day use]]></title>
            <link>https://medium.com/hackernoon/react-16-0-16-3-new-features-for-every-day-use-f397da374acf?source=rss-b031a508ddaf------2</link>
            <guid isPermaLink="false">https://medium.com/p/f397da374acf</guid>
            <category><![CDATA[react]]></category>
            <category><![CDATA[jsx]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[front-end-development]]></category>
            <dc:creator><![CDATA[Artem Sapegin]]></dc:creator>
            <pubDate>Tue, 15 May 2018 14:55:14 GMT</pubDate>
            <atom:updated>2019-03-27T19:15:50.057Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*kUv3w5Zs6kxhqUMb." /><figcaption>Photo by <a href="https://unsplash.com/@sapegin?utm_source=medium&amp;utm_medium=referral">Artem Sapegin</a> on <a href="https://unsplash.com/?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><p>This is a short cheat sheet for developers migrating from React 15 to React 16, or from earlier 16.x versions to 16.6. It focuses on features you’ll use often.</p><h4>Returning multiple elements from components with fragments</h4><p>Splitting UI into small reusable components may lead to creation of unnecessary DOM elements, like when you need to return multiple elements from a component. React 16 has several options to avoid that:</p><pre>// React 15: extra wrapper element<br>const Breakfast = () =&gt; (<br>  &lt;ul&gt;<br>    &lt;li&gt;Coffee&lt;/li&gt;<br>    &lt;li&gt;Croissant&lt;/li&gt;<br>    &lt;li&gt;Marmalade&lt;/li&gt;<br>  &lt;/ul&gt;<br>);<br><br>// React 16.0: array (note that keys are required)<br>const Breakfast = () =&gt; [<br>  &lt;li key=&quot;coffee&quot;&gt;Coffee&lt;/li&gt;,<br>  &lt;li key=&quot;croissant&quot;&gt;Croissant&lt;/li&gt;,<br>  &lt;li key=&quot;marmalade&quot;&gt;Marmalade&lt;/li&gt;<br>];<br><br>// React 16.2: fragment<br>const Breakfast = () =&gt; (<br>  &lt;React.Fragment&gt;<br>    &lt;li&gt;Coffee&lt;/li&gt;<br>    &lt;li&gt;Croissant&lt;/li&gt;<br>    &lt;li&gt;Marmalade&lt;/li&gt;<br>  &lt;/React.Fragment&gt;<br>);<br><br>// React 16.2: fragment (short syntax)<br>const Breakfast = () =&gt; (<br>  &lt;&gt;<br>    &lt;li&gt;Coffee&lt;/li&gt;<br>    &lt;li&gt;Croissant&lt;/li&gt;<br>    &lt;li&gt;Marmalade&lt;/li&gt;<br>  &lt;/&gt;<br>);<br><br>// React 16: fragments composition<br>const Meals = (<br>  &lt;ul&gt;<br>    &lt;Breakfast /&gt;<br>    &lt;Lunch /&gt;<br>    &lt;Dinner /&gt;<br>  &lt;/ul&gt;<br>);</pre><p>Note that the short syntax may not be supported by <a href="https://reactjs.org/blog/2017/11/28/react-v16.2.0-fragment-support.html#support-for-fragment-syntax">the tools you’re using</a>.</p><h4>Returning strings and numbers from components</h4><p>In React 16 components can return strings and numbers. This is useful for components that don’t need any markup, like internationalization or formatting:</p><pre>// React 15<br>const LocalDate = ({ date }) =&gt; (<br>  &lt;span&gt;<br>    {date.toLocaleDateString(&#39;de-DE&#39;, {<br>      year: &#39;numeric&#39;,<br>      month: &#39;long&#39;,<br>      day: &#39;numeric&#39;<br>    })}<br>  &lt;/span&gt;<br>);<br><br>// React 16<br>const LocalDate = ({ date }) =&gt;<br>  date.toLocaleDateString(&#39;de-DE&#39;, {<br>    year: &#39;numeric&#39;,<br>    month: &#39;long&#39;,<br>    day: &#39;numeric&#39;<br>  });</pre><h4>Cancelling setState() to avoid rerendering</h4><p>In React 15 it wasn’t possible to cancel setState() and avoid rerendering, if your next state was based on the previous state. In React 16 you could return null in setState()’s callback:</p><pre>// React 16<br>handleChange = event =&gt; {<br>  const city = event.target.value;<br>  this.setState(<br>    prevState =&gt; (prevState.city !== city ? { city } : null)<br>  );<br>};</pre><p>In this example calling handleChange() with the same city name as in the state won’t cause a rerender.</p><h4>Avoiding prop drilling with the official context API (16.3)</h4><p><a href="https://blog.kentcdodds.com/prop-drilling-bb62e02cb691">Prop drilling</a> is when you’re passing some data to a deeply nested component using a prop, so you have to add this prop to each layer of your React component tree between a component that owns the data and a component that consumes it.</p><pre>class Root extends React.Component {<br>  state = { theme: THEME_DARK };<br>  handleThemeToggle = theme =&gt;<br>    this.setState(({ theme }) =&gt; ({<br>      theme: theme === THEME_DARK ? THEME_LIGHT : THEME_DARK;<br>    }));<br>  render() {<br>    return (<br>      &lt;Page<br>        onThemeToggle={this.handleThemeToggle}<br>        {...this.state}<br>        {...this.props}<br>      /&gt;<br>    );<br>  }<br>}</pre><pre>// Each layer will have to pass theme and theme toggle handler props<br>&lt;SomeOtherComponent<br>  onThemeToggle={props.onThemeToggle}<br>  theme={props.theme}<br>/&gt;;</pre><pre>// Many layers below<br>const Header = ({ theme, onThemeToggle }) =&gt; (<br>  &lt;header className={cx(&#39;header&#39;, `header--${theme}`)}&gt;<br>    ...<br>    &lt;button onClick={onThemeToggle}&gt;Toggle theme&lt;/button&gt;<br>  &lt;/header&gt;<br>);</pre><p>That’s a lot of boilerplate code! With the <a href="https://reactjs.org/docs/context.html">context API</a> we can access our theme props anywhere in the component tree:</p><pre>const ThemeContext = React.createContext(THEME_DARK);</pre><pre>// We should wrap our app in this component<br>class ThemeProvider extends React.Component {<br>  state = { theme: THEME_DARK };<br>  handleThemeToggle = theme =&gt;<br>    this.setState(({ theme }) =&gt; ({<br>      theme: theme === THEME_DARK ? THEME_LIGHT : THEME_DARK<br>    }));<br>  render() {<br>    return (<br>      &lt;ThemeContext.Provider<br>        value={{<br>          onThemeToggle: this.handleThemeToggle,<br>          theme: this.state.theme<br>        }}<br>      &gt;<br>        {this.props.children}<br>      &lt;/ThemeContext.Provider&gt;<br>    );<br>  }<br>}</pre><pre>// And then use theme consumer anywhere in the component tree<br>const Header = () =&gt; (<br>  &lt;ThemeContext.Consumer&gt;<br>    {({ theme, onThemeToggle }) =&gt; (<br>      &lt;header className={cx(&#39;header&#39;, `header--${theme}`)}&gt;<br>        ...<br>        &lt;button onClick={onThemeToggle}&gt;Toggle theme&lt;/button&gt;<br>      &lt;/header&gt;<br>    )}<br>  &lt;/ThemeContext.Consumer&gt;<br>);</pre><p><a href="https://codesandbox.io/s/l43j6j2n7z">Check out an example</a> on CodeSandbox.</p><h4>Updating state based on props with getDerivedStateFromProps() (16.3)</h4><p>The getDerivedStateFromProps() lifecycle method is a replacement for componentWillReceiveProps(). It’s useful when you have a prop with a default value for a state property, but you want to reset the state when that prop changes. For example, a modal that has a prop that says if it’s initially open, and a state that says if a modal is open now:</p><pre>// React 15<br>class Modal extends React.Component {<br>  state = {<br>    isOpen: this.props.isOpen<br>  };<br>  componentWillReceiveProps(nextProps) {<br>    if (nextProps.isOpen !== this.state.isOpen) {<br>      this.setState({<br>        isOpen: nextProps.isOpen<br>      });<br>    }<br>  }<br>}<br><br>// React 16.3<br>class Modal extends React.Component {<br>  state = {};<br>  static getDerivedStateFromProps(nextProps, prevState) {<br>    if (nextProps.isOpen !== prevState.isOpen) {<br>      return {<br>        isOpen: nextProps.isOpen<br>      };<br>    }<br>  }<br>}</pre><p>The getDerivedStateFromProps() method is called when a component is created and when it receives new props, so you don’t have to convert props to state twice (on initialization and in componentWillReceiveProps()).</p><h4>Rerendering function components on props change with React.memo() (16.6)</h4><p><a href="https://reactjs.org/docs/react-api.html#reactmemo">React.memo()</a> does the same for function components as <a href="https://reactjs.org/docs/react-api.html#reactpurecomponent">PureComponent</a> does for class components: only rerenders the component if its props change.</p><pre>const MyComponent = React.memo(props =&gt; {<br>  /* Only rerenders if props change */<br>});</pre><h4>Easier access to context in class components with contextType (16.6)</h4><p><a href="https://reactjs.org/blog/2018/10/23/react-v-16-6.html#static-contexttype">Class.contextType</a> simplifies access to the React context <em>in class components</em>:</p><pre>class App extends React.Component {<br>  static contextType = ThemeContext;<br>  componentDidMount() {<br>    const { theme } = this.context;<br>    /* ... */<br>  }<br>  componentDidUpdate() {<br>    const { theme } = this.context;<br>    /* ... */<br>  }<br>  componentWillUnmount() {<br>    const { theme } = this.context;<br>    /* ... */<br>  }<br>  render() {<br>    const { theme } = this.context;<br>    return (<br>      &lt;h1&gt;<br>        {theme === THEME_DARK<br>          ? &#39;Welcome to the dark side!&#39;<br>          : &#39;Welcome to the light side!&#39;}<br>      &lt;/h1&gt;<br>    );<br>  }<br>}</pre><h4>Other new features</h4><p>React 16.x has many other useful features:</p><ul><li><a href="https://reactjs.org/docs/error-boundaries.html">error boundaries</a>;</li><li><a href="https://reactjs.org/docs/portals.html">portals</a>;</li><li><a href="https://reactjs.org/docs/forwarding-refs.html">forwarding refs</a> (16.3);</li><li><a href="https://reactjs.org/docs/context.html">the new context API</a> (16.3);</li><li><a href="https://reactjs.org/docs/react-component.html#getsnapshotbeforeupdate">getSnapshotBeforeUpdate() lifecycle method</a> (16.3);</li><li><a href="https://reactjs.org/blog/2018/03/29/react-v-16-3.html">StrictMode component</a> (16.3);</li><li><a href="https://reactjs.org/blog/2018/05/23/react-v-16-4.html#pointer-events">pointer events</a> (16.4);</li><li><a href="https://reactjs.org/blog/2018/09/10/introducing-the-react-profiler.html">profiler</a> (16.5);</li><li><a href="https://reactjs.org/blog/2018/10/23/react-v-16-6.html#reactlazy-code-splitting-with-suspense">React.lazy</a> (16.6);</li><li><a href="https://reactjs.org/blog/2018/10/23/react-v-16-6.html#static-getderivedstatefromerror">static getDerivedStateFromError()</a> (16.6).</li></ul><p>I also highly recommend Nik Graf’s <a href="https://egghead.io/courses/leverage-new-features-of-react-16">course on React 16</a> at Egghead.</p><p><strong>Subscribe to my newsletter: </strong><a href="https://tinyletter.com/sapegin"><strong>https://tinyletter.com/sapegin</strong></a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=f397da374acf" width="1" height="1" alt=""><hr><p><a href="https://medium.com/hackernoon/react-16-0-16-3-new-features-for-every-day-use-f397da374acf">React 16.0–16.6 new features for every day use</a> was originally published in <a href="https://medium.com/hackernoon">HackerNoon.com</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[React Styleguidist 7.0.0- hello webpack 4, goodbye Node.js 4]]></title>
            <link>https://medium.com/hackernoon/react-styleguidist-7-0-0-hello-webpack-4-goodbye-node-js-4-257a9c6a6e72?source=rss-b031a508ddaf------2</link>
            <guid isPermaLink="false">https://medium.com/p/257a9c6a6e72</guid>
            <category><![CDATA[style-guides]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[components]]></category>
            <category><![CDATA[react]]></category>
            <category><![CDATA[design-systems]]></category>
            <dc:creator><![CDATA[Artem Sapegin]]></dc:creator>
            <pubDate>Thu, 05 Apr 2018 10:13:17 GMT</pubDate>
            <atom:updated>2018-04-05T11:59:39.241Z</atom:updated>
            <content:encoded><![CDATA[<h3>React Styleguidist 7: hello webpack 4, goodbye Node.js 4, and more</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*bWkGapCbXkw3yYe9zX3FyQ.jpeg" /><figcaption>Photo by <a href="https://unsplash.com/photos/Ke4Ut8IDkuQ?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Artem Sapegin</a> on <a href="https://unsplash.com/@sapegin?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></figcaption></figure><p>👋 <a href="https://opencollective.com/styleguidist"><strong>Support Styleguidist</strong></a><strong> on Open Collective</strong> 👋</p><p>I’m happy to announce a new major release of <a href="https://react-styleguidist.js.org/">React Styleguidist</a>.</p><h4>Webpack 4 support</h4><p>Webpack 3 is still supported too.</p><h4>Node.js 6 is the lowest supported version</h4><p>Styleguidist won’t work with Node.js 4 anymore.</p><h4>Examples are wrapped in React.Fragment</h4><p>You don’t need to wrap multiple JSX tags in a div anymore.</p><pre>// 6.x<br>&lt;div&gt;<br>  &lt;Button primary&gt;Primary button&lt;/Button&gt;<br>  &lt;Button secondary&gt;Secondary button&lt;/Button&gt;<br>&lt;/div&gt;<br><br><br>// 7.x<br>&lt;Button primary&gt;Primary button&lt;/Button&gt;<br>&lt;Button secondary&gt;Secondary button&lt;/Button&gt;</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/698/1*4cT3hug3aD7WF5GXNkpl4Q.png" /></figure><p>Fragment JSX syntax also works:</p><pre>// 7.x<br>&lt;&gt;<br>  &lt;Button primary&gt;Primary button&lt;/Button&gt;<br>  &lt;Button secondary&gt;Secondary button&lt;/Button&gt;<br>&lt;/&gt;</pre><h4>New format of the template option</h4><p>We’re now using <a href="https://github.com/styleguidist/mini-html-webpack-plugin">mini-html-webpack-plugin</a> and <a href="https://github.com/vxna/mini-html-webpack-template">@vxna/mini-html-webpack-template</a> instead of <a href="https://github.com/jantimon/html-webpack-plugin">html-webpack-plugin</a>. This will make things like <a href="https://react-styleguidist.js.org/docs/cookbook#how-to-add-a-favicon">adding a favicon</a> or fonts from <a href="https://react-styleguidist.js.org/docs/cookbook#how-to-add-fonts-from-google-fonts">Google Fonts</a> much easier.</p><p>If you’re using a custom HTML template, you need to update your style guide config. Instead of:</p><pre>// 6.x<br>module.exports = {<br>  template: &#39;./styleguie/template.html&#39;<br>}</pre><p>You need to use something like this:</p><pre>// 7.x<br>module.exports = {<br>  template: {<br>    favicon: &#39;https://assets-cdn.github.com/favicon.ico&#39;<br>  }<br>}</pre><p>Or like this:</p><pre>// 7.x<br>module.exports = {<br>  template: {<br>    head: {<br>      links: [<br>        {<br>          rel: &#39;stylesheet&#39;,<br>          href: &#39;https://fonts.googleapis.com/css?family=Roboto&#39;<br>        }<br>      ]<br>    }<br>  },<br>  theme: {<br>    fontFamily: {<br>      base: &#39;&quot;Roboto&quot;, sans-serif&#39;<br>    }<br>  }<br>}</pre><p>There are a few more changes, see <a href="https://github.com/styleguidist/react-styleguidist/releases/tag/v7.0.0">a full change log</a>.</p><p>❤️ Huge thanks to <a href="https://medium.com/u/5829a67c85f9">Andrey Okonetchnikov</a>, <a href="https://medium.com/u/a45523da9d91">Nikolay Burlov</a>, <a href="https://medium.com/u/7f28843c6e39">Rubén Moya</a> and others for help with this release️! ❤️</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=257a9c6a6e72" width="1" height="1" alt=""><hr><p><a href="https://medium.com/hackernoon/react-styleguidist-7-0-0-hello-webpack-4-goodbye-node-js-4-257a9c6a6e72">React Styleguidist 7.0.0- hello webpack 4, goodbye Node.js 4</a> was originally published in <a href="https://medium.com/hackernoon">HackerNoon.com</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[No complaints policy]]></title>
            <link>https://medium.com/hackernoon/no-complaints-policy-b5a537b86aec?source=rss-b031a508ddaf------2</link>
            <guid isPermaLink="false">https://medium.com/p/b5a537b86aec</guid>
            <category><![CDATA[open-source]]></category>
            <category><![CDATA[no-complaints-policy]]></category>
            <category><![CDATA[burnout]]></category>
            <category><![CDATA[github]]></category>
            <category><![CDATA[hobby]]></category>
            <dc:creator><![CDATA[Artem Sapegin]]></dc:creator>
            <pubDate>Sat, 27 Jan 2018 21:37:40 GMT</pubDate>
            <atom:updated>2018-02-08T09:39:16.062Z</atom:updated>
            <content:encoded><![CDATA[<h3>No complaints policy in open source</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*SbCPg0VfK5qy9Zl7lvTRCw.jpeg" /><figcaption>Photo by <a href="https://unsplash.com/@sapegin">yours truly</a></figcaption></figure><p>I love the open source community, especially the React ecosystem. Most of the folks there are supernice and helping each other. But sometimes something goes wrong.</p><p>I value my time and even more I value my mental health. I want to continue contributing to open source and avoid burnout. I try to be nice and helpful to every user of my projects. But sometimes it’s hard.</p><p>Every time I see or feel that someone is complaining about my project or my actions, or any unhealthy behavior towards me or other users, I immediately lock the conversation, or even block the user. I see it as the only way to continue working on open source.</p><p>There are many ways you can make folks in the open source community happier:</p><ul><li>new feature specs (better than just ideas because they’re often not actionable);</li><li>detailed easily reproducible bug reports;</li><li>any maintenance help, like answering questions on GitHub, Stack Overflow or Twitter.</li><li>bugfixes;</li><li>new features;</li><li>docs improvements.</li></ul><p>Other people are experiencing similar issues:</p><ul><li><a href="https://medium.com/@fox/the-dark-side-of-open-source-ba5a66c8a4c3">The Dark Side of Open Source</a> by Karolina Szczur</li><li><a href="http://thejameskyle.com/dear-javascript.html">Dear JavaScript</a> by James Kyle</li><li><a href="https://www.kennethreitz.org/essays/the-reality-of-developer-burnout">The Reality of Developer Burnout</a> by Kenneth Reitz</li></ul><p>Let’s keep this community healthy and friendly!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=b5a537b86aec" width="1" height="1" alt=""><hr><p><a href="https://medium.com/hackernoon/no-complaints-policy-b5a537b86aec">No complaints policy</a> was originally published in <a href="https://medium.com/hackernoon">HackerNoon.com</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Automating open source project configuration with Mrm]]></title>
            <link>https://medium.com/hackernoon/automating-open-source-project-configuration-with-mrm-7f67fd55a9b0?source=rss-b031a508ddaf------2</link>
            <guid isPermaLink="false">https://medium.com/p/7f67fd55a9b0</guid>
            <category><![CDATA[open-source]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[codemod]]></category>
            <category><![CDATA[mrm]]></category>
            <category><![CDATA[configuration-management]]></category>
            <dc:creator><![CDATA[Artem Sapegin]]></dc:creator>
            <pubDate>Sun, 03 Dec 2017 20:29:34 GMT</pubDate>
            <atom:updated>2017-12-03T20:29:34.404Z</atom:updated>
            <content:encoded><![CDATA[<p>We use many tools, like linters, test runners and continuous integration, to make our life as developers easier. But maintaining configuration for these tools is far from easy, especially if you want up-to-date configs in all your projects. <a href="https://github.com/sapegin/mrm">Mrm</a> tries to solve this problem.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ErDZPxz5bSZOwXXV2YwIKA.jpeg" /><figcaption><em>Slightly different files. Photo by </em><a href="http://morning.photos/albums/travel/2009-09-17-0908">yours truly</a>.</figcaption></figure><h4>What’s the problem</h4><p>The only thing that many times was preventing me from extracting some generic function to a separate package is a need to copy and modify a dozen of config files — all that .somethingrcs — just to publish a 50-line function.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1006/1*PgcpIZP23kObiRWas6DvOg.png" /></figure><p>These support files are usually only <em>slightly different</em> in all your projects. For example, a .gitignore file has node_modules and editor artifacts that you want to share between all your projects, but some projects have extra lines there that you don’t want in other projects. We need a way to keep in sync the common parts but allow per-project customizations.</p><p>Template-based tools, like Yeoman, are good for initial project bootstrapping but don’t work well for updates: they would overwrite a file with a new version and you’ll lose your customizations.</p><h4>What’s Mrm</h4><p><a href="https://github.com/sapegin/mrm">Mrm</a> takes a different approach. It works similar to <a href="https://www.sitepoint.com/getting-started-with-codemods/">codemods</a>: instead of a template that would overwrite everything, you’re describing in code how to <em>modify</em> or create files to achieve the desired state of the file.</p><h4>Minimal changes</h4><p>Mrm tries to do minimal changes by inferring indentation style or reading it from the EditorConfig, and keeping comments in JSON files.</p><h4>Minimal config</h4><p>It has minimal required configuration: it’ll use values from the project itself or from the environment, like reading your name and email from your Git or npm configs.</p><h4>Focused but rich API</h4><p>Mrm has utilities to work with popular config file formats: JSON, YAML, INI and new line separated text files; install npm packages; and file operations.</p><p>This allows you to create smart <em>tasks</em>, so the result depends on your project needs.</p><h4>Available tasks</h4><p>Mrm has <a href="https://github.com/sapegin/mrm-tasks/tree/master/packages/mrm-preset-default">many tasks</a> out of the box: CodeCov, EditorConfig, ESLint, .gitignore, Jest, lint-staged, Prettier, semantic-release, React Styleguidist, stylelint, Travis CI, TypeScript, package.json, contributing guidelines, license and readme file. You can create your own task or combine multiple tasks using aliases.</p><p>For example, the <a href="https://github.com/sapegin/mrm-tasks/tree/master/packages/mrm-task-jest">Jest task</a>:</p><ul><li>adds npm scripts to run Jest;</li><li>adds configuration to package.json if needed;</li><li>updates .gitignore, .npmignore, .eslintignore with common patterns;</li><li>installs Jest, babel-jest, ts-jest or Enzyme if needed;</li><li>tries to get rid of Mocha and AVA configs and dependencies;</li><li>suggests to us jest-codemods if projects used other test frameworks.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/784/1*yf_sYeuA-In-1PeByYhlQQ.png" /></figure><p>Or the <a href="https://github.com/sapegin/mrm-tasks/tree/master/packages/mrm-task-gitignore">gitignore task</a> that will add new lines to the .gitignore file but won’t remove per-project customizations:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/724/1*zdgk92kH_j7FaLH8x_pPaA.png" /></figure><h4>Installation and usage</h4><p>Install Mrm from npm:</p><pre>npm install -g mrm</pre><p>And run like this:</p><pre>mrm gitignore<br>mrm license --config:licenseFile LICENSE</pre><p>Or run Mrm via <a href="https://medium.com/@maybekatz/introducing-npx-an-npm-package-runner-55f7d4bd282b">npx</a> without installation:</p><pre>npx mrm gitignore<br>npx mrm license --config:licenseFile LICENSE</pre><p>Optionally, create a config file at ~/.mrm/config.json or ~/dotfiles/mrm/config.json instead of passing values via command line:</p><pre>{<br>  &quot;github&quot;: &quot;sapegin&quot;,<br>  &quot;eslintPreset&quot;: &quot;airbnb&quot;,<br>  &quot;aliases&quot;: {<br>    // Aliases to run multiple tasks at once<br>    &quot;node&quot;: [&quot;license&quot;, &quot;readme&quot;, &quot;editorconfig&quot;, &quot;gitignore&quot;]<br>  }<br>}</pre><p>See more usage examples and options <a href="https://github.com/sapegin/mrm#usage">in the docs</a>.</p><h4>Creating your own tasks</h4><p>The real power of Mrm is in custom tasks and <a href="https://github.com/sapegin/mrm-core">mrm-core library</a> that gives you tools to work with config files, dependencies, file operations, etc.</p><p>The simplest task could look like this:</p><pre>// Mrm module to work with new line separated text files<br>const { lines } = require(&#39;mrm-core&#39;);<br><br>function task() {<br>  // Read .gitignore if it exists<br>  lines(&#39;.gitignore&#39;)<br>    // Add lines that do not exist in a file yet,<br>    // but keep all existing lines<br>    .add([&#39;node_modules/&#39;, &#39;.DS_Store&#39;])<br>    // Update or create a file<br>    .save();<br>}<br><br>task.description = &#39;Adds .gitignore&#39;;<br>module.exports = task;</pre><p>See more examples <a href="https://github.com/sapegin/mrm#writing-your-own-tasks">in the docs</a>.</p><p>You can save your tasks locally, <a href="https://github.com/sapegin/mrm#sharing-tasks-via-npm">publish them on npm</a> or combine multiple tasks <a href="https://github.com/sapegin/mrm#custom-presets">in a preset</a>.</p><h4>Conclusion</h4><p>If you have many projects with a similar stack or a big multi-repository project, <a href="https://github.com/sapegin/mrm">Mrm</a> may be a good way to manage their configuration and could save your time.</p><p>Start with default tasks and then write your own or create a preset for your project or organization.</p><p>The project is still young — let me know what you think in comments or <a href="https://github.com/sapegin/mrm/issues">GitHub issues</a>.</p><p>P.S. Check out our new book on <a href="https://survivejs.com/maintenance/">JavaScript projects maintenance</a>.</p><p><em>Thanks to </em><a href="https://medium.com/u/82815f6b43dc"><em>Anna Gerus</em></a><em>, </em><a href="https://medium.com/u/4a0f6a534c55"><em>Karl Horky</em></a><em>, </em><a href="https://medium.com/u/5829a67c85f9"><em>Andrey Okonetchnikov</em></a><em>, </em><a href="https://medium.com/u/7c635fc6907"><em>Oleg Slobodskoi</em></a><em>, Olga Sylenko, </em><a href="https://medium.com/u/a82419fa03ca"><em>Juho Vepsäläinen</em></a><em>.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=7f67fd55a9b0" width="1" height="1" alt=""><hr><p><a href="https://medium.com/hackernoon/automating-open-source-project-configuration-with-mrm-7f67fd55a9b0">Automating open source project configuration with Mrm</a> was originally published in <a href="https://medium.com/hackernoon">HackerNoon.com</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Testing React Intl components with Jest and Enzyme]]></title>
            <link>https://medium.com/@sapegin/testing-react-intl-components-with-jest-and-enzyme-f9d43d9c923e?source=rss-b031a508ddaf------2</link>
            <guid isPermaLink="false">https://medium.com/p/f9d43d9c923e</guid>
            <category><![CDATA[jest]]></category>
            <category><![CDATA[react]]></category>
            <category><![CDATA[testing]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[enzyme]]></category>
            <dc:creator><![CDATA[Artem Sapegin]]></dc:creator>
            <pubDate>Fri, 17 Nov 2017 15:37:44 GMT</pubDate>
            <atom:updated>2017-11-17T16:42:01.561Z</atom:updated>
            <content:encoded><![CDATA[<p>There are two problems with testing components that use <a href="https://github.com/yahoo/react-intl">React Intl</a> with <a href="https://github.com/airbnb/enzyme">Enzyme</a> and <a href="https://facebook.github.io/jest/">Jest</a>:</p><ol><li>injectIntl higher-order component will break shallow rendering because it will render a wrapper component instead of your component.</li><li>An intl prop will make snapshot testing useless because each snapshot will contain all your messages.</li></ol><p>The solution is based on <a href="https://github.com/yahoo/react-intl/wiki/Testing-with-React-Intl">React Intl’s wiki</a>:</p><ol><li>Add two new helper functions to your Jest setup file (<a href="http://facebook.github.io/jest/docs/en/tutorial-react-native.html#setupfiles">setupFiles</a>):</li></ol><pre>import { IntlProvider, intlShape } from &quot;react-intl&quot;;<br><br>// Create IntlProvider to retrieve React Intl context<br>const intlProvider = new IntlProvider(<br>  {<br>    locale: &quot;en&quot;,<br>    messages: {<br>      message1: &quot;Hello world&quot;<br>    }<br>  },<br>  {}<br>);<br>const { intl } = intlProvider.getChildContext();<br><br>// `intl` prop is required when using injectIntl HOC<br>const nodeWithIntlProp = node =&gt; React.cloneElement(node, { intl });<br><br>// shallow() with React Intl context<br>global.shallowWithIntl = (node, { context, ...options } = {}) =&gt; {<br>  return shallow(nodeWithIntlProp(node), {<br>    ...options,<br>    context: {<br>      ...context,<br>      intl<br>    }<br>  });<br>};</pre><pre>// mount() with React Intl context<br>global.mountWithIntl = (<br>  node,<br>  { context, childContextTypes, ...options } = {}<br>) =&gt; {<br>  return mount(nodeWithIntlProp(node), {<br>    ...options,<br>    context: {<br>      ...context,<br>      intl<br>    },<br>    childContextTypes: {<br>      intl: intlShape,<br>      ...childContextTypes<br>    }<br>  });<br>};</pre><p>2. Export your component with and without injectIntl:</p><pre>import React, { Component } from &quot;react&quot;;<br>import { injectIntl } from &quot;react-intl&quot;;<br><br>export class Pony extends Component {<br>  /* _ */<br>}<br><br>export default injectIntl(Pony);</pre><p>3. Write test cases almost as usual, using the shallowWithIntl and mountWithIntl helpers:</p><pre>import React from &quot;react&quot;;<br>import { Pony } from &quot;./Pony&quot;;<br><br>test(&quot;pink pony&quot;, () =&gt; {<br>  const wrapper = shallowWithIntl(&lt;Pony color=&quot;pink&quot; /&gt;);<br>  expect(wrapper).toMatchSnapshot();<br>  expect(wrapper.find(&quot;.tail&quot;).prop(&quot;value&quot;)).toBe(&quot;pink&quot;);<br>});</pre><p>P. S. You may also enjoy my more generic article on <a href="http://blog.sapegin.me/all/react-jest">testing React components with Jest and Enzyme</a> and <a href="https://github.com/sapegin/jest-cheat-sheet">Jest cheat sheet</a>.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=f9d43d9c923e" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Why robots should format our code for us]]></title>
            <link>https://medium.com/free-code-camp/why-robots-should-format-our-code-159fd06d17f7?source=rss-b031a508ddaf------2</link>
            <guid isPermaLink="false">https://medium.com/p/159fd06d17f7</guid>
            <category><![CDATA[productivity]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[tech]]></category>
            <category><![CDATA[self-improvement]]></category>
            <category><![CDATA[programming]]></category>
            <dc:creator><![CDATA[Artem Sapegin]]></dc:creator>
            <pubDate>Sun, 08 Oct 2017 14:00:58 GMT</pubDate>
            <atom:updated>2019-03-27T19:16:20.150Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*U-jFxHWyzxtZTGtS6Q2CQQ.jpeg" /><figcaption>Photo by <a href="http://unsplash.com/photos/b18TRXc8UPQ?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">yours truly</a> on <a href="https://unsplash.com/?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></figcaption></figure><p>I used to think that a personal code style is a good thing for a programmer. It shows you are a mature developer who knows what good code should look like.</p><p>My college professors told me that they knew when some of my classmates used my code in their work because of the different code style. Now I think it was because my code was at least somehow formatted and everyone else’s was a mess.</p><p>Since then I’ve spent a lot of time arguing code style and configuring tools to enforce it. It’s time for a change.</p><h4>A few examples</h4><p>After reading the <a href="https://www.datapacrat.com/Opinion/Reciprocality/r0/index.html">The Programmers’ Stone</a> I put braces like this for a long time:</p><pre>if (food === &#39;pizza&#39;)<br>{<br>    alert(&#39;Pizza ;-)&#39;);  <br>}<br>else<br>{  <br>    alert(&#39;Not pizza ;-(&#39;);<br>}</pre><p>But then I realized that I may be the only one who did it that way in the front-end community. Everybody else uses this style:</p><pre>if (food === &#39;pizza&#39;) {<br>    alert(&#39;Pizza ;-)&#39;);  <br>} else {<br>    alert(&#39;Not pizza ;-(&#39;);<br>}</pre><p>Or this:</p><pre>if (food === &#39;pizza&#39;) {<br>    alert(&#39;Pizza ;-)&#39;);  <br>}<br>else {  <br>    alert(&#39;Not pizza ;-(&#39;);<br>}</pre><p>So I’ve changed my style to the last one.</p><p>I like this style for chaining very much:</p><pre>function foo(items) {<br>  return items<br>    .filter(item =&gt; item.checked)<br>    .map(item =&gt; item.value)<br>  ;<br>}</pre><p>I see the same refactoring benefits as for <a href="https://medium.com/@nikgraf/why-you-should-enforce-dangling-commas-for-multiline-statements-d034c98e36f8">trailing commas</a>:</p><pre>const food = [<br>  &#39;pizza&#39;,<br>  &#39;burger&#39;,<br>  &#39;pasta&#39;,<br>]</pre><p>But I’m probably even more lonely with this style than I was with braces. Nobody would ever send me code for review with this style, no linter can enforce it. So I have to stop using it too to be closer to the real world.</p><p>There’s another thing that nobody else does except me . I always put two spaces before end-of-the-line comment:</p><pre>const volume = 200;  // ml</pre><p>I thought it improves readability. But it actually makes the codebase inconsistent because other developers only put one space.</p><h4>What JavaScript developers do</h4><p>Unfortunately JavaScript has no official code style. There are a few <a href="http://blog.sapegin.me/all/javascript-code-styles">popular code styles</a> like <a href="http://airbnb.io/javascript/">Airbnb</a> or <a href="https://standardjs.com/">Standard</a>. You could use them to make your code look familiar to other developers.</p><p>You could use <a href="https://eslint.org/">ESLint </a>to enforce code style and even autoformat code in some cases. But it won’t make your code base 100% consistent. ESLint with Airbnb config would normalize only my first example and allow inconsistency in the other two examples.</p><h4>What JavaScript developers should do</h4><p>Some languages have strict code styles and tools to format code. So developers don’t waste time arguing code style. Look at <a href="https://reasonml.github.io/guide/what-and-why">Refmt</a> for Reason and <a href="https://github.com/rust-lang-nursery/rustfmt">Rustfmt</a> for Rust.</p><p>It looks like JavaScript finally <a href="http://jlongster.com/A-Prettier-Formatter">has a solution</a> to this problem. A new tool called <a href="https://github.com/prettier/prettier">Prettier</a> will reformat your code using its own rules. It completely ignores how the code was written in the first place.</p><p>Let’s <a href="https://prettier.github.io/prettier/">try Prettier</a> on my examples:</p><pre>if (food === &#39;pizza&#39;) {<br>  alert(&#39;Pizza ;-)&#39;);<br>} else {<br>  alert(&#39;Not pizza ;-(&#39;);<br>}<br><br>function foo(items) {<br>  return items.filter(item =&gt; item.checked).map(item =&gt; item.value);<br>}<br><br>const volume = 200; // ml</pre><p>You can disagree with this style. For example I don’t like the else placement and writing function chains in one line is questionable. But I see huge benefits in adopting Prettier:</p><ul><li>Almost no decisions to make — Prettier has few options.</li><li>No arguing about particular rules if you’re working in a team.</li><li>No need to learn your project’s code style for contributors.</li><li>No need to fix style issues reported by ESLint.</li><li>Possible to set up autoformat on file save.</li></ul><h4>Conclusion</h4><p>Prettier has been already adopted by <a href="https://github.com/prettier/prettier/issues/1351">some popular projects</a> like React and Babel. And I’m starting to <a href="https://github.com/tamiadev/eslint-config-tamia">convert all my projects</a> from my custom code style to Prettier. I will recommend it instead of the Airbnb code style.</p><p>At first I had a lot of “Ugh, that’s ugly” moments with Prettier. But when I think that I’d have to, for example, manually reformat JSX code from a single-line to multi-line when I add another prop and it doesn’t fit on one line — I realize that it’s totally worth it.</p><figure><img alt="Prettier" src="https://cdn-images-1.medium.com/max/1024/0*spj1CsmHiP8l4C5h.gif" /><figcaption>Prettier is formatting your code when you save a file</figcaption></figure><p>Read how to <a href="https://survivejs.com/maintenance/code-quality/code-formatting/">set up Prettier</a> in your project.</p><p>P. S. <a href="https://github.com/sapegin/mrm">Have a look at my new tool</a> that will simplify adding ESLint, Prettier, and other tools to your project, as well as keeping their configs in sync.</p><p><strong>Subscribe to my newsletter: </strong><a href="https://tinyletter.com/sapegin"><strong>https://tinyletter.com/sapegin</strong></a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=159fd06d17f7" width="1" height="1" alt=""><hr><p><a href="https://medium.com/free-code-camp/why-robots-should-format-our-code-159fd06d17f7">Why robots should format our code for us</a> was originally published in <a href="https://medium.com/free-code-camp">We’ve moved to freeCodeCamp.org/news</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>