<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Stef</title>
    <description>The latest articles on DEV Community by Stef (@stefee).</description>
    <link>https://dev.to/stefee</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%2F425415%2F46fe6430-876e-4f97-9bc8-deea08471bd1.jpg</url>
      <title>DEV Community: Stef</title>
      <link>https://dev.to/stefee</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/stefee"/>
    <language>en</language>
    <item>
      <title>Chakra UI is still great in 2024</title>
      <dc:creator>Stef</dc:creator>
      <pubDate>Sat, 17 Feb 2024 21:30:08 +0000</pubDate>
      <link>https://dev.to/stefee/chakra-ui-is-still-great-in-2024-p7</link>
      <guid>https://dev.to/stefee/chakra-ui-is-still-great-in-2024-p7</guid>
      <description>&lt;p&gt;I was working at a startup in 2021 (not my current role) and the company was going through a pivot which meant all of our existing code was being scrapped and we were starting again from scratch.&lt;/p&gt;

&lt;p&gt;The main project we'd developed up until that point was a React Native app used on tablets for managing stock and orders. The changes to the business model meant we were about to start work on an online B2B SaaS platform instead.&lt;/p&gt;

&lt;p&gt;Most of the dev team (including myself) had never worked on a SaaS application before. We had a mixture of web and native experience, a mixture of Java, Kotlin and JS/TS experience, and we had about six weeks to try to ship something.&lt;/p&gt;

&lt;p&gt;So why did we choose to use Chakra UI:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;We didn't want an extra build step for CSS, because we couldn't afford to spend time debugging build issues and we had limited CSS experience&lt;/li&gt;
&lt;li&gt;We wanted something that felt like React Native from a code perspective, because that's what we were used to&lt;/li&gt;
&lt;li&gt;We needed to create something presentable and usable, without design expertise, in a short amount of time, without creating a big mess of tech debt - Chakra UI was 'batteries included' and had a bunch of useful components&lt;/li&gt;
&lt;li&gt;Some of us had used Material UI in the past and had a bad experience with it - it's too complicated and full of gotchas, and it looks a bit dated&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  The honeymoon period
&lt;/h3&gt;

&lt;p&gt;Chakra UI was amazingly simple to install and start using. Everything worked first time.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://chakra-ui.com/docs/styled-system/theme"&gt;Chakra UI theme&lt;/a&gt; and layout components such as &lt;a href="https://chakra-ui.com/docs/components/stack/usage"&gt;Stack&lt;/a&gt; and &lt;a href="https://chakra-ui.com/docs/components/center"&gt;Center&lt;/a&gt; made it easy to build presentable layouts without design expertise. The layout code was simple enough that we could quickly try out different page layouts, so we didn't need to wireframe anything. It was really easy to throw together some basic forms with nice validation states using &lt;a href="https://chakra-ui.com/docs/components/form-control"&gt;Form&lt;/a&gt; components. I &lt;em&gt;loved&lt;/em&gt; using the &lt;a href="https://chakra-ui.com/docs/components/skeleton/usage"&gt;Skeleton&lt;/a&gt; component to make nice loading states. I'd never done anything like this before (I mostly worked on static content sites) so this was really fun.&lt;/p&gt;

&lt;p&gt;Something else caught my attention, which I hadn't realised at first. Chakra's theme system (which is based on &lt;a href="https://github.com/styled-system/styled-system/blob/master/docs/theme-specification.md"&gt;Styled System Theme Spec&lt;/a&gt;) is very powerful. I was surprised that it wasn't a lot more opinionated about styling considering the other benefits the library was offering, but the styling can be completely overridden using a &lt;a href="https://chakra-ui.com/docs/styled-system/customize-theme"&gt;custom theme&lt;/a&gt; which can also be extended for styling &lt;a href="https://chakra-ui.com/docs/styled-system/component-style"&gt;custom components&lt;/a&gt;. I had tried to do a similar thing on a previous project using &lt;a href="https://styled-components.com/"&gt;Styled Components&lt;/a&gt; to create white-label components that can be wrapped with different brand themes - Chakra UI is light-years ahead of that approach and I wish it had been around a few years earlier so we could've used it then.&lt;/p&gt;

&lt;p&gt;Back to the earlier story - we managed to ship something in time without creating a big mess, which was great. Unfortunately the business itself didn't work out, as is known to happen from time to time with startups.&lt;/p&gt;

&lt;p&gt;Chakra UI's theming system was, however, a significant factor in the decision to adopt Chakra UI at the company I've since been working at, and we've used it for all of our projects over the last couple of years.&lt;/p&gt;

&lt;h3&gt;
  
  
  The last couple of years
&lt;/h3&gt;

&lt;p&gt;We've been using Chakra UI in production for a couple of years now. How has it been so far?&lt;/p&gt;

&lt;p&gt;I think it's mostly been great. All of the things that were initially great about Chakra UI are still great about Chakra UI.&lt;/p&gt;

&lt;p&gt;I've put together some thoughts below on some of the specific highlights and lowlights I wanted to call out.&lt;/p&gt;

&lt;h4&gt;
  
  
  The theming system has helped a lot with design/dev alignment and handoff
&lt;/h4&gt;

