<?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: Paul Mooney</title>
    <description>The latest articles on DEV Community by Paul Mooney (@pauldmooney).</description>
    <link>https://dev.to/pauldmooney</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%2F62733%2F3b5d2ca9-5de9-4255-8182-28a27ea66e9f.jpeg</url>
      <title>DEV Community: Paul Mooney</title>
      <link>https://dev.to/pauldmooney</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/pauldmooney"/>
    <language>en</language>
    <item>
      <title>Enhancing the Developer Experience of Testing Part 2</title>
      <dc:creator>Paul Mooney</dc:creator>
      <pubDate>Sun, 08 Dec 2024 01:14:07 +0000</pubDate>
      <link>https://dev.to/pauldmooney/enhancing-the-developer-experience-of-testing-part-2-3oee</link>
      <guid>https://dev.to/pauldmooney/enhancing-the-developer-experience-of-testing-part-2-3oee</guid>
      <description>&lt;p&gt;In my &lt;a href="https://dev.to/pauldmooney/enhancing-the-developer-experience-of-testing-9fk"&gt;last post&lt;/a&gt;, I talked about writing tests with natural language descriptions, and leveraging structured testing to provide organized and comprehensible output. Here I will expand more on these concepts. &lt;/p&gt;

&lt;h2&gt;
  
  
  Structured Testing Part 2
&lt;/h2&gt;

&lt;p&gt;Structured testing is a nesting of contexts, until eventually terminating in one or more tests. In NodeJS test frameworks, a context is a &lt;code&gt;describe&lt;/code&gt; function. In JUnit a context is the test class itself or a &lt;code&gt;@Nested&lt;/code&gt; inner class. Contexts, just like tests, can also be described (or named) with natural language and can appear in the test output's tree structure. Here are some of the ways we can use this contextual test structure for well described tests:&lt;/p&gt;

&lt;h3&gt;
  
  
  Given-When-Then Pattern
&lt;/h3&gt;

&lt;p&gt;Borrowing from &lt;a href="https://martinfowler.com/bliki/GivenWhenThen.html" rel="noopener noreferrer"&gt;Behaviour Driven Development (BDD)&lt;/a&gt;, one of the ways we can structure our tests is to use the Given-When-Then pattern. In this pattern we nest the &lt;code&gt;Given&lt;/code&gt;s, &lt;code&gt;When&lt;/code&gt;s, and &lt;code&gt;Then&lt;/code&gt;s in a hierarchical layout where the &lt;code&gt;Given&lt;/code&gt;s and &lt;code&gt;When&lt;/code&gt;s are contexts and &lt;code&gt;Then&lt;/code&gt;s are the tests (in most popular testing frameworks). &lt;/p&gt;

&lt;p&gt;The &lt;code&gt;Given&lt;/code&gt; context's clause describes some kind of preconditions. I like to include inputs here as well because it gives purpose to the &lt;code&gt;Given&lt;/code&gt; clause even when the thing being tested does not require preconditions. I will talk more on this later, but some people may prefer to not include inputs here.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;When&lt;/code&gt; context's clause describes the execution. It can also be used to describe inputs if you prefer. Again, more on this later.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;Then&lt;/code&gt; clause for tests should describe our expectation. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note&lt;/em&gt;: It's common to see synonymous conventions to these like "Arrange-Act-Assert", or the use of "it should ..." for tests instead of "Then...". This is all fine, as long as consistency is maintained.&lt;/p&gt;

&lt;p&gt;There are generally at least two more kinds of contexts in this pattern that we will see:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;The &lt;code&gt;And&lt;/code&gt; context. This is used for providing additional preconditions or inputs to compliment the &lt;code&gt;Given&lt;/code&gt; or &lt;code&gt;When&lt;/code&gt;&lt;br&gt;
contexts.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The class or file under test context. This is the highest level context and just describes the class or file containing the units to be tested. It could also just be a name for a group of tests in a particular test file. This comes implicitly in some test frameworks and may default to the name of the class or file containing the tests.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here's an example all of this in action using JUnit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@DisplayName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"REST Endpoint tests"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RestEndpointTest&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@DisplayName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Given an `id` for an existing record"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="nd"&gt;@Nested&lt;/span&gt;
    &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;GivenValidId&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

        &lt;span class="nd"&gt;@DisplayName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"When calling the `GET /api/record/{id}` endpoint"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="nd"&gt;@Nested&lt;/span&gt;
        &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WhenCallingRecordEndpoint&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

            &lt;span class="nd"&gt;@DisplayName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Then it should return the record for that `id`"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="nd"&gt;@Test&lt;/span&gt;
            &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;testRecordReturned&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="c1"&gt;// test code here&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;

            &lt;span class="nd"&gt;@DisplayName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Then it should return a 200 response code"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="nd"&gt;@Test&lt;/span&gt;
            &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;test200Response&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="c1"&gt;// test code here&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;

            &lt;span class="c1"&gt;// ... other tests&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="nd"&gt;@DisplayName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"And the `Accept` header is `application/xml`"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="nd"&gt;@Nested&lt;/span&gt;
        &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AndAcceptHeaderIsXml&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

            &lt;span class="nd"&gt;@DisplayName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"When calling the `GET /api/record/{id}` endpoint"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="nd"&gt;@Nested&lt;/span&gt;
            &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WhenCallingRecordEndpoint&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

                &lt;span class="nd"&gt;@DisplayName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Then it should return the record for that `id` in XML format"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="nd"&gt;@Test&lt;/span&gt;
                &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;testRecordReturnedInXml&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                    &lt;span class="c1"&gt;// test code here&lt;/span&gt;
                &lt;span class="o"&gt;}&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@DisplayName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Given an `id` which does not correspond to an existing record"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="nd"&gt;@Nested&lt;/span&gt;
    &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;GivenInvalidId&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nd"&gt;@DisplayName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"When calling the `GET /api/record/{id}` endpoint"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="nd"&gt;@Nested&lt;/span&gt;
        &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WhenCallingRecordEndpoint&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

            &lt;span class="nd"&gt;@DisplayName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Then it should return a 404 response code"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="nd"&gt;@Test&lt;/span&gt;
            &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;test404Response&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="c1"&gt;// test code here&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This pattern fits nicely with the "One assert per test" rule. Sometimes, from one execution (a &lt;code&gt;When&lt;/code&gt; context) we have multiple expectations (&lt;code&gt;Then&lt;/code&gt; tests). For example, if we were testing a REST endpoint then we might expect that the response body looks a particular way, but also separately we expect the response code to be a particular value. These are two conceptually different expectations to assert from the same single execution with all the same preconditions. And there could be more -  maybe there were certain response headers expected, too. Breaking our expectations up into multiple &lt;code&gt;Then&lt;/code&gt; clauses/test lets us describe each expectation separately.&lt;/p&gt;

&lt;h3&gt;
  
  
  UnitUnderTest-Given-Then Pattern
&lt;/h3&gt;

&lt;p&gt;It can be helpful to group all contexts and tests by the unit being tested. From an organizational standpoint, this is where the Given-When-Then pattern needs an alteration because, in its current form, it lacks a way to organize all tests for a particular unit. This can be difficult from a code organization standpoint, and since test order is usually randomized, the tests for a particular unit become scattered amongst the contexts and tests for other sibling units.&lt;/p&gt;

&lt;p&gt;To combat this, I like to organize my tests in a UnitUnderTest-Given-Then pattern. "UnitUnderTest" is the particular unit being tested, whether that be a method, function, REST endpoint, or other &lt;a href="https://en.wikipedia.org/wiki/Unit_testing#Unit" rel="noopener noreferrer"&gt;unit&lt;/a&gt;. Our structured test hierarchy would look like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ClassUnderTest

&lt;ul&gt;
&lt;li&gt;Method One Under Test

&lt;ul&gt;
&lt;li&gt;Given some arguments and preconditions

&lt;ul&gt;
&lt;li&gt;It should return an expected result&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Given some other arguments and preconditions

&lt;ul&gt;
&lt;li&gt;It should return a different expected result &lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;li&gt;Method Two Under Test

&lt;ul&gt;
&lt;li&gt;Given ...

&lt;ul&gt;
&lt;li&gt;It should ...&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Here's an example of this pattern in action using JUnit. Notice how the test scenarios for a particular unit (in this case units are methods) are grouped together under a context for that unit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@DisplayName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"PersonService"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PersonServiceTest&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@DisplayName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"findById"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// &amp;lt;-- Unit under test: the `findById` method&lt;/span&gt;
    &lt;span class="nd"&gt;@Nested&lt;/span&gt;
    &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FindById&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

        &lt;span class="nd"&gt;@DisplayName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Given an `id` for an existing record"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="nd"&gt;@Nested&lt;/span&gt;
        &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;GivenIdForExistingRecord&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

            &lt;span class="nd"&gt;@DisplayName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"It should return an `Optional` containing the record for that `id`"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="nd"&gt;@Test&lt;/span&gt;
            &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;thenRecordIsReturned&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="c1"&gt;// test code here&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="nd"&gt;@DisplayName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Given an `id` which does not correspond to an existing record"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="nd"&gt;@Nested&lt;/span&gt;
        &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;GivenIdForNoExistingRecords&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

            &lt;span class="nd"&gt;@DisplayName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"It should return an empty Optional"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="nd"&gt;@Test&lt;/span&gt;
            &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;thenNullIsReturned&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="c1"&gt;// test code here&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@DisplayName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"deleteById"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// &amp;lt;-- Unit under test: the `deleteById` method&lt;/span&gt;
    &lt;span class="nd"&gt;@Nested&lt;/span&gt;
    &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DeleteById&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

        &lt;span class="nd"&gt;@DisplayName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Given an `id` for an existing record"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="nd"&gt;@Nested&lt;/span&gt;
        &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;GivenIdForExistingRecord&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

            &lt;span class="nd"&gt;@DisplayName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"It should delete the record for that `id`"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="nd"&gt;@Test&lt;/span&gt;
            &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;thenRecordIsDeleted&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="c1"&gt;// test code here&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Note&lt;/em&gt;: This does put a bit of a demand on the reader to understand the convention going on here, as any sentence that can be inferred from the hierarchy starts deeper into the hierarchy than it does in the "Given-When-Then" pattern. I believe this is not a difficult expectation for readers to pick up on this pattern, especially given the organizational advantage it provides.&lt;/p&gt;

&lt;h4&gt;
  
  
  Alternative: UnitUnderTest-Given-When-Then Pattern
&lt;/h4&gt;

&lt;p&gt;So far, I've omitted the &lt;code&gt;When&lt;/code&gt; context because I state the inputs in the &lt;code&gt;Given&lt;/code&gt; context. This is a personal preference and if you believe &lt;code&gt;Given&lt;/code&gt;s should only state preconditions, then you can include a &lt;code&gt;When&lt;/code&gt; context to describe the inputs. Both of these do not need to exist - sometimes you don't have preconditions, and sometimes you don't have inputs.&lt;/p&gt;

&lt;p&gt;Example with both &lt;code&gt;Given&lt;/code&gt; and &lt;code&gt;When&lt;/code&gt; contexts, because there is both a preconditon and an input:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;PersonService

&lt;ul&gt;
&lt;li&gt;deleteById

&lt;ul&gt;
&lt;li&gt;Given there is an existing record

&lt;ul&gt;
&lt;li&gt;When called with the `id` for the existing record

&lt;ul&gt;
&lt;li&gt;It should delete the record for that `id`&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Example with just &lt;code&gt;Given&lt;/code&gt; context, because there is only a precondition and no input:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;PersonService

&lt;ul&gt;
&lt;li&gt;deleteAll

&lt;ul&gt;
&lt;li&gt;Given multiple records exist

&lt;ul&gt;
&lt;li&gt;It should delete all records&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Example with just &lt;code&gt;When&lt;/code&gt; context, because there is only an input and no precondition:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;PersonService

&lt;ul&gt;
&lt;li&gt;getFullName

&lt;ul&gt;
&lt;li&gt;When called with a `firstName` and `lastName`

&lt;ul&gt;
&lt;li&gt;It should return the `firstName` and `lastName` concatenated with a space in-between.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Some Dos and Don'ts
&lt;/h2&gt;

&lt;p&gt;We've gone over the general framework for writing good tests, at least from a structure and output standpoint. Let's look at some more specific tidbits as Dos and Don'ts.&lt;/p&gt;

&lt;h3&gt;
  
  
  Do: Provide contexts which describe preconditions, inputs, and their relationship to each-other
&lt;/h3&gt;

&lt;p&gt;Look at a test structure like&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;PersonService

&lt;ul&gt;
&lt;li&gt;deleteById

&lt;ul&gt;
&lt;li&gt;Given an existing record

&lt;ul&gt;
&lt;li&gt;It should delete the record&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;This sounds wrong. We know from the description that a record exists and a record is deleted but was it the same record? How is it deciding which record to delete? Details are missing. Clearly there is an input which is not being described here and then there's no relationship described between the input and anything else. The improved version of this test would be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;PersonService

&lt;ul&gt;
&lt;li&gt;deleteById

&lt;ul&gt;
&lt;li&gt;Given an `id` for an existing record

&lt;ul&gt;
&lt;li&gt;It should delete the record for that `id`&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Now it's easy to understand what's being deleted and why.&lt;/p&gt;

&lt;h3&gt;
  
  
  Don't: Put explicit values in the description
&lt;/h3&gt;

&lt;p&gt;Unless that exact value has relevance in the code. For example, if we had&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;PersonService

&lt;ul&gt;
&lt;li&gt;deleteById

&lt;ul&gt;
&lt;li&gt;Given an `id` of `1234` for an existing record

&lt;ul&gt;
&lt;li&gt;It should delete the record for that `id`&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Reading this, it seems like &lt;code&gt;1234&lt;/code&gt; is important to the unit being tested. As if, there is an explicit check in the code for &lt;code&gt;1234&lt;/code&gt;, and if we had a test Like "Given an &lt;code&gt;id&lt;/code&gt; of &lt;code&gt;ABCDE&lt;/code&gt; for an existing record..." then we might expect a completely different behaviour. In reality though &lt;code&gt;1234&lt;/code&gt; is probably not important, it's just a sample value, so it should be left out of the description to avoid confusing the reader. Another example of this might be where both the inputs and expectation are described with explicit values:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;MathUtil

&lt;ul&gt;
&lt;li&gt;hardToFullyDescribeMethodName

&lt;ul&gt;
&lt;li&gt;When called with a `radianValue` of `1`

&lt;ul&gt;
&lt;li&gt;It should return the `2.3974`&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Now I'm left wondering what happens if the &lt;code&gt;radianValue&lt;/code&gt; is &lt;code&gt;0&lt;/code&gt; or &lt;code&gt;2&lt;/code&gt;? What does &lt;code&gt;hardToFullyDescribeMethodName&lt;/code&gt; actually do? It's better to leave out explicit values and convey the preconditions, inputs, and expectations in more general terms:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;MathUtil

&lt;ul&gt;
&lt;li&gt;hardToFullyDescribeMethodName

&lt;ul&gt;
&lt;li&gt;When called with a `radianValue`

&lt;ul&gt;
&lt;li&gt;It should return the sum of tan and sin of the `radianValue`&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;It's fine to use explicit values in the actual test code, just not in the description. There are some exceptions to this rule, like when the value is some kind of enumeration, boolean, or actual special case value. Or when writing &lt;a href="https://www.baeldung.com/parameterized-tests-junit-5" rel="noopener noreferrer"&gt;parameterized tests&lt;/a&gt;. Then it makes sense to state those values in the description.&lt;/p&gt;

&lt;h3&gt;
  
  
  Don't: Leave out important information
&lt;/h3&gt;

&lt;p&gt;I've seen tests like&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Should return a Person record with no bio&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This leaves me asking so many questions. The author might as well have called this "test 1". I'm going to be generous and say that maybe they did try to describe the preconditions and inputs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;PersonService

&lt;ul&gt;
&lt;li&gt;findById

&lt;ul&gt;
&lt;li&gt;Given an `id` for an existing record

&lt;ul&gt;
&lt;li&gt;It should return a Person record with no bio&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Maybe this is fine, because that's the general expectation that this particular method always leaves the bio field empty. But if the reality is that there's a condition where the bio field should be empty then what is it? It's not described as it should be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;PersonService

&lt;ul&gt;
&lt;li&gt;findById

&lt;ul&gt;
&lt;li&gt;Given an `id` for an existing record

&lt;ul&gt;
&lt;li&gt;And the record's `showBio` field is `false`

&lt;ul&gt;
&lt;li&gt;It should return a Person record with no bio&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  Do: Avoid overly vague terms
&lt;/h3&gt;

&lt;p&gt;It's not uncommon to run into tests that have some overly vague terminology and say things like "it should return the appropriate value". What is the "appropriate value"? While we want to be general in our descriptions of our preconditions, inputs, and expectations, we still don't want to leave the reader guessing. This "appropriate value" gives no clue about what the unit being tested is supposed to do, just that whatever it is, it does it.&lt;/p&gt;

&lt;p&gt;This can be a bit of a challenge, as you also don't want to be overly specific or too verbose. You need to find the phrasing that is just descriptive enough to give the reader a good idea of what's going on. Ideally we should fully understand the behaviour of the unit from reading its test's output, but there are times that's not possible or reasonable. So instead we need to find phrasing that invites the reader to dig into the test code if they need more specifics. It should be rare that they need to do this.&lt;/p&gt;

&lt;p&gt;For example, with this test:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;PersonService

&lt;ul&gt;
&lt;li&gt;findById

&lt;ul&gt;
&lt;li&gt;Given an `id` for an existing record

&lt;ul&gt;
&lt;li&gt;It should return a Person record for that `id` with all fields populated from the database&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;This is a bit vague, I'm not really sure what "all fields populated from the database" exactly entails. Like is the field &lt;code&gt;lastName&lt;/code&gt; populated from the database column &lt;code&gt;SURNAME&lt;/code&gt;? I don't know. I'll have to dig into the test code to find out. While that's inconvenient, if there's 20 fields in a &lt;code&gt;Person&lt;/code&gt; record, leaving it kind of vague makes it much easier to both write and read these tests rather than describing how every single field gets populated.&lt;/p&gt;

&lt;p&gt;We also want to be careful here not to mask any behaviours. For example, if the &lt;code&gt;Person&lt;/code&gt; returned has an age, which is computed based on the birthdate stored in the database, then that should have its own test somewhere and not just hidden amongst the assertions in the "It should return a Person record for that &lt;code&gt;id&lt;/code&gt; with all fields populated from the database" test.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This post has all been about the organization and verbiage around tests. This is important because it not only helps the reader of these tests, but it can help organize your thoughts about how to actually write the test code. This advice is all derived from my own experiences; I hope you find it useful.&lt;/p&gt;

</description>
      <category>testing</category>
    </item>
    <item>
      <title>Enhancing the Developer Experience of Testing</title>
      <dc:creator>Paul Mooney</dc:creator>
      <pubDate>Sun, 08 Dec 2024 01:13:24 +0000</pubDate>
      <link>https://dev.to/pauldmooney/enhancing-the-developer-experience-of-testing-9fk</link>
      <guid>https://dev.to/pauldmooney/enhancing-the-developer-experience-of-testing-9fk</guid>
      <description>&lt;p&gt;One overlooked aspect of testing is the developer's experience when running tests. Particularly the next developer's experience, whether that be a different person, or future you who has just come back to some area of the code that you have not worked with in awhile. It may also be current you practicing &lt;a href="https://martinfowler.com/bliki/TestDrivenDevelopment.html" rel="noopener noreferrer"&gt;Test Driven Development (TDD)&lt;/a&gt;, and you need to organize your thoughts around what and how to test. Many times we run these tests, we can be confident that nothing broke but the test output is incomprehensible! We aren't  really sure what's supposed to be happening, or if it's safe to change anything. Or worse, something breaks, and we're not sure what the test was supposed to be doing, to get back to a working state. Let's see if we can fix that!&lt;/p&gt;

&lt;h2&gt;
  
  
  Prioritizing the Test Output
&lt;/h2&gt;

&lt;p&gt;One of the pillars of writing good tests is to make the test's output look good for human eyes. We want it to be self affirming documentation of the expected behaviours of the various units of the system, as well as the behaviours of the system in general. This may seem obvious, but the statement I'm trying to make here is that the test code itself is &lt;strong&gt;not good enough&lt;/strong&gt; to explain what is happening. It's not good enough for a couple of reasons. The first being, that it significantly slows developers down having to read the test code. The second is that the test code does not express meaning and intentions. Looking at the sample inputs and outputs that the test uses is not enough to explain what's going on.&lt;/p&gt;

&lt;p&gt;So how do we know if we have good output? We just look at it. Various IDEs and other test runners usually provide some kind of test output report, this is what we're aiming to make look good.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7ci8er43x9ut5chvg7k0.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7ci8er43x9ut5chvg7k0.jpg" width="800" height="321"&gt;&lt;/a&gt;Example IntelliJ Test Run Output&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftes0jhoh8zy72hm9gcrf.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftes0jhoh8zy72hm9gcrf.jpg" width="800" height="387"&gt;&lt;/a&gt;Example VSCode Test Explorer Output&lt;/p&gt;

&lt;p&gt;The rest of this post will cover tips for how to make this output look good.&lt;/p&gt;

&lt;h2&gt;
  
  
  Human Readable Test Descriptions
&lt;/h2&gt;

&lt;p&gt;Depending on your test framework, this is may be a no-brainer. NodeJS testing frameworks, RSpec, and most styles of &lt;a href="https://kotest.io/docs/framework/framework.html" rel="noopener noreferrer"&gt;Kotest&lt;/a&gt; all have a required space for you to write real, human-readable sentences right into the test and their test contexts. This makes their output quite legible.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;MyClassUnderTest&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Given an `id` for an existing record, when `deleteById` is called, then the record is deleted from the DB&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// test code here&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;The above results in nice output like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foikzlljwz9a9xoazecz3.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foikzlljwz9a9xoazecz3.jpg" width="800" height="45"&gt;&lt;/a&gt;Example NodeJS Test output&lt;/p&gt;

&lt;p&gt;Other method based test frameworks like JUnit and TestNG don't require this, and it's led to these awful &lt;a href="https://enterprisecraftsmanship.com/posts/you-naming-tests-wrong/" rel="noopener noreferrer"&gt;conventions&lt;/a&gt; of writing out descriptions of tests as the method name with mixes of camel and snake case. Eg,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Test&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;givenAnIdForExistingRecord_whenDeleteByIdCalled_thenRecordIsDeletedFromDB&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// test code here&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is barely human-readable. It's hard to pick out the methods and inputs involved from the rest of the test verbiage. When viewing many of these test methods together, they're difficult to pick out from each other. It's an eyesore. Nowhere in life do we need to read sentences that look like this, so we shouldn't need to read tests like this either.&lt;/p&gt;

&lt;p&gt;Fortunately these test frameworks usually have a way to add a description to the test. For example, In JUnit, you can use the &lt;code&gt;@DisplayName&lt;/code&gt; annotation to write normal sentences. Or TestNG has &lt;code&gt;@Test(name="...some name... ")&lt;/code&gt;. If we're using this kind of testing framework then we should ALWAYS use these kinds of annotations. And then it doesn't really matter what the method name is.&lt;/p&gt;

&lt;p&gt;An improved example of the test above:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Test&lt;/span&gt;
&lt;span class="nd"&gt;@DisplayName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Given an `id` for an existing record, when `deleteById` is called, then the record is deleted from the DB"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;testDeleteById1&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// test code here&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will give us a nice human readable output in the test report, just like the NodeJS Test above.&lt;/p&gt;

&lt;h2&gt;
  
  
  Structured Testing
&lt;/h2&gt;

&lt;p&gt;Another tool that can help make our test output look good is to take advantage of the test frameworks ability to group tests within a nesting of "contexts". This helps us create reusability in the test code, but more importantly in the test sentence structure. Imagine we have these 3 [flat] tests for a REST endpoint:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Given an `id` for an existing record, when calling the `/api/record/{id}` endpoint, it should return the record for that `id`&lt;/li&gt;
&lt;li&gt;Given an `id` for an existing record, when calling the `/api/record/{id}` endpoint, it should return a 200 response code&lt;/li&gt;
&lt;li&gt;Given an `id` for an existing record, and the `Accept` header is `application/xml`, when calling the `/api/record/{id}` endpoint, 
it should return the record for that `id` in XML format&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this example there are two problems: We're repeating the same setup over and over again, and the test descriptions are becoming verbose run-on sentences. Structured testing can help solve this problem. We can group these tests into nested contexts like so:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Given an `id` for an existing record

&lt;ul&gt;
&lt;li&gt;When calling the `/api/record/{id}` endpoint

&lt;ul&gt;
&lt;li&gt;It should return the record for that `id`&lt;/li&gt;
&lt;li&gt;It should return a 200 response code&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;And the &lt;code&gt;Accept&lt;/code&gt; header is &lt;code&gt;application/xml&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;When calling the `/api/record/{id}` endpoint 

&lt;ul&gt;
&lt;li&gt;It should return the record for that `id` in XML format&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Resulting in the following output:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fudynw7f13hlrz4p615dq.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fudynw7f13hlrz4p615dq.jpg" alt="Structured Test Output" width="800" height="273"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Notice the expand/collapse controls that can help narrow down on the specific cases you may be interested in&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This definitely looks cleaner. One could argue that this deviates from a natural language sentence structure, or that there's extra cognitive load in having to piece together the full declaration of a single test from its setup, to execution, to expectation. This might be true, but in the first example with the flattened test structure we also have an arguably poor sentence structure given that they verge on run on sentences. And there may be just as much mental load grouping the tests together which share the same contexts. So in that sense it's a wash. But from a visualization, and organization standpoint, providing a structure like this is the clear winner.&lt;/p&gt;

&lt;p&gt;In JUnit this can be accomplished using the &lt;code&gt;@Nested&lt;/code&gt; annotation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@DisplayName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"REST Endpoint tests"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RestEndpointTest&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

  &lt;span class="nd"&gt;@DisplayName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Given a valid `id`"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="nd"&gt;@Nested&lt;/span&gt;
  &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;GivenValidId&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@DisplayName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"When calling the `/api/record/{id}` endpoint"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="nd"&gt;@Nested&lt;/span&gt;
    &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WhenCallingRecordEndpoint&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

      &lt;span class="nd"&gt;@DisplayName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"It should return the record for that `id`"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
      &lt;span class="nd"&gt;@Test&lt;/span&gt;
      &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;testRecordReturned&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// test code here&lt;/span&gt;
      &lt;span class="o"&gt;}&lt;/span&gt;

      &lt;span class="nd"&gt;@DisplayName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"It should return a 200 response code"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
      &lt;span class="nd"&gt;@Test&lt;/span&gt;
      &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;test200Response&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// test code here&lt;/span&gt;
      &lt;span class="o"&gt;}&lt;/span&gt;

      &lt;span class="c1"&gt;// ... other tests&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Structured testing isn't always mandatory. Sometimes a unit is simple enough that its tests can be written out in a flat list. But more often then not, I find that for the sake of readability and organization, it's necessary to introduce some kind of structure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;By focusing on clear and comprehensible test output, we can ensure that both current and future developers can easily understand the purpose and results of tests. This not only aids in debugging and maintaining the code but also increases confidence in making changes and improvements. Well-written tests serve as valuable documentation, making the development process smoother and more reliable. &lt;/p&gt;