&lt;p&gt;The &lt;a href="https://chakra-ui.com/figma/ui-kit"&gt;Figma kit&lt;/a&gt; has provided a good foundation for our internal library file. The theme system in Chakra UI itself is flexible and extensible enough that we haven't been concerned about deviating from the initial defaults. (You can see what our main application looks like on its &lt;a href="https://www.kobaltmusic.com/creator-portal/"&gt;product page&lt;/a&gt; - other companies have demonstrated this to an even greater degree, such as the &lt;a href="https://config.figma.com/"&gt;Figma Conf' 23&lt;/a&gt; site which also uses Chakra UI.)&lt;/p&gt;

&lt;h4&gt;
  
  
  Chakra UI has worked great for devs at all experience levels and backgrounds
&lt;/h4&gt;

&lt;p&gt;I think Chakra UI is really easy to use, but the real proof of this has been seeing the success that junior/mid and backend engineers have been able to have with it.&lt;/p&gt;

&lt;p&gt;I've found that it's been easy to maintain a good standard of code quality compared to the other approaches I've used in the past (CSS, &lt;a href="https://sass-lang.com/"&gt;Sass&lt;/a&gt;, and &lt;a href="https://styled-components.com/"&gt;Styled Components&lt;/a&gt;), which is maybe because the &lt;a href="https://chakra-ui.com/docs/styled-system/style-props"&gt;Style Props&lt;/a&gt; syntax in Chakra UI is just normal React code - this reduces the cognitive overhead of learning and writing Chakra UI code compared to the alternatives, especially for developers who are new to React and JS/TS.&lt;/p&gt;

&lt;h4&gt;
  
  
  New patch/minor releases sometimes broke our builds
&lt;/h4&gt;

&lt;p&gt;We've found that occasionally new releases of Chakra UI would cause breakages in our CI/CD builds due to breaking changes creeping into patch/minor releases. These are often fairly small things such as an ARIA role changing on an element causing our tests to fail. Sometimes they are harder to fix or it's unclear whether it's a bug or intended behaviour.&lt;/p&gt;

&lt;h4&gt;
  
  
  The source code seems overly complex and a bit too spooky for me
&lt;/h4&gt;