&lt;p&gt;See more in my &lt;a href="https://dev.to/pauldmooney/enhancing-the-developer-experience-of-testing-part-2-3oee"&gt;next post&lt;/a&gt;&lt;/p&gt;

</description>
      <category>testing</category>
    </item>
    <item>
      <title>Ditching Docker Compose for Kubernetes</title>
      <dc:creator>Paul Mooney</dc:creator>
      <pubDate>Tue, 06 Apr 2021 22:05:49 +0000</pubDate>
      <link>https://dev.to/pauldmooney/ditching-docker-compose-for-kubernetes-1jke</link>
      <guid>https://dev.to/pauldmooney/ditching-docker-compose-for-kubernetes-1jke</guid>
      <description>&lt;p&gt;When developing locally I usually incorporate Docker Compose into my local development workflow: Bringing up supporting containers needed to run databases, reverse proxies, other applications, or just to see how the container I'm developing works. Given that &lt;a href="https://www.docker.com/products/docker-desktop"&gt;Docker Desktop&lt;/a&gt; comes with a single node Kubernetes (K8s) cluster and I usually end up deploying my containers to a Kubernetes cluster, I wanted to figure out if I can switch from Docker-Compose to Kubernetes for local development. It's also a good way to work the kinks out of Kubernetes manifests or Helm charts without disrupting any shared environments.&lt;/p&gt;

&lt;p&gt;There are five things I need to be able to do in order to replace Docker-Compose with Kubernetes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
Build an image locally and run it on the Kubernetes.&lt;/li&gt;
&lt;li&gt;
Make changes to an app and redeploy on Kubernetes.&lt;/li&gt;
&lt;li&gt;
Make an easily accessible volume mount on a container in Kubernetes.&lt;/li&gt;
&lt;li&gt;
Have Kubernetes apps easily communicate with host OS apps.&lt;/li&gt;
&lt;li&gt;
Have host OS apps easily communicate with Kubernetes apps.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you want to skip to how all of this works out here's the TL;DR otherwise keep reading.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Warning: The rest of this post assumes some familiarity with Docker and Kubernetes.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;You can find sample applications that demonstrate all of this in &lt;a href="https://github.com/PaulDMooney/Local-K8s-Dev-Blog/"&gt;this monorepo&lt;/a&gt; along with an &lt;a href="https://github.com/PaulDMooney/Local-K8s-Dev-Blog/blob/main/README.md#working-with-the-local-environment"&gt;explanation to get up and running&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;span id="build-local"&gt;Build an image locally and run it on the Kubernetes&lt;/span&gt;
&lt;/h2&gt;

&lt;p&gt;With Docker Compose I can build an image and run it with just one simple command &lt;code&gt;docker-compose up --build&lt;/code&gt;, assuming I have my docker-compose files setup. What's the analogue of this with Kubernetes? When I build an image, how can Kubernetes pull it? Do I need a local &lt;a href="https://docs.docker.com/registry"&gt;Docker Registry&lt;/a&gt; to push my image to? &lt;/p&gt;

&lt;p&gt;The answer to that last question, luckily, is "No". When building an image locally using the standard docker build command &lt;code&gt;docker build --tag my-image:local .&lt;/code&gt; the image is stored in docker's image cache. This is the &lt;em&gt;same&lt;/em&gt; image cache Kubernetes will use because it's using the &lt;em&gt;same&lt;/em&gt; docker instance. There are two things to note here:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The &lt;code&gt;image&lt;/code&gt; name of a Kubernetes pod must exactly match the name given via the &lt;code&gt;--tag&lt;/code&gt; parameter of the &lt;code&gt;docker build&lt;/code&gt; command. In the example given it's &lt;code&gt;my-image:local&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;imagePullPolicy&lt;/code&gt; must be set to &lt;code&gt;Never&lt;/code&gt; or &lt;code&gt;IfNotPresent&lt;/code&gt;. It cannot be set to &lt;code&gt;Always&lt;/code&gt; otherwise Kubernetes will attempt to pull the image from a remote registry like &lt;a href="https://hub.docker.com/"&gt;Docker Hub&lt;/a&gt;, and it would fail.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;my-container&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;my-image:local"&lt;/span&gt;
    &lt;span class="na"&gt;imagePullPolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Never&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
Container definitions would contain an `image` name that matches your build command and an `imagePullPolicy` that is not `Always`





&lt;p&gt;That covers how to build and run an image locally.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;span id="make-changes"&gt;Make Changes to an app and redeploy on Kubernetes&lt;/span&gt;
&lt;/h2&gt;

&lt;p&gt;If I were making changes to the application or its image definition (ie, Dockerfile) and wanted to see it running in Docker Compose I would just run the command &lt;code&gt;docker-compose up --build&lt;/code&gt;. For kubernetes we can rebuild the image &lt;code&gt;docker build --tag my-image:local&lt;/code&gt;. That much is the same as the initial build but you will probably notice your changes aren't actually running in Kubernetes right away. &lt;/p&gt;

&lt;p&gt;The problem is there's been no signal for Kubernetes to do anything after the image was built. The solution is to delete the pod the image was running in and recreate it. If you are running single unmanaged pod (which I think is unlikely) you would have to delete it and recreate it yourself from the pod definition yaml. If you're running a deployment or a statefulset you can either delete the pods and they will automatically be recreated for you, or you can scale down the replicas to 0 and then back up again:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Delete a pod: &lt;code&gt;kubectl delete pod my-pod-xyz --force&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Scale down &lt;code&gt;kubectl scale deployment my-deployment --replicas=0&lt;/code&gt; and then back up &lt;code&gt;kubectl scale deployment my-deployment --replicas=3&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;span id="volume-mount"&gt;Make an easily accessible volume mount on a container in Kubernetes&lt;/span&gt;
&lt;/h2&gt;

&lt;p&gt;In Docker Compose, volumes can be fairly straightforward in that we can mount any file or subdirectory relative to the directory we are executing &lt;code&gt;docker-compose&lt;/code&gt; from. That makes it easy to find, inspect and cleanup those files. But Kubernetes is not the same. It's not running from a project's folder like Docker Compose, it's already running on the Docker Desktop Virtual Machine somewhere. So if we defined a volume to mount into a container, where would the data for that volume live? It lives in the Docker Desktop Virtual Machine somewhere (unless we're running WSL 2). Luckily Docker Desktop has file sharing setup with the host OS so we can take advantage of this to do any inspection or cleanup of persistent data.&lt;/p&gt;

&lt;p&gt;Going into the Docker Desktop dashboard under Settings/Preferences -&amp;gt; Resources -&amp;gt; File Sharing I can see and manage all of the file sharing that is available. Using this information I can create a &lt;a href="https://kubernetes.io/docs/concepts/storage/volumes/#hostpath"&gt;hostPath&lt;/a&gt; Persistent Volume that my application can &lt;a href="https://kubernetes.io/docs/concepts/storage/persistent-volumes/#persistentvolumeclaims"&gt;claim&lt;/a&gt; and use. In my example below I picked a path under &lt;code&gt;/Users&lt;/code&gt; since that was already shared (on MacOS):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PersistentVolume&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;my-volume&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;storageClassName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;my-volume-class&lt;/span&gt;
  &lt;span class="na"&gt;accessModes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;ReadWriteMany&lt;/span&gt;
  &lt;span class="na"&gt;capacity&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;storage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;1Gi&lt;/span&gt;
  &lt;span class="na"&gt;hostPath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/Users/Shared/my-volume"&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;DirectoryOrCreate&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This volume obviously differs from what you would use in your dev or prod Kubernetes clusters, so I recommend having a folder of "local" persistent volume definition yamls like this that can be reused by team mates (or your future self) to populate their Kubernetes with. Unfortunately you may have no choice but to have different persistent volume yamls for both Mac and Windows if your team uses a mix of those.&lt;/p&gt;

&lt;p&gt;One last thing - if you ever delete the claim to this Persistent Volume, you must delete and recreate the Persistent Volume too, if you ever want to run your application again in the future. This is not unique to local Kubernetes development.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;span id="docker-internal-dns"&gt;Have Kubernetes apps easily communicate with host OS apps&lt;/span&gt;
&lt;/h2&gt;

&lt;p&gt;Often times I will be working on an application in the host OS. Most of my primary development is done here, as you get the advantages of automatic rebuilds and IDE tooling, etc. There will be other applications that I'd like to run in Kubernetes that can talk to this application on the host OS. For example, I may have a reverse proxy like nginx running in Kubernetes that needs to serve up my host OS application. This is super easy, and done exactly the same as we would do it with just Docker or Docker Compose: with the &lt;code&gt;host.docker.internal&lt;/code&gt; DNS name. &lt;/p&gt;

&lt;p&gt;An example of my nginx config running on kubernetes that reverse proxies my app running on the host port 4200:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;server {
    listen       80;
    server_name  localhost;

    location / {
        proxy_pass http://host.docker.internal:4200;
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;span id="expose-app"&gt;Have host OS apps easily communicate with Kubernetes apps&lt;/span&gt;
&lt;/h2&gt;

&lt;p&gt;Whether I'm developing an application on the host OS that communicates with an application on Kubernetes, or if I want to access the application on Kubernetes in a web browser, or some kind of client, the application needs to be exposed. There are two ways to do this. The first, and not my recommended approach, is to use &lt;a href="https://kubernetes.io/docs/tasks/access-application-cluster/port-forward-access-application-cluster/#forward-a-local-port-to-a-port-on-the-pod"&gt;kubectl port-forwarding&lt;/a&gt;. I don't like this approach because you need to be re-run this command whenever you restart your cluster for every service that needs to be exposed. My preferred approach is to use a &lt;a href="https://kubernetes.io/docs/concepts/services-networking/service/#nodeport"&gt;NodePort&lt;/a&gt; service.&lt;/p&gt;

&lt;p&gt;A NodePort exposes a port on the kubernetes node that you can access your application through and in Docker Desktop that exposes the port on your host OS.&lt;/p&gt;

&lt;p&gt;So I can create a service for my application like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Service&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;my-app-service&lt;/span&gt;
  &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="s"&gt;app.kubernetes.io/name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;my-app-service&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;NodePort&lt;/span&gt;
  &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3000&lt;/span&gt;
      &lt;span class="na"&gt;targetPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;http&lt;/span&gt;
      &lt;span class="na"&gt;protocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;TCP&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;http&lt;/span&gt;
      &lt;span class="na"&gt;nodePort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;30001&lt;/span&gt; 
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="s"&gt;app.kubernetes.io/name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;my-app&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And I can access my application at &lt;code&gt;localhost:30001&lt;/code&gt;!&lt;/p&gt;

&lt;p&gt;I prefer to define my nodePort for predictability of the port, but you can leave it empty for Kubernetes to decide what it should be. Then there's less chance of a collision for an already occupied port.&lt;/p&gt;

&lt;p&gt;Chances are the application's service might be a ClusterIP or LoadBalancer type when deployed to other Kubernetes clusters, or that the nodePort will have a different value in those clusters. You can get around this by templating your service definition in &lt;a href="https://helm.sh/"&gt;Helm&lt;/a&gt;, and having different service configurations for your local Kubernetes versus other Kubernetes clusters.&lt;/p&gt;

&lt;h2&gt;
  
  
  Helm
&lt;/h2&gt;

&lt;p&gt;Without Helm, or similar tools, using a local Kubernetes cluster for development is pointless beyond just experimentation purposes. We want to use the local Kubernetes cluster so that our running applications will mirror shared environments, like production as closely as possible. Helm lets us accomplish this by allowing us to template out our kubernetes manifests, and abstract out only the necessary environmental differences into &lt;a href="https://helm.sh/docs/chart_template_guide/values_files/"&gt;values files&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;When you're using Helm you'll be creating values files for every environment. I recommend creating values files for local clusters as well that can be shared with the team. You can even create personal "overrides" values files that you can use to change some minor configurations for your own purposes (just be sure to .gitignore them). Helm lets you chain these files together, and gives precendence to the rightmost file. E.g., &lt;code&gt;helm upgrade my-app ./my-app -f values-local.yaml -f .values-override.yaml&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Another benefit of Helm is in it's package management. If your application requires another team's application up and running, they can publish their Helm chart to a remote repository like a &lt;a href="https://github.com/helm/chartmuseum"&gt;ChartMuseum&lt;/a&gt;. You can then install their application into your Kubernetes by naming that remote chart combined with a local values file. E.g., &lt;code&gt;helm install other-teams-app https://charts.mycompany.com/other-teams-app-1.2.3.tgz -f values-other-teams-app.yaml&lt;/code&gt;. This is convenient because it means you don't have to checkout their project and dig through it for their helm charts to get up and running - all you need to supply is your own values file.&lt;/p&gt;

&lt;h2&gt;
  
  
  Scripting
&lt;/h2&gt;

&lt;p&gt;Working with kubernetes, and then layering in extra tools like Helm, there are a lot of commands to get to know. Most of your team will probably need some kind of containerized apps running locally, but it can be a high bar to expect them to know all of the docker and kubectl and helm commands. You will also want to take the things that are done often and condense them into some simpler scripts for your own convenience. Things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Build and Install your app on the kubernetes cluster:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker build --tag myimage:local \
&amp;amp;&amp;amp; kubectl apply -f my-volume.yaml \
&amp;amp;&amp;amp; helm install my-app ./my-app -f values-local.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Build and restart your app:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker build --tag myimage:local \
&amp;amp;&amp;amp; kubectl scale deployment my-app --replicas=0 \
&amp;amp;&amp;amp; kubectl scale deployment my-app --replicas=3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Update your configuration:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;helm upgrade my-app ./my-app -f values-local.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Install another team or organization's app:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;helm install other-teams-app https://charts.mycompany.com/other-teams-app-1.2.3.tgz -f values-other-teams-app.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Clean up
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;helm uninstall my-app \
&amp;amp;&amp;amp; kubectl delete -f my-volume.yaml
&amp;amp;&amp;amp; rm -Rf /path/to/my-volume
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can script this however you like, whether it be in bash, Makefile, npm scripts, Gradle tasks. Use whatever suits your team best.&lt;/p&gt;

&lt;h2&gt;
  
  
  Comparing to Docker Compose
&lt;/h2&gt;

&lt;p&gt;Using Docker Compose for local development is undoubtedly more convenient than Kubernetes. For the most part you only need to be familiar with two commands to build, run, re-build and re-run, and shutdown your applications in docker: &lt;code&gt;docker-compose up --build&lt;/code&gt;, and &lt;code&gt;docker-compose down&lt;/code&gt;. For volumes, Docker Compose lets you mount a directory relative to where you execute &lt;code&gt;docker-compose&lt;/code&gt; from and in a way that works across platforms. Docker Compose is also safer - there's no chance you're going to accidentally &lt;code&gt;docker-compose up&lt;/code&gt; a mid-developed image into production!&lt;/p&gt;

&lt;p&gt;Docker Compose has the disadvantage that it's a duplication of effort to recreate an analogue of your Kubernetes manifests into docker-compose files. Considering the extra configurations, volume definitions, and scripting that needs to be added for local Kubernetes development, this is probably a negligable difference.&lt;/p&gt;

&lt;p&gt;Kubernetes, on the other hand, more accurately represents what you will be deploying into shared Kubernetes clusters or production. Using a tool like Helm gives us package manager-like features of installing externally developed manifest or dependencies without having to redefine them in your local repository. &lt;/p&gt;

&lt;p&gt;Using Kubernetes requires a good familiarity with Kubernetes and its surrounding tools, or extra scripting to hide these details. These tools like &lt;code&gt;kubectl&lt;/code&gt; and &lt;code&gt;helm&lt;/code&gt; rely on a &lt;a href="https://kubernetes.io/docs/reference/kubectl/cheatsheet/#kubectl-context-and-configuration"&gt;context&lt;/a&gt; which could be set to the wrong Kubernetes cluster, which would cause unwanted trouble! I recommend putting safeguards in place like setting up &lt;a href="https://kubernetes.io/docs/reference/access-authn-authz/rbac/"&gt;RBAC&lt;/a&gt; where possible in the shared or production Kubernetes clusters where possible. Or, work within a &lt;a href="https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/"&gt;namespace&lt;/a&gt; locally that does not exist in other clusters.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;It's possible to replace Docker Compose with Kubernetes for local development, but for the added complexity and trade-offs it may be worth using both. For most local development, Docker Compose is probably good enough, and much simpler. Using a local Kubernetes cluster is a step up in terms of complexity and effort so it is up to you if you want to take that on. It is definitely worth it for Helm Chart / Manifest development or situations where you absolutely must re-create a part of your deployment architecture.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;Building and running an image on Kubernetes works because Kubernetes will pull from the same shared image cache you built from, just make sure your pull policy is not 'Always'.&lt;/p&gt;

&lt;p&gt;To re-build an image and re-run, just delete the old pods running the old image. Newly created pods will come up with the new image.&lt;/p&gt;

&lt;p&gt;Docker Deskop's file sharing locations can be found and configured in the Preferences/Settings. A Persistent Volume can be created with a hostPath to one of those locations.&lt;/p&gt;

&lt;p&gt;Applications running on Kubernetes can access applications on the host OS via the &lt;code&gt;host.docker.internal&lt;/code&gt; DNS name.&lt;/p&gt;

&lt;p&gt;Applications running on Kubernetes can be accessed by setting up &lt;a href="https://kubernetes.io/docs/tasks/access-application-cluster/port-forward-access-application-cluster/#forward-a-local-port-to-a-port-on-the-pod"&gt;kubectl port forwarding&lt;/a&gt; and then accessed using &lt;code&gt;localhost:{forwardedPort}&lt;/code&gt;. Or, even better, make the Application's service a nodePort service and access using &lt;code&gt;localhost:{nodePort}&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Use Helm. Simplify the common tasks via scripting. Maybe don't ditch Docker Compose completely.&lt;/p&gt;

</description>
      <category>docker</category>
      <category>kubernetes</category>
    </item>
    <item>
      <title>Baking Configuration into your Angular App Pie</title>
      <dc:creator>Paul Mooney</dc:creator>
      <pubDate>Fri, 25 Oct 2019 14:50:35 +0000</pubDate>
      <link>https://dev.to/pauldmooney/baking-configuration-into-your-angular-app-pie-44mn</link>
      <guid>https://dev.to/pauldmooney/baking-configuration-into-your-angular-app-pie-44mn</guid>
      <description>&lt;p&gt;In this post I'm going to talk about some of the best ways to get your configurations to your Angular app. Just note, this isn't a post about Angular framework level configurations, this is about how the features you're developing receive your configurable values.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where's my Backend API Server?
&lt;/h2&gt;

&lt;p&gt;Most SPAs need a backend API server, so when development starts there's the question of "how do I tell my app where my API server is?" The answer is that you don't. Your app should assume the API server is served from the same host as the app itself. It will only use relative URLs (in this case "relative" means no protocol, host, or port specified) to call the API server.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Injectable&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;providedIn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;root&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ServerTimeService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;httpClient&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;HttpClient&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;getTime&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="c1"&gt;// Calls relative path `/api`. No host in the URL here.&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;httpClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/servertime&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="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;servertime&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is nice and clean, and avoids &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS" rel="noopener noreferrer"&gt;CORS&lt;/a&gt; complications and issues.&lt;/p&gt;

&lt;p&gt;How do we achieve this? With &lt;a href="https://www.nginx.com/resources/glossary/reverse-proxy-server/" rel="noopener noreferrer"&gt;Reverse Proxies&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let's look at the scenario where your backend API server sits at &lt;code&gt;http://myinternalhost:8080/api&lt;/code&gt; and we want the app to be able to make requests only to paths starting with &lt;code&gt;/api&lt;/code&gt;. Here's how you can configure reverse proxies for development and when deployed:&lt;/p&gt;

&lt;h3&gt;
  
  
  Proxy Server during Development
&lt;/h3&gt;

&lt;p&gt;When a project is generated using Angular CLI it uses &lt;a href="https://webpack.js.org/" rel="noopener noreferrer"&gt;webpack&lt;/a&gt; (at least at the time of writing this) which includes a &lt;a href="https://webpack.js.org/configuration/dev-server/" rel="noopener noreferrer"&gt;dev server&lt;/a&gt; that hosts the app and watches for changes when we run &lt;code&gt;ng serve&lt;/code&gt; (or &lt;code&gt;npm start&lt;/code&gt; if you're using the Angular CLI defaults). This server also includes a reverse proxy which can be configured via &lt;code&gt;proxy.conf.js&lt;/code&gt; or &lt;code&gt;proxy.conf.json&lt;/code&gt; file. You can read more about it in the &lt;a href="https://github.com/angular/angular-cli/blob/master/docs/documentation/stories/proxy.md" rel="noopener noreferrer"&gt;Angular CLI repo&lt;/a&gt;. I prefer the 'js' version of the file since it gives us more flexibility.&lt;/p&gt;

&lt;p&gt;Given our example scenario for getting requests from the relative path &lt;code&gt;/api&lt;/code&gt; to the absolute path &lt;code&gt;http://myinternalhost:8080/api&lt;/code&gt;, we can setup our &lt;code&gt;proxy.conf.js&lt;/code&gt; in the root of our project folder like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;PROXY_CONFIG&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;target&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://myinternalhost:8080&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;secure&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;logLevel&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;debug&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;changeOrigin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;PROXY_CONFIG&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And alter the "start" npm script to tell it to use the &lt;code&gt;proxy.conf.js&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"start"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"ng serve --proxy-config proxy.conf.js"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Of course it would be better if the &lt;code&gt;target&lt;/code&gt; value was not hardcoded to a specific server in a file that we're going to be checking into version control, so we can use an environment variable instead. Let's make the above snippet better:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;PROXY_CONFIG&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;target&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;API_SERVER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;secure&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;logLevel&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;debug&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;changeOrigin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;PROXY_CONFIG&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The environment variable can be passed via commandline &lt;code&gt;API_SERVER=http://myinternalhost:8080 npm start&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reverse Proxy when Deployed
&lt;/h3&gt;

&lt;p&gt;When you're deploying your application, you won't have webpack's dev-server to use as a reverse proxy so you'll need a separate standalone one. Popular options for reverse proxies are webservers like &lt;a href="https://www.nginx.com/" rel="noopener noreferrer"&gt;NGINX&lt;/a&gt; or &lt;a href="https://httpd.apache.org/" rel="noopener noreferrer"&gt;Apache HTTP Server&lt;/a&gt;. These serve other purposes as well such as handling HTTPS, load balancing, or if you're not using Server Side Rendering (&lt;a href="https://angular.io/guide/universal" rel="noopener noreferrer"&gt;https://angular.io/guide/universal&lt;/a&gt;) they can be used to serve your Angular app's static assets. So it's likely you'll need one of these anyways.&lt;/p&gt;

&lt;p&gt;The key idea here is that the reverse proxy is the single point for traffic to and from the browser for both requests to your app, and requests to the API server.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fh1e0unghrqvyp1v4jrwo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fh1e0unghrqvyp1v4jrwo.png" alt="Reverse Proxy Layout"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here's a snippet of nginx configuration that forwards traffic to your app, and to our &lt;code&gt;http://myinternalhost:8080&lt;/code&gt; API server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kn"&gt;listen&lt;/span&gt;       &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kn"&gt;server_name&lt;/span&gt;  &lt;span class="s"&gt;localhost&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;# Reverse proxy all traffic to the Angular app&lt;/span&gt;
  &lt;span class="kn"&gt;location&lt;/span&gt; &lt;span class="n"&gt;/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;proxy_pass&lt;/span&gt; &lt;span class="s"&gt;http://localhost:4000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;# Reverse proxy all traffic starting with `/api` to the backend API server&lt;/span&gt;
  &lt;span class="kn"&gt;location&lt;/span&gt; &lt;span class="n"&gt;/api&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;proxy_pass&lt;/span&gt; &lt;span class="s"&gt;http://myinternalhost:8080&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;NGINX itself can be configured to use environment variables as mentioned on its &lt;a href="https://hub.docker.com/_/nginx" rel="noopener noreferrer"&gt;Docker Hub page&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  What about Server Side Rendering?
&lt;/h3&gt;

&lt;p&gt;In server side rendering (SSR), your Angular app's code is running on the server similar to how it would run in the browser, complete with the API calls it needs to make but with a few exceptions. One of those exceptions is that relative URLs are meaningless on the server. Servers want absolute URLs. So it turns out that our app &lt;em&gt;does&lt;/em&gt; need that absolute URL to the backend API afterall.&lt;/p&gt;

&lt;p&gt;Luckily, when rendering on the server, we're &lt;em&gt;not&lt;/em&gt; in a context where we need to worry about CORS, and we &lt;em&gt;are&lt;/em&gt; in a context where your code can read environment variables. So our example HttpClient request can be altered to look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Injectable&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;providedIn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;root&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ServerTimeService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;httpClient&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;HttpClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;PLATFORM_ID&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;platformId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;getTime&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/servertime&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Make URL absolute only if on the server&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;isPlatformServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;platformId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;API_SERVER&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;httpClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;servertime&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This doesn't mean we can ditch the reverse proxy setup, we still need that when the app is running in the browser. This is just an extra consideration to make when leveraging SSR.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt;&lt;br&gt;
For this to compile, you will also need to install node types via &lt;code&gt;npm i -D @types/node&lt;/code&gt; and then add &lt;code&gt;"node"&lt;/code&gt; to the &lt;code&gt;compilerOptions.types&lt;/code&gt; array of the the &lt;code&gt;tsconfig.app.json&lt;/code&gt; file.&lt;/p&gt;
&lt;h2&gt;
  
  
  Environment Variables vs Environment.ts
&lt;/h2&gt;

&lt;p&gt;Let's imagine another scenario where your Angular app has a typeahead search in it, and it needs a debounce time to decide when the user has stopped typing and it's safe to make an API call. Kind of like &lt;a href="https://www.freakyjolly.com/angular-7-6-add-debounce-time-using-rxjs-6-x-x-to-optimize-search-input-for-api-results-from-server/" rel="noopener noreferrer"&gt;this article&lt;/a&gt; describes. We want to make the debounce time configurable.&lt;/p&gt;

&lt;p&gt;It'd be tempting to use the &lt;code&gt;Environment.ts&lt;/code&gt; and &lt;code&gt;Environment.prod.ts&lt;/code&gt; as the configuration point for this debounce time, but you probably shouldn't. Actually, just don't. It's a violation of the &lt;a href="https://12factor.net/config" rel="noopener noreferrer"&gt;third factor&lt;/a&gt; of &lt;a href="https://12factor.net/" rel="noopener noreferrer"&gt;The Twelve-Factor App&lt;/a&gt;. The short of it is that if you are using a version controlled file in your app to store configuration then your app has to be rebuilt and redeployed just to affect a configuration change. Sounds like hardcoding not configuration. This is fine for the world of Infrastructure as Code and GitOps but it is not ideal for applications.&lt;/p&gt;

&lt;p&gt;In general you probably won't use the &lt;code&gt;Environment.ts&lt;/code&gt; files much unless there are different modes your application needs to be built in. If you find yourself writing &lt;code&gt;Environment.staging.ts&lt;/code&gt; or &lt;code&gt;Environment.qa.ts&lt;/code&gt; files, you're doing it wrong.&lt;/p&gt;

&lt;p&gt;So how do you configure this 'debounce' time in the app? With Environment Variables! How do we use environment variables in an app that mostly runs in the browser? Serve them via API server.&lt;/p&gt;

&lt;p&gt;There are multiple ways to do this. We'll take the approach that we're using a purpose built "Config" REST endpoint just for this Angular app.&lt;/p&gt;
&lt;h3&gt;
  
  
  Sending environment variables during Development
&lt;/h3&gt;

&lt;p&gt;A quick and easy way to create a Config REST endpoint to use during development is to leverage the webpack's proxy server. We can create a faux backend inside the &lt;code&gt;proxy.conf.js&lt;/code&gt; file like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;PROXY_CONFIG&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/config&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bypass&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;proxyOptions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;switch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/config&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

                &lt;span class="c1"&gt;// Send an map of config values&lt;/span&gt;
                &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;end&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
                    &lt;span class="na"&gt;DEBOUNCE_TIME&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DEBOUNCE_TIME&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt; &lt;span class="c1"&gt;// Read from environment or default to 500&lt;/span&gt;
                    &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="c1"&gt;// Other config values here&lt;/span&gt;
                &lt;span class="p"&gt;}));&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="c1"&gt;// Other proxy settings&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="nx"&gt;PROXY_CONFIG&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From there it's just a matter of making a call to this &lt;code&gt;/config&lt;/code&gt; endpoint just like any other endpoint.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;httpClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/config&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can start your development server with an environment variable like so &lt;code&gt;DEBOUNCE_TIME=300 npm start&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Sending environment variables when Deployed