&lt;p&gt;I've jumped into the Chakra UI source code a few times to try and fix bugs. I find it scary how much stuff is going on in there. I feel like I can't trust it to not contain weird bugs due to the complexity of the codebase and the number of 3rd-party dependencies. (I think we've come across a few of these bugs, which is why I was looking at the source code to begin with!)&lt;/p&gt;

&lt;p&gt;I don't understand how all of the components work, such as the &lt;a href="https://chakra-ui.com/docs/components/toast/usage"&gt;Toast&lt;/a&gt; component - it seems like some of this stuff like &lt;a href="https://chakra-ui.com/docs/components/toast/usage#standalone-toasts"&gt;Standalone Toasts&lt;/a&gt; is breaking the rules of React by introducing global state. We've occasionally run into some issues with Chakra UI when writing unit tests (with &lt;a href="https://testing-library.com/docs/react-testing-library/intro/"&gt;React Testing Library&lt;/a&gt;) and I suspect some of those issues are a result of Chakra UI doing stuff it probably shouldn't be doing under the hood.&lt;/p&gt;

&lt;p&gt;Overall, I wish it was more 'basic React' and had less going on. I think this would also help to avoid breaking changes creeping into new minor/patch releases by mistake.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusions
&lt;/h3&gt;

&lt;p&gt;I still love Chakra UI despite its flaws.&lt;/p&gt;

&lt;p&gt;I love how accessible it is from a development perspective: it definitely levels the playing field and enables more people to build stuff with confidence and see immediate results from the start, regardless of whether your background is in web, native, backend or whatever. If you can learn to write React code then you can make stuff with Chakra UI.&lt;/p&gt;

&lt;p&gt;I'm wondering now what will happen with the project. The maintainers have mostly been working on new projects: &lt;a href="https://zagjs.com/"&gt;Zag&lt;/a&gt;, &lt;a href="https://ark-ui.com/"&gt;Ark UI&lt;/a&gt; and &lt;a href="https://panda-css.com/"&gt;Panda CSS&lt;/a&gt;. There were a couple of posts written by Sage explaining the plan with these:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.adebayosegun.com/blog/the-future-of-chakra-ui"&gt;The future of Chakra UI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.adebayosegun.com/blog/chakra-panda-ark-whats-the-plan"&gt;Chakra, Panda and Ark - What's the plan?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/thesegunadebayo/status/1744759129300947112"&gt;Prepping for a new major release of Chakra (v3)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I think Panda CSS looks great, especially for when you really care about page performance and you want to make extensive use of &lt;a href="https://nextjs.org/docs/app/building-your-application/rendering/server-components"&gt;Server Components&lt;/a&gt; - I'd actually really like to try it if I can find a project that demands it. On the other hand, it's an additional CLI tool that has to run both locally and in CI, and I like not having to think about &lt;a href="https://panda-css.com/docs/concepts/cascade-layers"&gt;Cascade Layers&lt;/a&gt;. The syntax also seems less friendly to me, but I need to try using it in practice.&lt;/p&gt;

&lt;p&gt;I still appreciate that Chakra UI doesn't require an extra build step for styling. It's one less thing that can go wrong, and that's saved us time in the long run. For our use case, I also don't really mind that it's not as optimal for end-user performance as some of the other approaches to styling (it uses &lt;a href="https://emotion.sh/docs/introduction"&gt;Emotion&lt;/a&gt; under the hood) - this is a worthwhile trade-off for what we gain in developer friendliness.&lt;/p&gt;

&lt;p&gt;I think integrating Ark UI into the Chakra UI codebase (as is planned, and I really hope will happen!) could reduce the complexity of the code as well as fixing some of the pain points we ran into, so I'm still holding out for this over the next couple of major releases.&lt;/p&gt;

&lt;p&gt;That's all for now!&lt;/p&gt;

</description>
      <category>react</category>
      <category>frontend</category>
    </item>
    <item>
      <title>Understanding React as a system</title>
      <dc:creator>Stef</dc:creator>
      <pubDate>Tue, 31 Aug 2021 07:49:13 +0000</pubDate>
      <link>https://dev.to/stefee/understanding-react-as-a-system-part-1-2knn</link>
      <guid>https://dev.to/stefee/understanding-react-as-a-system-part-1-2knn</guid>
      <description>&lt;p&gt;&lt;strong&gt;Note: since I started writing this series, the React team has published a new docs website. The new &lt;a href="https://beta.reactjs.org/learn/describing-the-ui"&gt;React Docs&lt;/a&gt; have put to bed pretty much all of the things which motivated me to write this, and they've done a much better job of explaining React for beginners than I've done here, so I recommend reading those docs instead.&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;I want to write about React to try and enable developers from various backgrounds to understand how it works, why it is good, and what it is good for.&lt;/p&gt;

&lt;p&gt;This is perhaps a rather lofty ambition. A lot of people have written about React already, so why do I feel the need to write this now?&lt;/p&gt;

&lt;p&gt;What I've found is that most of the writing about React is aimed specifically at front-end developers who are experienced in developing websites and other kinds of user interface code. I think maybe this is because the adoption of React in many teams has hinged on convincing the front-end developers in the team that it's something that they should be using.&lt;/p&gt;

&lt;p&gt;React is very popular now in teams of various sizes, which is great! What this means though is that developers from various different schools of thought are now developing products with React, many of whom might not have chosen to use it otherwise.&lt;/p&gt;

&lt;p&gt;My aim in writing this now is to try and help you to make the most of React even if, like me, you don't necessarily see yourself as a front-end developer.&lt;/p&gt;

&lt;p&gt;I am also hoping that in the process of writing this I might be able to clarify my own mental model of React. So if you are experienced with React then hopefully this will still be interesting to read and you will learn something.&lt;/p&gt;




&lt;h2&gt;
  
  
  “Building user interfaces”
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://reactjs.org/"&gt;official React website&lt;/a&gt; says this: “React is a JavaScript library for &lt;strong&gt;building user interfaces&lt;/strong&gt;”.&lt;/p&gt;

&lt;p&gt;I think this is a good sentence. 👍&lt;/p&gt;

&lt;p&gt;Let's just talk about user interfaces for a moment.&lt;/p&gt;

&lt;p&gt;User interfaces are how human beings interact with our computer code.&lt;/p&gt;

&lt;p&gt;We have some choices when we are creating an interface for humans to use: we can try to create an interface that is intuitive and easy to use straight away, but this will require us to account for a lot of potential outcomes because we did not tell the user what we expect them to do ahead of time.&lt;/p&gt;

&lt;p&gt;Alternatively, we can create a very streamlined interface that works in a very specific way, but this will require the user to learn exactly how to use it before they can achieve anything.&lt;/p&gt;

&lt;p&gt;These are both valid choices and it depends who we have in mind as our user.&lt;/p&gt;

&lt;p&gt;Humans can be quite messy and unpredictable, so if we do decide to make an intuitive user interface - one that does not require learning ahead of time - then it's often necessary for us to grapple with a large amount of complexity; an intuitive user interface will need to be able to react appropriately &lt;em&gt;on the fly&lt;/em&gt; to our users doing things we did not expect or want them to do.&lt;/p&gt;

&lt;p&gt;And perhaps, as we learn more about our users, we will need to find new ways in which to accomodate them and so the complexity of interface will increase over time.&lt;/p&gt;

&lt;p&gt;In short, user interfaces are often &lt;strong&gt;necessarily complex&lt;/strong&gt;. Our goal then is not to make them simple, but to find ways to manage that complexity.&lt;/p&gt;




&lt;h2&gt;
  
  
  React helps us to manage complexity
&lt;/h2&gt;

&lt;p&gt;When we're writing code, it is generally hard to manage large amounts of complexity.&lt;/p&gt;

&lt;p&gt;We may not be able to avoid complexity when we're building a user interface, but we can try to break it down and make it more manageable.&lt;/p&gt;

&lt;p&gt;I think one of the core aims of React is to allow developers to build a complex user interface system without needing to think about it all at once.&lt;/p&gt;

&lt;p&gt;I like this article called &lt;a href="https://jam1.re/blog/why-rusts-unsafe-works"&gt;Why Rust's Unsafe Works&lt;/a&gt; by &lt;a href="https://twitter.com/jam1garner"&gt;@jam1garner&lt;/a&gt; and it talks about the idea of &lt;strong&gt;locality&lt;/strong&gt; and &lt;strong&gt;encapsulation&lt;/strong&gt;. The article is unrelated to what we're talking about, but it says this about the &lt;em&gt;Rust&lt;/em&gt; programming language which I think is relevant:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;One of the greatest features of Rust is its increased design focus on locality, which is to say, it's easier to reason about a function without looking outside the function.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The Rust language is designed in such a way that functions are able to maintain locality; you can normally understand what a function does, and confidently make changes to it, without needing to read other parts of the code as well. You can also know with certainty whether or not a change you make to a function might break other parts of the code based purely on its return type and the type of its parameters.&lt;/p&gt;

&lt;p&gt;React does something similar for us, by allowing us to write our user interface code in such a way that the component parts can maintain locality - i.e. we should be able to make changes to one specific part of our user interface in the confidence that it will either not affect other parts at all, or that we can fully understand how it might affect other parts.&lt;/p&gt;

&lt;p&gt;React allows us to define a &lt;strong&gt;React component&lt;/strong&gt; as a single JavaScript function or class (we will focus on the function kind here). A component encapsulates all of the appearance and behaviour that makes up some part of a user interface. By using React components, we can reason about the behaviour of some part of a user interface by looking only within the scope of a single JavaScript function.&lt;/p&gt;

&lt;p&gt;Here's an example of a React function component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;MyUserInterface&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handleButtonClick&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Howdy ma'am&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleButtonClick&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            Hello dear
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code defines a component which I've decided to call MyUserInterface.&lt;/p&gt;

&lt;p&gt;The component will render an HTML &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt; tag which contains the text "Hello dear".&lt;/p&gt;

&lt;p&gt;When the user clicks on the button, an alert will be shown in their browser window which says "Howdy ma'am".&lt;/p&gt;




&lt;p&gt;Sidenote: You might have noticed in the above code example that the syntax &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt; is not valid JavaScript syntax.&lt;/p&gt;

&lt;p&gt;React uses a JavaScript language extension called JSX which compiles to vanilla JavaScript. Anywhere you see some JSX code like &lt;code&gt;&amp;lt;a href="/"&amp;gt;Home&amp;lt;/a&amp;gt;&lt;/code&gt; this can be transformed into normal JavaScript code like &lt;code&gt;React.createElement('a', {href: '/'}, 'Home')&lt;/code&gt; by a compiler such as &lt;a href="https://babeljs.io/"&gt;babel&lt;/a&gt;, &lt;a href="https://esbuild.github.io/"&gt;esbuild&lt;/a&gt; or &lt;a href="https://swc.rs/"&gt;swc&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Since JSX compiles to normal JavaScript, we can use our React components, for example, to make up part of a web page. Here's a code example that shows how to do this in a single &lt;code&gt;.html&lt;/code&gt; file which you can download and open in your favourite web browser: &lt;a href="https://raw.githubusercontent.com/stefee/reactjs.org/main/static/html/single-file-example.html"&gt;https://raw.githubusercontent.com/stefee/reactjs.org/main/static/html/single-file-example.html&lt;/a&gt; (this code is taken from the &lt;a href="https://reactjs.org/docs/getting-started.html#online-playgrounds"&gt;official React website&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;You can also use React &lt;a href="https://reactjs.org/docs/react-without-jsx.html"&gt;without JSX&lt;/a&gt; if you like!&lt;/p&gt;




&lt;p&gt;Here's a second example which has two components - but the rendered output will be the same as in the previous example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;AlertButton&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="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handleButtonClick&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;alertText&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleButtonClick&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;MyUserInterface&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;AlertButton&lt;/span&gt; &lt;span class="na"&gt;alertText&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Howdy ma'am"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            Hello dear
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;AlertButton&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here I have defined a new component and called it AlertButton.&lt;/p&gt;

&lt;p&gt;This component looks similar to the previous example, but the text values are passed in as parameters. The parameters passed into a React component are called properties, or &lt;strong&gt;props&lt;/strong&gt; for short.&lt;/p&gt;

&lt;p&gt;Now our MyUserInterface component will render the AlertButton component and pass the text values as props.&lt;/p&gt;

&lt;p&gt;The end result is identical to the previous example.&lt;/p&gt;

&lt;p&gt;However, by changing the text values to be passed in as parameters, we have created an abstraction which will allow us to re-use this part of our user interface.&lt;/p&gt;

&lt;p&gt;Here's an example where we render two different instances of AlertButton in our user interface:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;AlertButton&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="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handleButtonClick&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;alertText&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleButtonClick&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;MyUserInterface&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;AlertButton&lt;/span&gt; &lt;span class="na"&gt;alertText&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Howdy ma'am"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                Hello dear
            &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;AlertButton&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;AlertButton&lt;/span&gt; &lt;span class="na"&gt;alertText&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Okeydokey"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                Goodbye
            &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;AlertButton&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this interface, the "Hello dear" button works the same as before, but now if the user clicks the "Goodbye" button instead, they will see a different alert which says "Okeydokey".&lt;/p&gt;

&lt;p&gt;This example shows how we are able to abstract some user interface behaviour into a component, and re-use components to do different things.&lt;/p&gt;

&lt;p&gt;This is good stuff! 👌&lt;/p&gt;




&lt;p&gt;Sidenote: I should explain the &lt;strong&gt;children&lt;/strong&gt; prop which we used in AlertButton before continuing.&lt;/p&gt;

&lt;p&gt;The children prop is a special prop which takes on the value of whatever appears between the open and close tags in our JSX code (&lt;code&gt;&amp;lt;AlertButton&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;/AlertButton&amp;gt;&lt;/code&gt;) and it is used to describe a &lt;strong&gt;component hierarchy&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The component hierarchy is what makes React components &lt;strong&gt;composable&lt;/strong&gt;; components can be assembled in different combinations to satisfy different needs.&lt;/p&gt;




&lt;p&gt;We've got one more key concept to cover which is &lt;strong&gt;state&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;So far what we have seen is that a React component is able to describe how some part of a user interface should appear to the user.&lt;/p&gt;

&lt;p&gt;As well as describing how some part of our user interface is rendered, a React components is also able to manage the state of that part of the interface, that is to say it can describe how it will &lt;strong&gt;change&lt;/strong&gt; over time in response to events that may happen outside of its control.&lt;/p&gt;

&lt;p&gt;Here's an example of a component that manages some state:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;MyCounterButton&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;counter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setCounter&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handleButtonClick&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;setCounter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleButtonClick&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            counter is &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;counter&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this code example I've defined a new component which renders a button.&lt;/p&gt;

&lt;p&gt;At first this button will say "counter is 0".&lt;/p&gt;

&lt;p&gt;When the user clicks on the button, an event is triggered and the text will change to say "counter is 1". If the user clicks again it will say "counter is 2" and so on, and so forth.&lt;/p&gt;

&lt;p&gt;What this example demonstrates is that a React component is able to persist some state in memory (in this case, the value of &lt;code&gt;counter&lt;/code&gt;) between renders; when our component is rendered, React must store the value of &lt;code&gt;counter&lt;/code&gt; somewhere so that it can be modified by our event handler and the value will be remembered for subsequent renders.&lt;/p&gt;

&lt;p&gt;If you've not used React before then you might have a lot of questions at this point. This seems a bit magical, doesn't it?&lt;/p&gt;

&lt;p&gt;I want to try and explain this fully, so we're going to talk a lot more in detail about exactly how state works in part 2 of this series.&lt;/p&gt;

&lt;p&gt;First though, let's imagine we were to create a similar user interface to our previous example using just JavaScript.&lt;/p&gt;

&lt;p&gt;Without React, we have to describe imperatively (step-by-step) how the elements are to be constructed and related to one another when our code gets executed - e.g. first we &lt;em&gt;create&lt;/em&gt; a div node and then we &lt;em&gt;create&lt;/em&gt; a button node and then we &lt;em&gt;attach&lt;/em&gt; an event handler to the button and then we &lt;em&gt;append&lt;/em&gt; the button to the div and so on, and so forth.&lt;/p&gt;

&lt;p&gt;In contrast to this, React components are &lt;strong&gt;declarative&lt;/strong&gt;; our div element &lt;em&gt;has&lt;/em&gt; children which &lt;em&gt;has&lt;/em&gt; the type of “button” and &lt;em&gt;has&lt;/em&gt; a click event handler.&lt;/p&gt;

&lt;p&gt;Our components do not need to describe &lt;em&gt;how&lt;/em&gt; to construct our user interface, they only need to describe &lt;em&gt;what&lt;/em&gt; is to be shown to the user at any given point in time.&lt;/p&gt;

&lt;p&gt;What this means is, since the elements that make up our user interface do not come into existence until we render the component hierarchy, we can know for sure that, unless it is passed explicitly via props, it is impossible for one component to access an element which is created by another component and modify it's behaviour in some way - this is how React components enable us to fully encapsulate the behaviour of some part of our user interface and isolate it from the rest.&lt;/p&gt;

&lt;p&gt;This is also what enables us to maintain locality in our user interface code.&lt;/p&gt;

&lt;p&gt;When we look at the code in the MyCounterButton example, I can say with confidence that this component will always render a button which says "counter", clicking the button will always increment the number shown on the button, and there will &lt;em&gt;never&lt;/em&gt; be any other hidden behaviours attached to the button by other components that we need to be concerned about when editing this code.&lt;/p&gt;

&lt;p&gt;We can make these assertions simply because the MyCounterButton function does not have parameters, and so we know that running the function will always produce the same result, and the result will be defined only by the code inside the scope of the function.&lt;/p&gt;

&lt;p&gt;In general, we can say that the appearance and behaviour of some user interface element rendered by a React component will only change if the props received from its parent change, or as a result of some state defined internally, and that the way in which some part of our user interface changes over time will only be decided by its associated React component, and not any other parts of the system.&lt;/p&gt;

&lt;p&gt;This is how React enables us to break down a complex problem and reduce coupling between the component parts of our interface.&lt;/p&gt;

&lt;p&gt;It ultimately means that we can continue to introduce more complexity into our user interface over time, and as long as we are able to understand how each individual component works in isolation, we can have confidence in the system as a whole.&lt;/p&gt;




&lt;h2&gt;
  
  
  End of part 1
&lt;/h2&gt;

&lt;p&gt;I think we've touched on all of the things I want to cover in this introduction.&lt;/p&gt;

&lt;p&gt;This was originally going to be a post about how &lt;code&gt;React.useRef&lt;/code&gt; works - which I haven't even mentioned once. I still think it's a good idea to talk about this as a way of building a robust mental model of React as a runtime system, so that will be the primary focus of part 2.&lt;/p&gt;




&lt;p&gt;Thanks for taking the time to read this! &amp;lt;3&lt;/p&gt;

&lt;p&gt;Please let me know what you think of it. You can contact me by email at &lt;a href="mailto:stef@sril.email"&gt;stef@sril.email&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Also, thank you Sam Greenhalgh for reading my first draft. What a nice man.&lt;/p&gt;

&lt;p&gt;References:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Is React Functional Programming?&lt;/em&gt; - Eric Normand&lt;a href="https://lispcast.com/is-react-functional-programming/"&gt;https://lispcast.com/is-react-functional-programming/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Composition: Every Layout&lt;/em&gt; - Heydon Pickering &amp;amp; Andy Bell&lt;a href="https://every-layout.dev/rudiments/composition/"&gt;https://every-layout.dev/rudiments/composition/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Why Rust's Unsafe Works&lt;/em&gt; - jam1garner&lt;a href="https://jam1.re/blog/why-rusts-unsafe-works"&gt;https://jam1.re/blog/why-rusts-unsafe-works&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>react</category>
    </item>
    <item>
      <title>Speedy builds with Docker Layer Caching</title>
      <dc:creator>Stef</dc:creator>
      <pubDate>Sat, 05 Sep 2020 10:32:10 +0000</pubDate>
      <link>https://dev.to/stefee/speedy-builds-with-docker-layer-caching-4fae</link>
      <guid>https://dev.to/stefee/speedy-builds-with-docker-layer-caching-4fae</guid>
      <description>&lt;p&gt;&lt;em&gt;I found Docker to be one of the most intimidating and confusing things about my work. Hopefully I can share some of what I’ve learned in a way that is accessible and somewhat less intimidating.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Docker?
&lt;/h2&gt;

&lt;p&gt;Docker is an application for “containerising” software in an &lt;a href="https://en.wikipedia.org/wiki/Docker_(software)"&gt;(almost) virtual machine&lt;/a&gt;. Docker containers can be used to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Isolate your application code from the rest of your computer.&lt;/li&gt;
&lt;li&gt;Allow you to control what resources an application has access to (e.g. networking).&lt;/li&gt;
&lt;li&gt;Run your code on a virtual operating system, allowing you to run it on different computers and have greater confidence that it will behave the same way (e.g. during development and in production).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How it works
&lt;/h2&gt;

&lt;p&gt;Here’s how a Docker container gets made:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You write a &lt;em&gt;Dockerfile&lt;/em&gt; and add it alongside your source code.&lt;/li&gt;
&lt;li&gt;You give your &lt;em&gt;Dockerfile&lt;/em&gt; to the Docker &lt;em&gt;build&lt;/em&gt; command.&lt;/li&gt;
&lt;li&gt;Docker builds up an &lt;em&gt;image&lt;/em&gt; of a container by running the instructions from your &lt;em&gt;Dockerfile&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;You give that image to the Docker &lt;em&gt;create&lt;/em&gt; command.&lt;/li&gt;
&lt;li&gt;Docker creates a container from the image.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So first off, Docker builds an image based on the instructions in your &lt;em&gt;Dockerfile&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Here’s what that might look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; node:12.14.1-slim&lt;/span&gt;
&lt;span class="k"&gt;USER&lt;/span&gt;&lt;span class="s"&gt; node&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; package.json /home/node/&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /home/node&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm run build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each line in the &lt;em&gt;Dockerfile&lt;/em&gt; is an &lt;a href="https://docs.docker.com/engine/reference/builder/#from"&gt;instruction&lt;/a&gt; for how Docker should build the image.&lt;/p&gt;

&lt;p&gt;For example, the &lt;em&gt;copy&lt;/em&gt; instruction copies a file from the Docker context (e.g. your source code) into the container. (A container has its own file system!)&lt;/p&gt;

&lt;p&gt;Docker executes your instructions one after the other, then creates a snapshot of the result and stores this as an &lt;em&gt;image&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;You can then &lt;em&gt;create&lt;/em&gt; a container from the image, &lt;em&gt;start&lt;/em&gt; the container, and &lt;em&gt;execute&lt;/em&gt; commands inside it.&lt;/p&gt;

&lt;p&gt;Here’s how I would build and run my Node.js app using the above &lt;em&gt;Dockerfile&lt;/em&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker build &lt;span class="nt"&gt;--tag&lt;/span&gt; my_app &lt;span class="nb"&gt;.&lt;/span&gt;
docker run my_app npm start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(Docker &lt;em&gt;run&lt;/em&gt; is like a combination of &lt;em&gt;create&lt;/em&gt;, &lt;em&gt;start&lt;/em&gt; and &lt;em&gt;execute&lt;/em&gt; in a single command).&lt;/p&gt;

&lt;p&gt;But wait, that’s not the full picture of what’s happening. Let’s talk about layers.&lt;/p&gt;

&lt;h2&gt;
  
  
  How layers work
&lt;/h2&gt;

&lt;p&gt;Docker doesn’t just create a snapshot at the end of building an image. In fact, Docker creates a snapshot from the result of every instruction during a build.&lt;/p&gt;

&lt;p&gt;These snapshots are called &lt;em&gt;layers&lt;/em&gt;, and each layer is a recording of &lt;strong&gt;what changed&lt;/strong&gt; as a result of executing an instruction.&lt;/p&gt;

&lt;p&gt;Because a layer only stores what changed since running the previous instruction, each layer is dependant on the previous layer (aka. its &lt;em&gt;parent&lt;/em&gt; layer). A layer without its parent is invalid, because it only makes sense in the context of its parent layers.&lt;/p&gt;

&lt;p&gt;So, a layer consists of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An instruction&lt;/li&gt;
&lt;li&gt;A recording of what changed during the instruction&lt;/li&gt;
&lt;li&gt;A unique ID&lt;/li&gt;
&lt;li&gt;The ID of its parent&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;(Sidenote: Docker layers look a lot like Git commits!)&lt;/p&gt;

&lt;p&gt;Docker stores all of the layers during a build in the outputted image.&lt;/p&gt;

&lt;p&gt;When you ask Docker to create a container from an image, Docker re-plays the changes from each of the layers, one on top of the other (that’s why they’re called layers).&lt;/p&gt;

&lt;h2&gt;
  
  
  How layer caching works
&lt;/h2&gt;

&lt;p&gt;When you run docker build you can give Docker an image to use as its layer cache by adding the &lt;code&gt;--cache-from&lt;/code&gt; command-line argument.&lt;/p&gt;

&lt;p&gt;Before running each instruction, Docker will check if there’s a layer in its cache which matches the instruction it’s going to run, and if it finds one, it will use that layer rather than building a new one. Nice one, Docker!&lt;/p&gt;

&lt;p&gt;Importantly though, Docker also checks that the previous layer’s ID matches the cached layer’s parent ID. If the previous layer doesn’t match, then the cached layer can’t be used.&lt;/p&gt;

&lt;p&gt;The effect of this is that as soon as Docker fails to find a match in its layer cache for one instruction, the layer for that instruction and all of the child layers will have to be re-built – invalidating one cached layer effectively invalidates all of its children as well.&lt;/p&gt;

&lt;p&gt;To demonstrate how this works in practice, let’s go back to our example &lt;em&gt;Dockerfile&lt;/em&gt;, which looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; node:12.14.1-slim&lt;/span&gt;
&lt;span class="k"&gt;USER&lt;/span&gt;&lt;span class="s"&gt; node&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; package.json /home/node/&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /home/node&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm run build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s run docker build, and add the &lt;code&gt;--cache-from&lt;/code&gt; argument like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker build &lt;span class="nt"&gt;--tag&lt;/span&gt; “my_app” &lt;span class="nt"&gt;--cache-from&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;”my_app” &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here’s our log output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Step 1/6 : FROM node:12.14.1-slim
    ---&amp;gt; 918c7b4d1cc5
Step 2/6 : USER node
    ---&amp;gt; Using cache
    ---&amp;gt; d897eea3d14a
Step 3/6 : COPY package.json /home/node/
    ---&amp;gt; Using cache
    ---&amp;gt; 6211fc2535b1
Step 4/6 : WORKDIR /home/node
    ---&amp;gt; Using cache
    ---&amp;gt; 8b7fbfbc367f
Step 5/6 : RUN npm install
    ---&amp;gt; Using cache
    ---&amp;gt; 530d5f1f8e6d
Step 6/6 : RUN npm run build
    ---&amp;gt; Using cache
    ---&amp;gt; ae5267476d3d
Successfully built ae5267476d3d
Successfully tagged my_app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After each instruction, Docker logs Using cache, followed by the ID of the layer it’s caching from.&lt;/p&gt;

&lt;p&gt;Now, if I change my &lt;em&gt;Dockerfile&lt;/em&gt; to say &lt;code&gt;RUN npm install --only=prod&lt;/code&gt; instead of &lt;code&gt;RUN npm install&lt;/code&gt; and re-run the build, here’s what we get:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Step 1/6 : FROM node:12.14.1-slim
    ---&amp;gt; 918c7b4d1cc5
Step 2/6 : USER node
    ---&amp;gt; Using cache
    ---&amp;gt; d897eea3d14a
Step 3/6 : COPY package.json /home/node/
    ---&amp;gt; Using cache
    ---&amp;gt; 6211fc2535b1
Step 4/6 : WORKDIR /home/node
    ---&amp;gt; Using cache
    ---&amp;gt; 8b7fbfbc367f
Step 5/6 : RUN npm install --only=prod
    ---&amp;gt; Running in a168555b7db9
Removing intermediate container a168555b7db9
    ---&amp;gt; 44ab41899c52
Step 6/6 : RUN npm run build
    ---&amp;gt; Running in 1230a3e778aa
Removing intermediate container 1230a3e778aa
    ---&amp;gt; 8d3dca829a17
Successfully built 8d3dca829a17
Successfully tagged my_app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can’t tell from the log output, but this build ran a lot slower than the last one! Let’s figure out why.&lt;/p&gt;

&lt;p&gt;The first few lines here are the same as before, but now when we get to the instruction we changed, instead of:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Step 5/6 : RUN npm install
    ---&amp;gt; Using cache
    ---&amp;gt; 530d5f1f8e6d
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we get:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Step 5/6 : RUN npm install --only=prod
    ---&amp;gt; Running in a168555b7db9
Removing intermediate container a168555b7db9
    ---&amp;gt; 44ab41899c52
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Aha, so rather than using cache for this step, it has executed the instruction because the instruction has changed! This is a good thing of course, because we changed the instruction so we want Docker to do something different. If Docker used the cached layer, it would have the wrong result.&lt;/p&gt;

&lt;p&gt;But the key thing here is that the ID of the layer has changed as well (from &lt;code&gt;530d5f1f8e6d&lt;/code&gt; to &lt;code&gt;44ab41899c52&lt;/code&gt;). This means from this point on, when Docker looks in its layer cache, it won’t find a layer that matches, because the IDs of the layers are all different to before — and remember, it caches layers based on the ID of the parent layer as well as the instruction.&lt;/p&gt;

&lt;p&gt;All of the layers will have to be re-built for the instructions following the one we changed. And you can see in the log output that this is exactly what happened. There are no more Using cache lines once the cache gets invalidated.&lt;/p&gt;

&lt;p&gt;So the reason why our build took longer was because we had to re-run both the &lt;code&gt;npm install&lt;/code&gt; and &lt;code&gt;npm run build&lt;/code&gt; steps in full.&lt;/p&gt;

&lt;p&gt;It’s worth noting here that this is not a problem with Docker, it’s an important feature! The result of &lt;code&gt;npm run build&lt;/code&gt; could change depending on whether we ran &lt;code&gt;npm install&lt;/code&gt; or &lt;code&gt;npm install --only=prod&lt;/code&gt; before-hand. Changing the &lt;code&gt;npm install&lt;/code&gt; line in our &lt;em&gt;Dockerfile&lt;/em&gt; means we will almost certainly want Docker to re-run our &lt;code&gt;npm run build&lt;/code&gt; as well. This is &lt;em&gt;cache invalidation&lt;/em&gt; working just as intended.&lt;/p&gt;

&lt;p&gt;And of course, if we were to re-run this command again without making any changes, we would now get a fully cached build, since we are overwriting the same image tag each time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this matters
&lt;/h2&gt;

&lt;p&gt;It’s important to understand how Docker layer caching works when writing your &lt;em&gt;Dockerfile&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Let’s use this &lt;em&gt;Dockerfile&lt;/em&gt; snippet as an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; src /home/node/src&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; package.json /home/node/&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /home/node&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm run build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we have placed our &lt;code&gt;COPY src&lt;/code&gt; instruction &lt;em&gt;before&lt;/em&gt; our &lt;code&gt;npm install&lt;/code&gt; instruction. This means &lt;code&gt;npm install&lt;/code&gt; will have to execute again every time we make a change to the files in the &lt;code&gt;src&lt;/code&gt; directory, because a change to the src files will invalidate the layer cache during the &lt;code&gt;COPY src&lt;/code&gt; line. (Note: during a &lt;code&gt;COPY&lt;/code&gt;, Docker will treat file changes as if the instruction has changed and this will invalidate the cache).&lt;/p&gt;

&lt;p&gt;In the case of my Node.js app, I’m confident that the result of &lt;code&gt;npm install&lt;/code&gt; will not be affected by what’s in my &lt;code&gt;src&lt;/code&gt; folder, so I‘d like to be able to make changes to &lt;code&gt;src&lt;/code&gt; without having to wait for &lt;code&gt;npm install&lt;/code&gt; every time.&lt;/p&gt;

&lt;p&gt;So let’s change the order of our &lt;em&gt;Dockerfile&lt;/em&gt; and move &lt;code&gt;COPY src&lt;/code&gt; to happen after &lt;code&gt;npm install&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; package.json /home/node/&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /home/node&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; src /home/node/src&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm run build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now if I change the contents of &lt;code&gt;src&lt;/code&gt; but I haven’t touched &lt;code&gt;package.json&lt;/code&gt;, Docker can take the first few layers straight from the cache, and it only has to re-run &lt;code&gt;npm run build&lt;/code&gt;. And that’s exactly what we want, since the output from &lt;code&gt;npm install&lt;/code&gt; doesn’t change depending on the content of &lt;code&gt;src&lt;/code&gt;, but the output from &lt;code&gt;npm run build&lt;/code&gt; &lt;em&gt;does&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;This will speed up my build when I’m not changing &lt;code&gt;package.json&lt;/code&gt;, because it means Docker doesn’t re-run &lt;code&gt;npm install&lt;/code&gt;. 🎉&lt;/p&gt;

&lt;h2&gt;
  
  
  In conclusion…
&lt;/h2&gt;

&lt;p&gt;It’s important to be aware of dependencies between instructions in your &lt;em&gt;Dockerfile&lt;/em&gt; to maximise the benefits from Docker layer caching. Try to group dependent instructions together.&lt;/p&gt;

&lt;p&gt;You can also think about which things you change often and which things you don’t, and try to put the things which you think will change most often towards the bottom of your &lt;em&gt;Dockerfile&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;❤&lt;/p&gt;

</description>
      <category>docker</category>
      <category>devops</category>
    </item>
  </channel>
</rss>