&lt;/h3&gt;

&lt;p&gt;For this, you'd probably just have to build a separate server, perhaps using something like &lt;a href="https://expressjs.com/" rel="noopener noreferrer"&gt;Express&lt;/a&gt;. However, if you're leveraging server side rendering then you'll probably already have a server in the form of the &lt;code&gt;server.ts&lt;/code&gt; file (likely generated by a &lt;a href="https://angular.io/guide/schematics" rel="noopener noreferrer"&gt;schematic&lt;/a&gt; like &lt;a href="https://www.npmjs.com/package/@nguniversal/express-engine" rel="noopener noreferrer"&gt;@nguniversal/express-engine&lt;/a&gt;). This is a good place to add a little extra functionality to serve up configuration read from server side environment variables in a similar manner to how it's done in the &lt;code&gt;proxy.conf.js&lt;/code&gt; example.&lt;/p&gt;

&lt;p&gt;Add the following to the &lt;code&gt;server.ts&lt;/code&gt; file used for SSR:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/config&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="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;DEBOUNCE_TIME&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DEBOUNCE_TIME&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt; &lt;span class="c1"&gt;// Read from environment or default to 500&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="c1"&gt;// Other config values here&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;During server side rendering, when the code is executing on the server you won't necessarily need to call this API (though you could) since you can just directly access the environment variables from within code. To keep things simple, it's probably best to hide how all of your configuration values are retreived behind a single "Config" Angular service:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Injectable&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;providedIn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;root&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ConfigService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;httpClient&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;HttpClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;PLATFORM_ID&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;platformId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

  &lt;span class="nf"&gt;getConfig&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="c1"&gt;// Direct, speedy access to environment variables when on server.&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;isPlatformServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;platformId&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="k"&gt;of&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;DEBOUNCE_TIME&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DEBOUNCE_TIME&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Otherwise from the brwoser call the `/config` API.&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;httpClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/config&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Avoid Depending on Transferstate to Transport your Configuration
&lt;/h4&gt;

&lt;p&gt;When using server side rendering, It may be tempting to avoid setting up a "Config" REST service like the one above and just leverage transfer state to gather values from environment variables on the server and send them to the client. This may or may not work for you but if you're enabling &lt;a href="https://angular.io/guide/service-worker-getting-started" rel="noopener noreferrer"&gt;Progressive Web App&lt;/a&gt; then a good deal of the time server side rendering won't even come into play since the app is rendered from javascript and other assets cached in the browser, bypassing SSR completely. Since there's no SSR happening in a PWA, there's no transferstate, so it's not a good idea to make it the sole medium for transporting configuration values.&lt;/p&gt;

&lt;h2&gt;
  
  
  The right time to call your Configuration API endpoint
&lt;/h2&gt;

&lt;p&gt;There are different situations where you may need to call a configuration API in the lifecycle of your app. The earlier it's called the better, but it can also get more complex. These are some of the places where you could call the config API from:&lt;/p&gt;

&lt;h3&gt;
  
  
  On Demand, maybe leveraging a behaviour subject
&lt;/h3&gt;

&lt;p&gt;This is like the title says, call it only when you need. This is ideal when you require configuration values for some of the views or components you're developing. You can call the config API from one of the &lt;a href="https://angular.io/guide/lifecycle-hooks" rel="noopener noreferrer"&gt;lifecycle hooks&lt;/a&gt; of your components.&lt;/p&gt;

&lt;p&gt;Perhaps use something like a &lt;a href="https://rxjs-dev.firebaseapp.com/api/index/class/ReplaySubject" rel="noopener noreferrer"&gt;Replay Subject&lt;/a&gt; to prevent multiple or competing calls going to the config API at once and to cache your config values.&lt;/p&gt;

&lt;h3&gt;
  
  
  From the Angular APP_INITIALIZER hook
&lt;/h3&gt;

&lt;p&gt;An APP_INITIALIZER function gets called during Angular's startup. This is likely the place you want to execute your config retrieval if some of those configurations are central to the app. Like say, if they relate to how you might configure a global aspect of the app such as internationalization, or possibly affect some change in routing, or maybe if you prefer the app to just fail fast when there is an invalid configuration instead of finding out later when the config value is finally used.&lt;/p&gt;

&lt;p&gt;You can read more about the &lt;a href="https://www.tektutorialshub.com/angular/angular-how-to-use-app-initializer/" rel="noopener noreferrer"&gt;APP_INITIALIZER&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Again, it's probably good to wrap the config API call in a Replay Subject just so that its results can be cached for later.&lt;/p&gt;

&lt;h3&gt;
  
  
  Before Angular Starts
&lt;/h3&gt;

&lt;p&gt;This is the earliest time to retrieve configuration: before anything Angular begins to bootstrap. This is good for situations where you need these values even earlier than APP_INITIALIZER allows. Examples might be if you need them to configure a custom &lt;a href="https://angular.io/api/common/http/HttpInterceptor" rel="noopener noreferrer"&gt;HttpInterceptor&lt;/a&gt; or if you have a special &lt;a href="https://angular.io/api/core/ErrorHandler" rel="noopener noreferrer"&gt;Error Handler&lt;/a&gt; that needs an API key to a logging service.&lt;/p&gt;

&lt;p&gt;The place to make this call is in the &lt;code&gt;main.ts&lt;/code&gt; file. On return, store the results in local storage so that they can be retrieved when needed. Note that angular service such as HttpClient won't be available so the browser basics like &lt;code&gt;fetch&lt;/code&gt; or &lt;code&gt;XMLHttpRequest&lt;/code&gt; will have to do.&lt;/p&gt;

&lt;p&gt;Example &lt;code&gt;main.ts&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;production&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;enableProdMode&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;DOMContentLoaded&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/config&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;config&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;platformBrowserDynamic&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;bootstrapModule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;AppModule&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  .env Files
&lt;/h2&gt;

&lt;p&gt;One last bonus tidbit of information: It can be tedious to setup environment variables in the command line when developing. Especially if there's a lot of them. The answer to this problem is the &lt;code&gt;.env&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;It's a simple file where each line is an environment variable assignment in the format &lt;code&gt;VARIABLE_NAME=value&lt;/code&gt;. &lt;em&gt;And&lt;/em&gt; it supports comments!&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;.env&lt;/code&gt; file works out of the box in some runtimes, like for docker-compose, but doesn't work out of the box in node.js. You'll need to install the library &lt;a href="https://www.npmjs.com/package/dotenv" rel="noopener noreferrer"&gt;dotenv&lt;/a&gt; as a dev dependency: &lt;code&gt;npm i -D dotenv&lt;/code&gt; and then have it loaded up.&lt;/p&gt;

&lt;p&gt;To load it in your &lt;code&gt;proxy.conf.js&lt;/code&gt;, just add the following line to the top of the file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dotenv&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To load it for SSR, alter the npm script called "serve:ssr" to the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"serve:ssr"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"node -r dotenv/config dist/server"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally be sure &lt;code&gt;.env&lt;/code&gt; file entry is added to your &lt;code&gt;.gitignore&lt;/code&gt; file. This file is for your local development, it would be really annoying if your settings were regularly and unexpectedly clobbered by someone else's changes whenever you're pulling the latest.&lt;/p&gt;

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

&lt;p&gt;To summarize what we've learned here about getting configuration to your Angular app:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Use a reverse-proxy to "host" your Angular app and Backend APIs from the same server, don't try to configure where that backend API is in your Angular app.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You may have very frontend specific configurations that aren't appropriate to serve from your existing business oriented backend APIs. If so, create a simple config API by hijacking your webpack dev-server during development, and by hijacking your server.ts file if your're using SSR.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Environment Variables are a good medium to set config values from the server side.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You probably won't need &lt;code&gt;Environment.ts&lt;/code&gt; files as much as you think.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;There are various times to call your config API. Pick one.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Don't forget the &lt;code&gt;.env&lt;/code&gt; files&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Hope this was a good read. Not all of it will be appropriate for your project, but I'm sure some of it will be.&lt;/p&gt;

&lt;p&gt;Sample project source, and this blog in the works, can be found &lt;a href="https://github.com/PaulDMooney/angular-config-blog" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;

</description>
      <category>angular</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Tips for Your Site's Iconography</title>
      <dc:creator>Paul Mooney</dc:creator>
      <pubDate>Fri, 19 Apr 2019 22:22:47 +0000</pubDate>
      <link>https://dev.to/pauldmooney/tips-for-your-site-s-iconography-5d63</link>
      <guid>https://dev.to/pauldmooney/tips-for-your-site-s-iconography-5d63</guid>
      <description>&lt;h2&gt;
  
  
  Choosing your Iconography Approach
&lt;/h2&gt;

&lt;p&gt;At the beginning of every web app's development there is the question of iconography. Which icon library do we use? There's lots to choose from: &lt;a href="https://fontawesome.com/" rel="noopener noreferrer"&gt;Font Awesome&lt;/a&gt;, &lt;a href="https://fortawesome.com/" rel="noopener noreferrer"&gt;Fort Awesome&lt;/a&gt;, &lt;a href="https://thenounproject.com/" rel="noopener noreferrer"&gt;The Noun Project&lt;/a&gt;, &lt;a href="https://material.io/tools/icons/" rel="noopener noreferrer"&gt;Material Design Icons&lt;/a&gt;, &lt;a href="https://icomoon.io/" rel="noopener noreferrer"&gt;IcoMoon&lt;/a&gt;. Generally this choice is up to the designer (if you have one), but as a developer your choice is going to be between using SVG's as icons or Icon fonts. There are a number of pros and cons to SVGs vs Icon fonts that you can find better articles on such as &lt;a href="https://css-tricks.com/icon-fonts-vs-svg/" rel="noopener noreferrer"&gt;this one&lt;/a&gt;. Here's my quick comparison:&lt;/p&gt;

&lt;p&gt;SVG Pros:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SVGs are generally sharper than fonts.&lt;/li&gt;
&lt;li&gt;You are able to specifically pick out and download only the SVGs you want. &lt;/li&gt;
&lt;li&gt;Aligning SVGs is simpler and more predictable because they aren't susceptible to weird font rules such as line height which can add unwanted white space.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;SVG Cons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Coloring external SVGs can't be done in CSS in a way that's supported in all browsers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Icon Font Pros:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Can be colored easily by setting the containing elements 'color' property.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Icon Font Cons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;While the font is loading up, or if it fails to load, you will see squares like this □ or the ligature of the icon. E.g., you will see the text 'get_app' where the &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmaterial.io%2Ftools%2Ficons%2Fstatic%2Ficons%2Fbaseline-get_app-24px.svg" alt="get_app icon"&gt; icon should appear.&lt;/li&gt;
&lt;li&gt;Fonts Icons can be trickier to align due to font rules applied to them (mentioned above).&lt;/li&gt;
&lt;li&gt;More difficult to hide from screen readers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With that brief comparison, it's up to you to decide but I'm going with SVG icons, at least for the rest of this article ;)&lt;/p&gt;

&lt;h2&gt;
  
  
  Inline SVGs vs External SVGs
&lt;/h2&gt;

&lt;p&gt;Inline SVGs, where the SVG definition is part of the &lt;a href="https://css-tricks.com/using-svg/#article-header-id-7" rel="noopener noreferrer"&gt;html document&lt;/a&gt;, versus External SVGs is the next choice to make.&lt;/p&gt;

&lt;p&gt;Mostly this choice comes down to your school of thought on iconography: is iconography part of the style or theme of your web application, aimed to be fully controlled by CSS? Or is iconography a part of the web app's makeup, meaning your html has additional markup just to support icons?&lt;/p&gt;

&lt;p&gt;If your school of thought is the former, then congratulations you've made the right choice! Or at least you have from a purists point of view, and definitely if you plan on treating the theme of your web application as a separated concern.&lt;/p&gt;

&lt;p&gt;Inline SVGs are still great in the sense that you get the flexibility to use CSS to select and color their elements. Or that they can be animated, but a lot of iconography design on the web today is static and monochrome. If you don't need multicolored, animated icons then you don't need to pollute your HTML with extra inline SVG markup and blur the lines between theme and content structure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Working with External SVG Icons
&lt;/h2&gt;

&lt;p&gt;Generally the best way to work with SVG Icons is to load them in as background images. This way screen readers will avoid them and we don't need to add extra &lt;a href="https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA" rel="noopener noreferrer"&gt;ARIA&lt;/a&gt; attributes to say that they're presentation only.&lt;/p&gt;

&lt;p&gt;Why are icons presentation only you say? Well an icon itself doesn't have any meaning to a screenreader. It's something that's meant to convey [extra] meaning to a sighted user in a shorthand way without having to consume precious screen real estate with text. So it's useful to have on a button for example, but that button should already have ARIA attributes to describe its meaning.&lt;/p&gt;

&lt;h3&gt;
  
  
  SVG Icon as a Background Image
&lt;/h3&gt;

&lt;p&gt;For things like buttons that we're adding SVG icons to, we'll start by setting up a reusable mixin that takes as an argument the path to the icon, and the size of the icon (assuming square dimensions). This mixin will cover all of the properties we'll typically apply to every icon:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sass"&gt;&lt;code&gt;&lt;span class="k"&gt;@mixin&lt;/span&gt; &lt;span class="nf"&gt;createIconStyle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$path-to-svg&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$icon-size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="err"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background-image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sx"&gt;url('~/../src/&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nv"&gt;$path-to-svg&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sx"&gt;')&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;background-repeat&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;no-repeat&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;background-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;$icon-size&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;background-position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;$icon-size&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;$icon-size&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
&lt;span class="err"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then we can setup a specific css class for an icon using that mixin:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sass"&gt;&lt;code&gt;&lt;span class="nc"&gt;.download-icon&lt;/span&gt; &lt;span class="err"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;@include&lt;/span&gt; &lt;span class="nd"&gt;createIconStyle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/assets/baseline-get_app-24px.svg'&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="m"&gt;2rem&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="err"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Note: My example is using &lt;a href="https://webpack.js.org/" rel="noopener noreferrer"&gt;webpack&lt;/a&gt; which is why it has the weird '~/..' prepended to the icon path.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Now we're free to add this style class to a download button:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"btn btn-primary download-icon"&lt;/span&gt; &lt;span class="na"&gt;aria-label=&lt;/span&gt;&lt;span class="s"&gt;"Download the thing"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fv2movjcnubhug1cmjwy4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fv2movjcnubhug1cmjwy4.png" alt="Download Button White"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The download button with an icon. Note: I changed my icon to white for this example because the default black on blue looked bad.&lt;/em&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Data URLs for Icons
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs" rel="noopener noreferrer"&gt;Data URLs&lt;/a&gt; are a nice way to bundle your CSS and icons together into the same HTTP request, though there are some good and some vague reasons why &lt;a href="https://github.com/angular/angular-cli/issues/13355#issuecomment-451089973" rel="noopener noreferrer"&gt;this is bad&lt;/a&gt;. If handled properly, this can still be a good thing. Especially if you're not using HTTP/2 yet. The main concern is to avoid duplicate data URLs otherwise it can easily bloat your CSS assets fast.&lt;/p&gt;

&lt;p&gt;With Sass we can avoid this duplication pretty easily with inheritance. Let's say we want to make a &lt;code&gt;.download-icon-large&lt;/code&gt; which is twice as big as the original, then we just inherit the original and override its properties. It's possible to make a mixin of this if it's a common enough occurrence:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sass"&gt;&lt;code&gt;&lt;span class="k"&gt;@mixin&lt;/span&gt; &lt;span class="nf"&gt;overrideIconSize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$extends-class&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$icon-size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="err"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;@extend&lt;/span&gt; &lt;span class="nc"&gt;.&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nv"&gt;$extends-class&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;background-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;$icon-size&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;$icon-size&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;$icon-size&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
&lt;span class="err"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.download-icon-large&lt;/span&gt; &lt;span class="err"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;@include&lt;/span&gt; &lt;span class="nd"&gt;overrideIconSize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;download-icon&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="m"&gt;3rem&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
&lt;span class="err"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will result in CSS which only includes that data URL once:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.download-icon&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;.download-icon-large&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background-image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sx"&gt;url('data:image/svg+xml;utf8,&amp;lt;svg ...&amp;gt; ... &amp;lt;/svg&amp;gt;')&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  SVG Icon as a Side Image
&lt;/h3&gt;

&lt;p&gt;A popular use for icons is to put them beside some text for a link or a button to give a bit more of a hint to what will happen when it's clicked. Some examples might include a down arrow beside a menu item to hint that it will expand into a submenu. Or a download icon beside the link to a file to hint that it will download instead of open.&lt;/p&gt;

&lt;p&gt;These are situations where it's common for developers to add extra markup, usually in the form of an &lt;code&gt;&amp;lt;i&amp;gt;&lt;/code&gt; tag or worse an &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; tag. Yuck! Let's keep it all in the CSS please! Remember icons are presentation only, no need for extra markup in our content. That's also &lt;a href="https://www.w3schools.com/tags/tag_i.asp" rel="noopener noreferrer"&gt;not the purpose of an &lt;code&gt;&amp;lt;i&amp;gt;&lt;/code&gt; tag&lt;/a&gt; and &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; tags download images regardless of visibility which is inefficient, and looks bad with its display of the browser's broken image icon if the download fails.&lt;/p&gt;

&lt;p&gt;So without adding extra markup, the solution is to use a pseudo element. Either &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/::before" rel="noopener noreferrer"&gt;before&lt;/a&gt; or &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/::after" rel="noopener noreferrer"&gt;after&lt;/a&gt; will do. Which you choose depends on the position of the icon (before for icon on the left, after for icon on the right) but it doesn't matter since position can be controlled in other ways.&lt;/p&gt;

&lt;p&gt;For this example, let's say we have a download link with the download icon to the right of it like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Furkgllm4ou26bijnpkkv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Furkgllm4ou26bijnpkkv.png" alt="Download link"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Expanding on the &lt;code&gt;.download-icon&lt;/code&gt; example above, let's create a Sass mixin to create a pseudo element that inherits from the &lt;code&gt;.download-icon&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sass"&gt;&lt;code&gt;&lt;span class="k"&gt;@mixin&lt;/span&gt; &lt;span class="nf"&gt;existingIconAfter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$extends-class&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$icon-size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="err"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;inline-flex&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;align-items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nd"&gt;:after&lt;/span&gt; &lt;span class="err"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;@extend&lt;/span&gt; &lt;span class="nc"&gt;.&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nv"&gt;$extends-class&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;vertical-align&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;middle&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;inline-block&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;background-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;$icon-size&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;$icon-size&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;$icon-size&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
  &lt;span class="err"&gt;}&lt;/span&gt;
&lt;span class="err"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We set the &lt;code&gt;display&lt;/code&gt; property to &lt;code&gt;inline-flex&lt;/code&gt; and &lt;code&gt;align-items&lt;/code&gt; to &lt;code&gt;center&lt;/code&gt; so that we can take advantage of &lt;a href="https://developer.mozilla.org/en-US/docs/Glossary/Flexbox" rel="noopener noreferrer"&gt;Flexbox&lt;/a&gt; to vertically align the icon next to the text&lt;/p&gt;

&lt;p&gt;Next we create a new class using this mixin and the existing &lt;code&gt;.download-icon&lt;/code&gt; class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sass"&gt;&lt;code&gt;&lt;span class="nc"&gt;.download-icon-after&lt;/span&gt; &lt;span class="err"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;@include&lt;/span&gt; &lt;span class="nd"&gt;existingIconAfter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;download-icon&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="mi"&gt;.5rem&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
&lt;span class="err"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then we can add setup our download link:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"..."&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"download-icon-after"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;span&amp;gt;&lt;/span&gt;Download&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What's with this &lt;code&gt;&amp;lt;span&amp;gt;&lt;/code&gt; tag wrapping the 'Download' text? In this example it's for positioning. On some browsers Flexbox won't recognize text as an item to apply positioning and alignment to. Doesn't this go against "don't add extra markup for icons" approach we're trying to achieve? Maybe, but regardless we'd still want a way to apply styling rules to the separate elements that ultimately make up this link anyways so we can use that &lt;code&gt;span&lt;/code&gt; to target the text portion of the link. For example, where horizontal space is limited, we may want to apply rules such that our text will wrap without wrapping the icon too. &lt;/p&gt;

&lt;p&gt;If we had a separate theme in our webapp we'd be able to have different looks for this link such as flanking the text with icons on both sides, or removing the icons completely without having to change the structure of the html.&lt;/p&gt;

&lt;h3&gt;
  
  
  Coloring External SVG Icons using CSS Mask
&lt;/h3&gt;

&lt;p&gt;Applying color to External SVG Icons is unfortunately its weak point depending on your needs. If you don't need to support Internet Explorer, then there's a great solution &lt;a href="https://codepen.io/noahblon/post/coloring-svgs-in-css-background-images" rel="noopener noreferrer"&gt;here&lt;/a&gt; using CSS &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/mask" rel="noopener noreferrer"&gt;mask&lt;/a&gt; which we'll follow. If this doesn't work for you, then one option might be to just create different color variants of the icon SVG files by opening them up and changing their &lt;code&gt;fill&lt;/code&gt; color and saving them, or some automated variant of this.&lt;/p&gt;

&lt;p&gt;Back to the CSS mask option. The gist of it is that a mask decides the shape of an element, and the only visible parts of that element are inside that mask shape. So if we set an element's background color to blue, and apply a star shaped mask to it then we end up with a blue star. Unfortunately, because the rest of the element outside the star became invisible we lose the elements important details. This means we can't use an SVG mask as a direct replacement for a background image on say a button because the intended outline, background, hover, etc, whatever falls outside the mask shape is invisible. That's no good.&lt;/p&gt;

&lt;p&gt;We can solve this using pseudo elements. If we want a star shape icon on a button, we can apply the mask to a pseudo element within the button instead of on the button itself.&lt;/p&gt;

&lt;p&gt;Similar to how we have the &lt;code&gt;createIconStyle&lt;/code&gt; mixin above, we can start out with a &lt;code&gt;createMaskStyle&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sass"&gt;&lt;code&gt;&lt;span class="k"&gt;@mixin&lt;/span&gt; &lt;span class="nf"&gt;createMaskStyle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$path-to-svg&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$icon-size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="err"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;mask&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sx"&gt;url('~/../src/&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nv"&gt;$path-to-svg&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sx"&gt;')&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
  &lt;span class="na"&gt;mask-repeat&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;no-repeat&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
  &lt;span class="na"&gt;mask-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;$icon-size&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
  &lt;span class="na"&gt;mask-position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;$icon-size&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;$icon-size&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
&lt;span class="err"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And create a css class leveraging that mixin&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sass"&gt;&lt;code&gt;&lt;span class="nc"&gt;.download-mask&lt;/span&gt; &lt;span class="err"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;@include&lt;/span&gt; &lt;span class="nd"&gt;createMaskStyle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/assets/baseline-get_app-24px.svg'&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="m"&gt;2rem&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="err"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But, like we talked about, we usually don't want to apply a style like this directly to an element. We want to apply it to a pseudo element. Similar to our &lt;code&gt;createIconAfter&lt;/code&gt; mixin we will create another mixin to leverage this style class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sass"&gt;&lt;code&gt;&lt;span class="k"&gt;@mixin&lt;/span&gt; &lt;span class="nf"&gt;existingMaskAfter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$extends-class&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$icon-size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="err"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;inline-flex&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;align-items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nd"&gt;:after&lt;/span&gt; &lt;span class="err"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;@extend&lt;/span&gt; &lt;span class="nc"&gt;.&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nv"&gt;$extends-class&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;vertical-align&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;middle&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;inline-block&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
    &lt;span class="na"&gt;mask-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;$icon-size&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;$icon-size&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;$icon-size&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
  &lt;span class="err"&gt;}&lt;/span&gt;
&lt;span class="err"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then we can leverage that mixin to create style classes we can apply to any element we want to have apply this pseudo element to (and maybe readjust its size if we want):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sass"&gt;&lt;code&gt;&lt;span class="nc"&gt;.download-mask-after&lt;/span&gt; &lt;span class="err"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;@include&lt;/span&gt; &lt;span class="nd"&gt;existingMaskAfter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;download-mask&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="mi"&gt;.5rem&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
&lt;span class="err"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you can add an icon to a button like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"download-mask-after"&lt;/span&gt; &lt;span class="na"&gt;aria-label=&lt;/span&gt;&lt;span class="s"&gt;"Download Button"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But wait... I don't see an icon! That's because the pseudo element has nothing to show, so it looks invisible. If we give the pseudo element some color, the icon appears:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sass"&gt;&lt;code&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="nc"&gt;.download-mask-after&lt;/span&gt;&lt;span class="nd"&gt;:after&lt;/span&gt; &lt;span class="err"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;red&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
&lt;span class="err"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we're coloring SVG icons using CSS!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fl6uv9ht3dhc4gupj9vl5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fl6uv9ht3dhc4gupj9vl5.png" alt="Red Download Button"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Hurray we have a red download icon to make our eyes sore!&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  SVG Sprites
&lt;/h3&gt;

&lt;p&gt;In the Data URLs section above we talked about using data URLs as a way to minimize http requests, but that it has drawbacks such as needing to find ways to reduce data URL duplication. If you want to use the CSS Mask technique mentioned above to color your icons, and you have an autoprefixer, then chances are you're going get duplicate data URLs anyways since for every &lt;code&gt;mask&lt;/code&gt; property with a data URL there will be at least a &lt;code&gt;-webkit-mask&lt;/code&gt; property with the same data URL. An alternative that also helps minimize http requests is to use SVG Sprites.&lt;/p&gt;

&lt;p&gt;SVG Sprites is just delivering all of your SVG icons in a single SVG file. Unlike traditional sprite files where you need to know the position of the image inside the file and do some magic to align background positioning over that image, with SVG sprites you can simply reference the image through the URL by its identifier.&lt;/p&gt;

&lt;p&gt;For example, I've created a 'sprites.svg' file and inside of it I have, among other icons, my 'getapp' (download) icon which is identified by the name 'getapp' and referenced as a URL fragment like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sass"&gt;&lt;code&gt;&lt;span class="nc"&gt;.download-mask-sprite&lt;/span&gt; &lt;span class="err"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;@include&lt;/span&gt; &lt;span class="nd"&gt;createMaskStyle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/assets/sprites.svg#getapp'&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="m"&gt;2rem&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="err"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There is some trickery around getting the sprites.svg structured to work for this purpose. Here's an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;svg&lt;/span&gt; &lt;span class="na"&gt;version=&lt;/span&gt;&lt;span class="s"&gt;"1.1"&lt;/span&gt;
  &lt;span class="na"&gt;xmlns=&lt;/span&gt;&lt;span class="s"&gt;"http://www.w3.org/2000/svg"&lt;/span&gt;
  &lt;span class="na"&gt;xmlns:xlink=&lt;/span&gt;&lt;span class="s"&gt;"http://www.w3.org/1999/xlink"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"sprites"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;defs&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;style&amp;gt;&lt;/span&gt;
    svg.sprites {
      display: inline;
    }
    svg {
      display: none;
    }
    svg:target {
      display: inline;
    }
    &lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/defs&amp;gt;&lt;/span&gt;

  &lt;span class="c"&gt;&amp;lt;!-- Here I've pasted in the original SVG, and wrapped it's path elements in a g tag--&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;svg&lt;/span&gt; &lt;span class="na"&gt;viewBox=&lt;/span&gt;&lt;span class="s"&gt;"0 0 24 24"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"getapp"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;g&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;path&lt;/span&gt; &lt;span class="na"&gt;d=&lt;/span&gt;&lt;span class="s"&gt;"..."&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/path&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;path&lt;/span&gt; &lt;span class="na"&gt;d=&lt;/span&gt;&lt;span class="s"&gt;"..."&lt;/span&gt; &lt;span class="na"&gt;fill=&lt;/span&gt;&lt;span class="s"&gt;"none"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/path&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/g&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/svg&amp;gt;&lt;/span&gt;

  &lt;span class="c"&gt;&amp;lt;!-- Another SVG in the same file referenced via #setttings URL fragment --&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;svg&lt;/span&gt; &lt;span class="na"&gt;viewBox=&lt;/span&gt;&lt;span class="s"&gt;"0 0 20 20"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"settings"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;g&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;path&lt;/span&gt; &lt;span class="na"&gt;fill=&lt;/span&gt;&lt;span class="s"&gt;"none"&lt;/span&gt; &lt;span class="na"&gt;d=&lt;/span&gt;&lt;span class="s"&gt;"..."&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/path&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;path&lt;/span&gt; &lt;span class="na"&gt;d=&lt;/span&gt;&lt;span class="s"&gt;"..."&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/path&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/g&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/svg&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/svg&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can read more about it in &lt;a href="https://css-tricks.com/svg-fragment-identifiers-work/" rel="noopener noreferrer"&gt;this article&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;From here it's up to you to decide how you want to incorporate this into your project. Do you build the sprite file yourself? Alternatively you can use a command line tool, like &lt;a href="https://www.npmjs.com/package/svg-sprite" rel="noopener noreferrer"&gt;svg-sprite&lt;/a&gt;, to build the sprite file for you. Another option is you can try to make it a part of your project's build.&lt;/p&gt;

&lt;h4&gt;
  
  
  Coloring SVG Sprites
&lt;/h4&gt;

&lt;p&gt;If the CSS Mask option is not for you then you can change the fill color of the icons inside the sprite file. We can gain an efficiency here where each icon (or rather its paths) is only defined once and then can be referenced multiple times taking advantage of SVG's &lt;code&gt;&amp;lt;use&amp;gt;&lt;/code&gt; tag and applying different fill colors.  &lt;/p&gt;

&lt;p&gt;First all of the icon definitions (the &lt;code&gt;&amp;lt;g&amp;gt;&lt;/code&gt; tags) can be moved into the &lt;code&gt;&amp;lt;defs&amp;gt;&lt;/code&gt; section of the SVG and given identifiers. Then all of the different color variants of each icon are created using &lt;code&gt;&amp;lt;svg&amp;gt;&lt;/code&gt; tags with &lt;code&gt;&amp;lt;use&amp;gt;&lt;/code&gt; tags inside them and something to distinguish their color in a CSS selector like a CSS class name. Finally we can use CSS inside the &lt;code&gt;&amp;lt;defs&amp;gt;&lt;/code&gt; section to set the fill color on the icons matching that selector. &lt;/p&gt;

&lt;p&gt;Here's an iteration on the previous example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;svg&lt;/span&gt; &lt;span class="na"&gt;version=&lt;/span&gt;&lt;span class="s"&gt;"1.1"&lt;/span&gt;
  &lt;span class="na"&gt;xmlns=&lt;/span&gt;&lt;span class="s"&gt;"http://www.w3.org/2000/svg"&lt;/span&gt;
  &lt;span class="na"&gt;xmlns:xlink=&lt;/span&gt;&lt;span class="s"&gt;"http://www.w3.org/1999/xlink"&lt;/span&gt;
  &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"sprites"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;defs&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;style&amp;gt;&lt;/span&gt;
    svg.sprites {
      display: inline;
    }
    svg {
      display: none;
    }
    svg:target {
      display: inline;
    }

    &lt;span class="c"&gt;&amp;lt;!-- Make SVGs with 'blue' classnames blue --&amp;gt;&lt;/span&gt;
    svg.blue use {
      fill: blue;
    }

    &lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;

    &lt;span class="c"&gt;&amp;lt;!-- Icon definitions --&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;g&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"getapp_icon"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;path&lt;/span&gt; &lt;span class="na"&gt;d=&lt;/span&gt;&lt;span class="s"&gt;"..."&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/path&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;path&lt;/span&gt; &lt;span class="na"&gt;d=&lt;/span&gt;&lt;span class="s"&gt;"..."&lt;/span&gt; &lt;span class="na"&gt;fill=&lt;/span&gt;&lt;span class="s"&gt;"none"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/path&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/g&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;g&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"settings_icon"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;path&lt;/span&gt; &lt;span class="na"&gt;fill=&lt;/span&gt;&lt;span class="s"&gt;"none"&lt;/span&gt; &lt;span class="na"&gt;d=&lt;/span&gt;&lt;span class="s"&gt;"..."&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/path&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;path&lt;/span&gt; &lt;span class="na"&gt;d=&lt;/span&gt;&lt;span class="s"&gt;"..."&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/path&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/g&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;/defs&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;svg&lt;/span&gt; &lt;span class="na"&gt;viewBox=&lt;/span&gt;&lt;span class="s"&gt;"0 0 24 24"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"getapp"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;use&lt;/span&gt; &lt;span class="na"&gt;xlink:href=&lt;/span&gt;&lt;span class="s"&gt;"#getapp_icon"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/svg&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;svg&lt;/span&gt; &lt;span class="na"&gt;viewBox=&lt;/span&gt;&lt;span class="s"&gt;"0 0 20 20"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"settings"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;use&lt;/span&gt; &lt;span class="na"&gt;xlink:href=&lt;/span&gt;&lt;span class="s"&gt;"#settings_icon"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/svg&amp;gt;&lt;/span&gt;

  &lt;span class="c"&gt;&amp;lt;!-- Referenced via #getapp_blue. Will display a blue version of the #getapp icon --&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;svg&lt;/span&gt; &lt;span class="na"&gt;viewBox=&lt;/span&gt;&lt;span class="s"&gt;"0 0 24 24"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"blue"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"getapp_blue"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;use&lt;/span&gt; &lt;span class="na"&gt;xlink:href=&lt;/span&gt;&lt;span class="s"&gt;"#getapp_icon"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/svg&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;svg&lt;/span&gt; &lt;span class="na"&gt;viewBox=&lt;/span&gt;&lt;span class="s"&gt;"0 0 20 20"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"blue"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"settings_blue"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;use&lt;/span&gt; &lt;span class="na"&gt;xlink:href=&lt;/span&gt;&lt;span class="s"&gt;"#settings_icon"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/svg&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;/svg&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Wrap up
&lt;/h3&gt;

&lt;p&gt;There are a number of approaches to handling iconography in your web application, and even more reasons to choose different approaches (fonts or SVGs, inlined or external, data URLs or sprites, etc.). It all depends on your tastes, technical limitations and capabilities. The aim of this post is to guide you down a specific path of using SVG icons and outline reasons you might want to do it that way.&lt;/p&gt;

</description>
      <category>css</category>
      <category>sass</category>
      <category>svg</category>
      <category>icons</category>
    </item>
    <item>
      <title>Tips for working with CSS Grids</title>
      <dc:creator>Paul Mooney</dc:creator>
      <pubDate>Mon, 11 Mar 2019 03:03:43 +0000</pubDate>
      <link>https://dev.to/pauldmooney/tips-for-working-with-css-grids-5ab3</link>
      <guid>https://dev.to/pauldmooney/tips-for-working-with-css-grids-5ab3</guid>
      <description>&lt;h2&gt;
  
  
  Overview of Grids
&lt;/h2&gt;

&lt;p&gt;A common practice in creating responsive layouts in web sites is to use what's referred to as a grid. Grids are tools used by designers and developers alike to help layout a page, align elements within the page and help define how much of the page those elements should take up for different screen sizes.&lt;/p&gt;

&lt;p&gt;A very common implementation is the 12 column grid which is generally used to help line up elements horizontally along "columns". They are made up of three elements:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A grid container, which defines the left and right side boundaries (or the width) of your site.&lt;/li&gt;
&lt;li&gt;A row, which lays out grid cells, and is responsible for wrapping the cells when they don't fit.&lt;/li&gt;
&lt;li&gt;A cell, which takes up space in a row. Most of the time cells take up some multiple of one 12th of the width of the grid which is how we get the 12 column effect. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fekk6oq4rgdap0cx7dtm8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fekk6oq4rgdap0cx7dtm8.png" alt="Grid container overlay figure"&gt;&lt;/a&gt;&lt;em&gt;The magenta outline shows the borders of the grid container. The translucent bars represent the columns that cells will align to in the grid.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This is seen in some form or another in popular CSS frameworks such as &lt;a href="https://getbootstrap.com/docs/4.0/layout/grid/" rel="noopener noreferrer"&gt;Bootstrap&lt;/a&gt; or &lt;a href="https://foundation.zurb.com/sites/docs/xy-grid.html" rel="noopener noreferrer"&gt;Foundation XY Grid&lt;/a&gt;, but can also be implemented in the native CSS-grid if your browser supports it. All of these systems are capable of creating other kinds of layouts beyond the 12 column grid, but it is still a popular choice to use them for this purpose.&lt;/p&gt;

&lt;p&gt;Working with a grid system like this isn't all scotches and skittles, there are some things that are unintuitive or require some workarounds. Here are some tips for working with grids.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This post is going to focus on implementing tips in Bootstrap with &lt;a href="https://sass-lang.com/" rel="noopener noreferrer"&gt;Sass&lt;/a&gt;, though these concepts can apply to other systems.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Breakout Backgrounds
&lt;/h2&gt;

&lt;p&gt;A common web site design feature is the have backgrounds that stretch out all the way to the left and right edges of the viewport while the main elements of your site remain constrained inside the grid. We'll refer to this as a  "breakout background".&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F5a04jhgm2stzm43e25r0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F5a04jhgm2stzm43e25r0.png" alt="Breakout background design"&gt;&lt;/a&gt;&lt;em&gt;In this design, several sections of the page have backgrounds that break out beyond the grid container (outlined in magenta)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The naive solution to this is to create a full width div, give it a background styling, then put a grid container inside that div. Rinse and repeat this process for every section that requires a breakout background. This could work, but it's ugly. The structure of the html has been compromised to support styling, and it probably puts some tough limitations on how you code your site.&lt;/p&gt;

&lt;p&gt;Our goal is that we want to have a single grid container for the whole site and still have these breakout backgrounds. We can achieve this purely in CSS without messing with our html structure.&lt;/p&gt;

&lt;p&gt;The trick is that we use a pseudo element on the element we want to have a breakout background for and then assign some background styling to it. Then we stretch that pseudo element out to the edges of the viewport.&lt;/p&gt;

&lt;p&gt;First we start with a class that has a pseudo element positioned behind the content of its parent on the Z-axis:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sass"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Apply this class to elements which should have breakout backgrounds&lt;/span&gt;
&lt;span class="nc"&gt;.breakout-background&lt;/span&gt; &lt;span class="err"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;relative&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;z-index&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="n"&gt;establish&lt;/span&gt; &lt;span class="n"&gt;stacking&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="n"&gt;for&lt;/span&gt; &lt;span class="n"&gt;breakout&lt;/span&gt;

  &lt;span class="c1"&gt;// Breakout background pseudo element&lt;/span&gt;
  &lt;span class="k"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nd"&gt;:before&lt;/span&gt; &lt;span class="err"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;absolute&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100vw&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="n"&gt;Takes&lt;/span&gt; &lt;span class="n"&gt;up&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;viewport&lt;/span&gt; &lt;span class="n"&gt;width&lt;/span&gt;
    &lt;span class="nl"&gt;z-index&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;-1&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="n"&gt;pseudo&lt;/span&gt; &lt;span class="n"&gt;element&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt; &lt;span class="nb"&gt;behind&lt;/span&gt; &lt;span class="n"&gt;its&lt;/span&gt; &lt;span class="n"&gt;parent&lt;/span&gt;
    &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;blue&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
  &lt;span class="err"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The tricky part is positioning the element horizontally so that its &lt;code&gt;left&lt;/code&gt; value is the far left side of the viewport. We want it to be moved left half the viewport width, but then since it's starting it's move from the left side of the grid container we have to take the size of the grid container into consideration. So after it's moved left half the viewport width it needs to move right again by half the grid container width:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sass"&gt;&lt;code&gt;    &lt;span class="nl"&gt;left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;calc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;-100vw&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nv"&gt;$container-max-width&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we have to figure out what the grid container width is. In Bootstrap there's a different width for every breakpoint, so we'll need our left positioning to be different for every breakpoint as well. We can accomplish this by looping over the available breakpoints Bootstrap provides:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sass"&gt;&lt;code&gt;&lt;span class="k"&gt;@each&lt;/span&gt; &lt;span class="nv"&gt;$breakpoint&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$container-max-width&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="nv"&gt;$container-max-widths&lt;/span&gt; &lt;span class="err"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;@include&lt;/span&gt; &lt;span class="nd"&gt;media-breakpoint-up&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$breakpoint&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$grid-breakpoints&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="err"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;calc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;-100vw&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nv"&gt;$container-max-width&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="err"&gt;}&lt;/span&gt;
&lt;span class="err"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our final output looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sass"&gt;&lt;code&gt;&lt;span class="k"&gt;@import&lt;/span&gt; &lt;span class="s"&gt;'~bootstrap/scss/variables';&lt;/span&gt;
&lt;span class="k"&gt;@import&lt;/span&gt; &lt;span class="s"&gt;'~bootstrap/scss/bootstrap-grid';&lt;/span&gt;
&lt;span class="k"&gt;@import&lt;/span&gt; &lt;span class="s"&gt;'~bootstrap/scss/mixins';&lt;/span&gt;

&lt;span class="c1"&gt;// Apply this class to elements which should have breakout backgrounds&lt;/span&gt;
&lt;span class="nc"&gt;.breakout-background&lt;/span&gt; &lt;span class="err"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;relative&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="n"&gt;establish&lt;/span&gt; &lt;span class="n"&gt;breakout&lt;/span&gt; &lt;span class="n"&gt;positioning&lt;/span&gt; &lt;span class="n"&gt;ancestor&lt;/span&gt;
  &lt;span class="nl"&gt;z-index&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="n"&gt;establish&lt;/span&gt; &lt;span class="n"&gt;stacking&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="n"&gt;for&lt;/span&gt; &lt;span class="n"&gt;breakout&lt;/span&gt;

  &lt;span class="c1"&gt;// Breakout background pseudo element&lt;/span&gt;
  &lt;span class="k"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nd"&gt;:before&lt;/span&gt; &lt;span class="err"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;absolute&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100vw&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="n"&gt;Takes&lt;/span&gt; &lt;span class="n"&gt;up&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;viewport&lt;/span&gt; &lt;span class="n"&gt;width&lt;/span&gt;
    &lt;span class="nl"&gt;z-index&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;-1&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="n"&gt;pseudo&lt;/span&gt; &lt;span class="n"&gt;element&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt; &lt;span class="nb"&gt;behind&lt;/span&gt; &lt;span class="n"&gt;its&lt;/span&gt; &lt;span class="n"&gt;parent&lt;/span&gt;
    &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;blue&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Different left position for each breakpoint&lt;/span&gt;
    &lt;span class="k"&gt;@each&lt;/span&gt; &lt;span class="nv"&gt;$breakpoint&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$container-max-width&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="nv"&gt;$container-max-widths&lt;/span&gt; &lt;span class="err"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;@include&lt;/span&gt; &lt;span class="nd"&gt;media-breakpoint-up&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$breakpoint&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$grid-breakpoints&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="err"&gt;{&lt;/span&gt;

        &lt;span class="c1"&gt;// Position -50% of viewport width, then readjust right again half the grid container width&lt;/span&gt;
        &lt;span class="nl"&gt;left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;calc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;-100vw&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nv"&gt;$container-max-width&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="err"&gt;}&lt;/span&gt;
    &lt;span class="err"&gt;}&lt;/span&gt;
  &lt;span class="err"&gt;}&lt;/span&gt;
&lt;span class="err"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can add this class wherever we need a background breakout:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"row breakout-background different-background"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"col"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Here's a breakout background&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And even override the background style either using Sass inheritance or by adding a simple modifier class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sass"&gt;&lt;code&gt;&lt;span class="nc"&gt;.different-background&lt;/span&gt;&lt;span class="nd"&gt;:before&lt;/span&gt; &lt;span class="err"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background-image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sx"&gt;url('./myImage.png')&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;background-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;cover&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
&lt;span class="err"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Nested Grids vs. Designers
&lt;/h2&gt;

&lt;p&gt;When a designer creates mockups to a 12 column grid, not only is it used for the general layout, but it's also common to align more specific elements to these grid columns. This can be good because it cuts down on the extra work of creating custom widths for various elements, those elements can squeeze down in size in a consistent way with the rest of the grid, and maybe it's more visually appealing as well.&lt;/p&gt;

&lt;p&gt;The problem is that those pesky designers don't have a clue how you need to structure your page (nor should they!). You're building your page in boxes that nest into each other, not line by line, which leads us to the problem of nested grids.&lt;/p&gt;

&lt;p&gt;Nested grids are exactly what they sound like. A grid nested down somewhere deeper into the cell of an existing grid.&lt;/p&gt;

&lt;p&gt;Let's take this example to illustrate the problem.&lt;/p&gt;

&lt;p&gt;A designer creates a mockup like this:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fetihqfr0go3fnz2eslh3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fetihqfr0go3fnz2eslh3.png" alt="Designer mockup of form"&gt;&lt;/a&gt;&lt;em&gt;This designer is a charity case. His name is Paul.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This is the same design with the designer's grid overlay to show the alignment of components to grid columns and separation of main area and sidebar.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fh8m9lyiwbun5b0o85sr8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fh8m9lyiwbun5b0o85sr8.png" alt="Designer mockup of form with grid overlay"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The problem is that when it's time to implement the design, we might end up with something that looks like this: &lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F8ak2iqz90plr5xqxlcv3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F8ak2iqz90plr5xqxlcv3.png" alt="Bad implementation of form with grid overlay"&gt;&lt;/a&gt;&lt;em&gt;Grid overlay added to illustrate misalignment of elements&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;What has happened is we've started a nested the grid in the main area, which itself is confined to a cell within a grid. Now there's no longer a set of CSS classes to help us size our elements properly. A column in a grid takes up 1/12th (or %8.3) of its parent. In this case we have a parent (the main area) that's already 10/12ths (or 83%) of the overall grid. Nesting a grid inside of that gives us columns that are about 6.9% of the overall grid container. They will never align to the designer's grid (ie, the overall grid).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fox175i9x50x3ciunnhgj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fox175i9x50x3ciunnhgj.png" alt="Bad grid overlay"&gt;&lt;/a&gt;&lt;em&gt;The red bars show the columns in the nested grid. Where they overlap with the overall grid columns it's grey. Since they don't line up there's not a perfect overlap.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;We need a new set of Bootstrap's &lt;code&gt;col-*&lt;/code&gt; classes here for a nested grid that is 10/12ths of the overall grid. Luckily Bootstrap has some Sass mixins to make this easy. It comes with a mixin called &lt;code&gt;make-grid-columns&lt;/code&gt; which takes as arguments the number of columns wide you want your grid to be, and then a map of "infix" names to breakpoints. Using the existing &lt;code&gt;$grid-breakpoints&lt;/code&gt; map from Bootstrap's variables we can create our ten column grid like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sass"&gt;&lt;code&gt;&lt;span class="k"&gt;@import&lt;/span&gt; &lt;span class="s"&gt;'~bootstrap/scss/bootstrap-grid';&lt;/span&gt;
&lt;span class="k"&gt;@import&lt;/span&gt; &lt;span class="s"&gt;'~bootstrap/scss/mixins';&lt;/span&gt;
&lt;span class="k"&gt;@import&lt;/span&gt; &lt;span class="s"&gt;'~bootstrap/scss/variables';&lt;/span&gt;

&lt;span class="nv"&gt;$breakpointsCustomColumns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="na"&gt;xs10&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;map-get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$grid-breakpoints&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;xs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;sm10&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;map-get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$grid-breakpoints&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sm&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;md10&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;map-get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$grid-breakpoints&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;md&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;lg10&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;map-get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$grid-breakpoints&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;xl10&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;map-get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$grid-breakpoints&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;xl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
&lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;@include&lt;/span&gt; &lt;span class="nd"&gt;make-grid-columns&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$columns&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$breakpoints&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;$breakpointsCustomColumns&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will produce classes &lt;code&gt;col-xs10-1&lt;/code&gt;, &lt;code&gt;col-xs10-2&lt;/code&gt;, up to &lt;code&gt;col-xs10-10&lt;/code&gt; for the &lt;code&gt;xs&lt;/code&gt; breakpoint. Likewise for &lt;code&gt;col-sm10-1&lt;/code&gt;, &lt;code&gt;col-md10-1&lt;/code&gt;, &lt;code&gt;col-md10-2&lt;/code&gt;, etc. for the remaining breakpoints. The keys from the breakpoints map were used as the "infix" value between the word &lt;code&gt;col-&lt;/code&gt; and the column number at the end: &lt;code&gt;col-${infix}-${columnwidth}&lt;/code&gt;. We can now create a grid at 1/10th widths. Using these new classes in a nested grid gives us perfect alignment with the overall grid.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fc1upuyhvgtp1pnvq8hyl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fc1upuyhvgtp1pnvq8hyl.png" alt="Good grid overlay"&gt;&lt;/a&gt;&lt;em&gt;Notice how the two grids column's perfectly overlap blue and red creating the grey bars.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Now we can take this one step further and create other col-* classes for other nested grid widths:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sass"&gt;&lt;code&gt;&lt;span class="k"&gt;@mixin&lt;/span&gt; &lt;span class="nf"&gt;make-custom-grid-columns&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$columns&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="err"&gt;{&lt;/span&gt;
  &lt;span class="nv"&gt;$breakpointsCustomColumns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="na"&gt;xs&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nv"&gt;$columns&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;map-get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$grid-breakpoints&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;xs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;sm&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nv"&gt;$columns&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;map-get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$grid-breakpoints&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sm&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;md&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nv"&gt;$columns&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;map-get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$grid-breakpoints&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;md&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;lg&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nv"&gt;$columns&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;map-get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$grid-breakpoints&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;xl&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nv"&gt;$columns&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;map-get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$grid-breakpoints&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;xl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
  &lt;span class="o"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;@include&lt;/span&gt; &lt;span class="nd"&gt;make-grid-columns&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$columns&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;$columns&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$breakpoints&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;$breakpointsCustomColumns&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="err"&gt;}&lt;/span&gt;

&lt;span class="nv"&gt;$customColumnCounts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="m"&gt;7&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="m"&gt;8&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="m"&gt;9&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="m"&gt;11&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;@each&lt;/span&gt; &lt;span class="nv"&gt;$customColumn&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="nv"&gt;$customColumnCounts&lt;/span&gt; &lt;span class="err"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;@include&lt;/span&gt; &lt;span class="nd"&gt;make-custom-grid-columns&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$customColumn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
&lt;span class="err"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it! We now have other sized grid columns we can use to align sub grid columns to the overall grid the designer is aligning elements to. &lt;code&gt;col-sm5-1&lt;/code&gt;, &lt;code&gt;col-sm5-2&lt;/code&gt;, &lt;code&gt;col-md7-5&lt;/code&gt;, etc. You may have noticed we skipped creating columns for grids that are 2, 3, 4, and 6 wide. That's because they all divide evenly into 12, so the default 12 column grid can be used on those situations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Grids are for Parents. Not for Kids
&lt;/h2&gt;

&lt;p&gt;This tip is more of a general guideline or a best practice for working with any kind of grid system and a component based application framework such as Angular, React, Vue, or Web Components. The tip is this: A component should not know about the grid it is being laid out into.&lt;/p&gt;

&lt;p&gt;The reasons why are reusability, and just generally knowing where to draw the line between your parent component and your child component.&lt;/p&gt;

&lt;p&gt;So what am I talking about? Well using the 12 column grid as an example, a parent component is probably setting a layout using rows. That much makes sense. But it should also fall on the responsibility of the parent to layout the cells. The child component should not have any styling on it that says "I take up 3 columns of ... something".&lt;/p&gt;

&lt;p&gt;Here's a brief example of the bad practice:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;
&lt;span class="c"&gt;&amp;lt;!-- the Parent component --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;I'm the parent!&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"row"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;app-mychild&amp;gt;&amp;lt;/app-mychild&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- The child component 'app-mychild'. Assumes it needs to take up 6 columns --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"col-md-6 child-style"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;h2&amp;gt;&lt;/span&gt;I'm the child!&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
  &lt;span class="c"&gt;&amp;lt;!--  some other important child component stuff here--&amp;gt;&lt;/span&gt;
  ...
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's an example of the good practice:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;
&lt;span class="c"&gt;&amp;lt;!-- the Parent component. Decides how much space to give the child. --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;I'm the parent!&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"row"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"col-md-6"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;app-mychild&amp;gt;&amp;lt;/app-mychild&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- The child component 'app-mychild' --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"child-style"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;h2&amp;gt;&lt;/span&gt;I'm the child!&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
  &lt;span class="c"&gt;&amp;lt;!--  some other important child component stuff here--&amp;gt;&lt;/span&gt;
  ...
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the good example above, the child is not coupled to any specific grid layout. It can be reused in other places where it may need to take up more space, or less space. From a layout perspective, the child component's responsibility is to either take up 100% of the space given to it by it's parent, or only as much as it needs to display its content depending on scenario.&lt;/p&gt;

&lt;p&gt;There may be some exceptions to the rule, like if the child component only ever exists with that parent component and is never reused anywhere else, but often its probably still a good idea to follow this rule just so we know where to draw the line on layout responsibility.&lt;/p&gt;

&lt;p&gt;This rule doesn't mean a child component can't have a grid layout of it's own, to layout its own children. That's perfectly fine as long as the grid existing entirely within the child component doesn't bleed into its own children.&lt;/p&gt;

</description>
      <category>css</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
