<?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: Dan Greene</title>
    <description>The latest articles on DEV Community by Dan Greene (@dgreene1).</description>
    <link>https://dev.to/dgreene1</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%2F406143%2Fe27d9504-56d5-4e60-afd6-1fe89d644b13.jpeg</url>
      <title>DEV Community: Dan Greene</title>
      <link>https://dev.to/dgreene1</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/dgreene1"/>
    <language>en</language>
    <item>
      <title>When to avoid squishing dates together (a lesson in UI &lt;--&gt; backend team collaboration)</title>
      <dc:creator>Dan Greene</dc:creator>
      <pubDate>Wed, 11 Oct 2023 17:48:04 +0000</pubDate>
      <link>https://dev.to/dgreene1/when-to-avoid-squishing-dates-together-a-lesson-in-ui-backend-team-collaboration-2cjl</link>
      <guid>https://dev.to/dgreene1/when-to-avoid-squishing-dates-together-a-lesson-in-ui-backend-team-collaboration-2cjl</guid>
      <description>&lt;p&gt;One of the most dangerous places for bugs to occur is the API contract between the UI and the server. No, I'm not talking about breaking contracts. I'm talking about when the backend team tells the UI devs what the contract is going to be instead of making it a conversation.&lt;/p&gt;

&lt;p&gt;In this article we'll discuss a scenario where, if I was in either devs shoes, I would recommend not using a &lt;code&gt;Date&lt;/code&gt; at all.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Are We Trying To Build?
&lt;/h2&gt;

&lt;p&gt;Our customer wants a UI where they can schedule jobs to run daily.&lt;/p&gt;

&lt;p&gt;They want to make sure that it always runs at the set time even if Daylight Savings is or is not observed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Some Context First
&lt;/h2&gt;

&lt;p&gt;At my current company (and at any company I would consult with), I encourage the UI developers to avoid Date in general and instead to use Temporal or js-joda (&lt;a href="https://dev.to/dgreene1/making-your-datepicker-easier-to-work-with-21n4"&gt;click here to learn why&lt;/a&gt;). And if you don't know what Temporal or js-joda is, you can read my primer &lt;a href="https://dev.to/dgreene1/temporaljoda-concept-breakdown-51gk"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Our company wrote an in-house set of widgets that wrap react-date-picker and expose js-joda types (&lt;a href="https://dev.to/dgreene1/making-your-datepicker-easier-to-work-with-21n4"&gt;and you can too if you follow my guide&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;When we did that, we made the decision to split react-datepicker into two separate components (date and time) for accessibility reasons. Namely, if you were navigating a date and time picker with a keyboard and a screen reader, you would be able to press "enter" on the selected day and you would automatically get the preselected time without knowing that you needed to make a time election. We solved that by making our pickers independent.&lt;/p&gt;

&lt;p&gt;Before:&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzo57zfe2ms7xa8aemlb8.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzo57zfe2ms7xa8aemlb8.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After (time get's moved to it's own component and removed from the day picker):&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fezp4r2yv5xc4bmwx8wkr.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fezp4r2yv5xc4bmwx8wkr.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Let's Build It The Wrong Way First
&lt;/h1&gt;

&lt;p&gt;Imagine a conversation like this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Backend Dev: "You UI devs only have a Date object right?"&lt;br&gt;
UI Dev: "Well no, we have Temporal coming up and Js-Joda..."&lt;br&gt;
Backend Dev: "Cool cool. We already built the service and it only takes a Date. I thought you'd like that."&lt;br&gt;
UI Dev: "I wish we had a conversation first."&lt;br&gt;
Backend Dev: "Sorry! Here's the schema"&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;BadSchema&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;jobName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;runTime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="cm"&gt;/**
     * So that we can determine if runTime was in Daylight Savings Time
     */&lt;/span&gt;
    &lt;span class="nl"&gt;usersZone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&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;So the backend dev, who thought he was doing the UI dev a favor &lt;em&gt;(he wasn't),&lt;/em&gt; goes to write the scheduler code.&lt;/p&gt;

&lt;p&gt;By sticking to just a Date in the contract, the dev accidentally introduces a bug. Note: The backend dev is using Joda here since most recent Java versions have that js-joda API natively. But for consistency, this is Typescript.&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;jobStartDateTimeFromUI&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2016-03-18T16:00:00Z&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Convert that value that came across the wire into a useful type&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;jobStartDateTime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ZonedDateTime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ofInstant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Instant&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;jobStartDateTimeFromUI&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;ZoneId&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;usersZone&lt;/span&gt;&lt;span class="p"&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;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;jobStartDateTime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;DateTimeFormatter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;RFC_1123_DATE_TIME&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// Fri, 18 Mar 2016 17:00:00 Europe/Berlin&lt;/span&gt;

&lt;span class="c1"&gt;// adding a date unit of 2 weeks, crossing a daylight saving transition&lt;/span&gt;
&lt;span class="nx"&gt;jobStartDateTime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;plusWeeks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 2016-04-01T17:00+02:00[Europe/Berlin] (still 17:00)&lt;/span&gt;

&lt;span class="c1"&gt;// adding a time unit of 2 weeks (2 * 7 * 24)&lt;/span&gt;
&lt;span class="nx"&gt;jobStartDateTime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;plusHours&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 2016-04-01T18:00+02:00[Europe/Berlin] (now 18:00)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What you'll notice there is that the server code broke the user's requirement that the scheduled job be run at the same time every day. But in this case it's going to be run at 6pm instead of 5pm. They wanted it sent at 5pm.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Can We Prevent This?
&lt;/h2&gt;

&lt;p&gt;In cases like this, you want the API contract to communicate as much as possible (within reason) so that the server can make informed decisions.&lt;/p&gt;

&lt;p&gt;That means that instead of sending &lt;code&gt;new Date().toISOString()&lt;/code&gt; the UI should be sending the first day of the scheduled job as a &lt;code&gt;LocalDate&lt;/code&gt;, then the time they want it to run daily as a &lt;code&gt;LocalTime&lt;/code&gt;, and then finally the &lt;code&gt;ZoneId&lt;/code&gt; of the user so we can determine if Daylight Savings Time is even observed.&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="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;FormItems&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;jobName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="cm"&gt;/**
     * Most servers will accept YYYY-MM-DD format since it's ISO-8601 and JSON Schema has support for format: date and format: date-time (https://swagger.io/docs/specification/data-models/data-types/#format)
     */&lt;/span&gt;
    &lt;span class="nl"&gt;firstJobDay&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;LocalDate&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="cm"&gt;/**
     * preserve this so that we can make sure that the scheduled job happens at the same time if we are or are not observing Daylight Savings
     */&lt;/span&gt;
    &lt;span class="nl"&gt;jobDailyTime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;LocalTime&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;ScheduledJobPostBodyDeserialized&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;FormItems&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cm"&gt;/**
     * So that we can determine if firstJobDate was in Daylight Savings Time so we can ensure that jobDailyTime will remain the right time for any date in the future
     */&lt;/span&gt;
    &lt;span class="nl"&gt;usersZone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&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;
  
  
  Full Solution
&lt;/h2&gt;

&lt;p&gt;Below is code for how the UI and the server would schedule this job. Note: I don't do any React code here since I'm trying to focus on just controller logic and the conversation between the UI and the backend over "the wire" (i.e. HTTP).&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;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;LocalDate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;LocalTime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;LocalDateTime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ZonedDateTime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ZoneId&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@js-joda/core&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;FormItems&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;jobName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="cm"&gt;/**
     * Most servers will accept YYYY-MM-DD format since it's ISO-8601 and JSON Schema has support for format: date and format: date-time (https://swagger.io/docs/specification/data-models/data-types/#format)
     */&lt;/span&gt;
    &lt;span class="nl"&gt;firstJobDay&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;LocalDate&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="cm"&gt;/**
     * preserve this so that we can make sure that the scheduled job happens at the same time if we are or are not observing Daylight Savings
     */&lt;/span&gt;
    &lt;span class="nl"&gt;jobDailyTime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;LocalTime&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;ScheduledJobPostBodyDeserialized&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;FormItems&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cm"&gt;/**
     * So that we can determine if firstJobDate was in Daylight Savings Time so we can ensure that jobDailyTime will remain the right time for any date in the future
     */&lt;/span&gt;
    &lt;span class="nl"&gt;usersZone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// START OF MOCK UI CODE&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;// This would be React code normally, but for brevity this is what I have&lt;/span&gt;
    &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getFormItems&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;FormItems&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Pretend implementation&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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;prepareForServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;formItems&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FormItems&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;ScheduledJobPostBodyDeserialized&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;firstJobDay&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;jobDailyTime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;jobName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;formItems&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="c1"&gt;// We have to pass the server the real offset instead of the value of ZoneId.SYSTEM since no one knows what that is besides js-joda&lt;/span&gt;
        &lt;span class="c1"&gt;// Read more at: https://js-joda.github.io/js-joda/manual/ZonedDateTime.html#the--code-system--code--zone-id&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;usersZone&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Intl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;DateTimeFormat&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;resolvedOptions&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;timeZone&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="na"&gt;serverBody&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ScheduledJobPostBodyDeserialized&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;jobName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nx"&gt;firstJobDay&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nx"&gt;jobDailyTime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nx"&gt;usersZone&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;serverBody&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;sendToServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;jobPostBody&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ScheduledJobPostBodyDeserialized&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;void&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;// psuedo-code&lt;/span&gt;

        &lt;span class="c1"&gt;// fetch({&lt;/span&gt;
        &lt;span class="c1"&gt;//     method: "POST", // *GET, POST, PUT, DELETE, etc.&lt;/span&gt;
        &lt;span class="c1"&gt;//     url: "fake url",&lt;/span&gt;
        &lt;span class="c1"&gt;//     body: JSON.stringify(jobPostBody),&lt;/span&gt;
        &lt;span class="c1"&gt;// })&lt;/span&gt;

        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Not Implemented&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;sendToServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;prepareForServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;getFormItems&lt;/span&gt;&lt;span class="p"&gt;()));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// END OF MOCK UI CODE&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="na"&gt;mockDB&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ScheduledJobPostBodyDeserialized&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;jobs&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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;postNewScheduledJob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ScheduledJobPostBodyDeserialized&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
        &lt;span class="nx"&gt;mockDB&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;jobs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;runJob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;job&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ScheduledJobPostBodyDeserialized&lt;/span&gt;&lt;span class="p"&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;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Let's pretend that we ran job named "&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;job&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;jobName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&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;// We'd never do it this way, but it communicates how you'd work out Daylight Savings Time&lt;/span&gt;
    &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;tryToRunJobs&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
        &lt;span class="c1"&gt;// Create the time once so that it's fixed for all of the jobs&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;now&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ZonedDateTime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="nx"&gt;mockDB&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;jobs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;aJob&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;firstJobDay&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;jobDailyTime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;usersZone&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aJob&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

            &lt;span class="c1"&gt;// You avoid the Daylight Savings Time problem by creating an instant with the component parseStrict&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;thisJobsTimeButToday&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ZonedDateTime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="nx"&gt;LocalDateTime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;firstJobDay&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;jobDailyTime&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                &lt;span class="nx"&gt;ZoneId&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;usersZone&lt;/span&gt;&lt;span class="p"&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;thisJobsTimeButToday&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;equals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;now&lt;/span&gt;&lt;span class="p"&gt;)){&lt;/span&gt;
                &lt;span class="nf"&gt;runJob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;aJob&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;// Again, we'd never do it this way, but it communicates the idea&lt;/span&gt;
    &lt;span class="nf"&gt;setInterval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tryToRunJobs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt; &lt;span class="cm"&gt;/* ms */&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;// START OF MOCK SERVER CODE&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And here's &lt;a href="https://www.typescriptlang.org/play?#code/JYWwDg9gTgLgBAbwDIQMYEMA2ARdMCmANHChpgCqhElpa4GUjUBaEAdvgCb36Mvv4AkpzgBfOADMoEEHABEAAQBWAZwC0SiJ3QB6VNHxyA3ACgTwNgSgT0qfHABi0EIIIgViE3G9xNAIwA5dCYALjgVGCgLAHNTHzgdACpEr3jEuABZCAjw-CgANzyPAHdgTEw4WzsweABNetq1DIy1bGxJZzxwizs4YBgAcg9BAGUAeTUADgA2AAYARkq2EQApcYC4EdQAC3wQdDht9A8VAFcwSFgOqGv9mDDtAiWRCU77uEf8NRgqOAAKbYwGBgFQhHQ6FTFdDRaJ5AB0wAgOk4aBUELA+FQwAkwAwP3YyLw6DUIC0+EwaMexJgAE8MWiAMSvKB3ACUqR8iR0HMkwCgERWED8uBpYVIdDw+DiPiSKXicHSYCg+BUeUKcBg22AJwgGqO8GK9gwbDg+wA1vYzsq9V1NZadlxTpguL4hYd0Bd8GwPLbduFgvYfkw+hI4IbKtboBH7GwIPAhaqCjE4CLMMBooDNuh8jEVDyFdz4v5cGUaXwxbQKFRTKIzBYrDZeltdpwnVxBX4AArZGAAIS0NOwKrywCwwAAXi78AAPAjLDxOFmuPYeBA82X59IjXWarrh40ffBWEAWezY3n8mAdnhh459E2p9OZkbZ3NwPjhXX79Amr1WwP6q6wroKWH6lOUcDKvsFh6vYUQZvAQb2MySw0h8kr3rBkinDApzKpuhY+KciYqKwHBhBEURsLEJi1iY4KbOQACCABK5BwGMDiZGMADCADScAAKqCHAPFjNgACiJh-KyAC8AB8a7rjo75aiUEBOiIfj2Cx+C2PA+icDGnTlDSxB+Dh1xwH4yo5rSeran0JSASJRyFDyEinGwqD4iasIwIuLhuCoMlhIFy7uJ48o+PmPiatIxRwBwiUSVA0hQH8cidsqc4iKAYDOkwlh4IibByKy0reHR8Sed5vlwEq+BgOgyqLiMap5H8zJBSuYXOBFKismEzaOs6nAdt2ET9pwg7DlEY6TiIa7Rd4+jevACAXgKQoisQxYgZgZZUHtQpBEw4iybcA2mLF3gMQA6vYbmBrqzUqB4dq5AUeRYcqWBwBAEgSKq8AWBEekiIDWH5Fgpz2FDZFCJwcIjLUIzkBJGTdN5xkAxwcBmrGxTOb6XSOdpKjAEZHiqBoWjoLdCQqbp6AiKS1p4GEgLAqC4K05o2hwtE-TbKcfgIki-P0zo+xsKcWA6Ij3CSnwcKAiAmAMnaahqIZXwqDS4MgDres6+OAhqFTjNrTkxFFIjcCXYIliYHCPB8IFeAyXCyoqBAmCFJwYw1KVIWsnCSGIzdK1wDb8CJoUUDTaKmwOq2Y0TT2ydDomo5potjtRTHPj+GdRCMzVfLbcBZkVyXO0HUdTCEHX3h2-yiOM9VK05XhJoJ3kyeVWIZg1V5PmlbkyzkBA7XfRl-iTX2A7DWnbbjUKS-Z3NecTlwQ1wNlMjavgAA8+QQFT8lF9FDEgnDKK62So8rQxEhHjsfzLa-KnxEwmpaDCFlMY6M5DEAYokAA4hJcgxBOwgNgYfQSiDJJIBgRJYgH84SMwYvEPCmAgE2AtHAfBYCcG-x8H4FecA1hjACHCSiMRsQ0j+IvLOA5WQtxjgxUQ7JGbxQgIlZKcBUrpUygEOMcBBDgEKl6AgnByrD27t4VU09Z4dQyo1ZqrVoBz0Tn8fy4VgoyVZBVWiZgGISQCO0Ti3F+JCREmJSS0lWSO2vkpeIcdTRoDNNgXsYRv7RX8KCVOLZ16ZymgOHOI4FpcAANoAF0lGF0CfKYJYREk8mUdhOqk9IARACPgYoI107tiFH8KhM1V5hIzpvdhM1onzXzvvVJf8fF+LhMEuEYBiLbAqRwpRL9vC1QnuwSCXkOysKFNU0aZSuz1NmrnWJnBWStJ8Dbf2+A4SYAgNEP4AADJAR4hgNRyl6EQu4DRwR-EBJKAYRByAACQIH8J006AZRByH2WY+I2SHr4AGCIDgicPi6n6A5Eo6AzLWUsuC-QIAQBeVxJKDw2xBFwBpBpQFYZoBmgBpZR8CEsw5moh4PgHlx71UiGWCALEJkJhkmsu6KkeJ-SeJ9JCeNeh+xtKDQYHgcTThdChLAFQoafWCdbdgOQiaFyVu7KgcIiYyWjitUkqBfG9jeX4FQcJmQSVsH09AHY3E32Ll4zaOJLzXihSdYCoFjokJIg7C6lQOyquLkzOAtQNKVAvlTLChLnyvlJe+X4SohSFWsmhVAbLkw3LBjAH8BoRZYXhZADglgGotVVCMSIuIYCt1jtKxCakOwqD4L2HCM9tBoUuvKlWirAZ-CLfEcUOBG1MDhM2q11ddpARLIdPgnDW0+ERsIbtEg-jt1IgIdknrvA-IXUW7EfxNTanLZW6t9MaRwnwAAR3lhSP4RNTFMuLlAelfg-jGqFEuz1tYY68KyUMr1TFoggTYMQQ02LgU-RRH0UtjkoTQosny4tCKkV4hVFhKmekeQg2dlYGGmA11QBpXStg5biDzFmHhhI6RIpcjMbWBi6NWLsVsRkXiAkRgSRYgANXo6JcSEkgA" rel="noopener noreferrer"&gt;a link to this in TypeScript playground&lt;/a&gt; to help you noodle around with it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lessons
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Send component parts of the Date if you want to ensure you handle Daylight Savings Time&lt;/li&gt;
&lt;li&gt;UI developers should make sure that contract discussions happen long before each team starts working&lt;/li&gt;
&lt;li&gt;Ideally, combine your teams into fully-autonomous team that has both backend and UI devs on it. But that's a topic for another day!&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>java</category>
      <category>coding</category>
    </item>
    <item>
      <title>Why input masking is not accessible</title>
      <dc:creator>Dan Greene</dc:creator>
      <pubDate>Wed, 16 Aug 2023 18:56:57 +0000</pubDate>
      <link>https://dev.to/dgreene1/why-masking-is-not-accessible-i3c</link>
      <guid>https://dev.to/dgreene1/why-masking-is-not-accessible-i3c</guid>
      <description>&lt;p&gt;My team was asked recently to implement an accessible number input widget that utilizes masking.&lt;/p&gt;

&lt;p&gt;As a UI Architect, I'm always willing to investigate if a feature such as masking can be accomplished in an accessible, performant, and high quality manner. Frankly, masking sounds cool and people have argued that it is necessary (&lt;a href="https://uxmovement.com/forms/why-formatted-data-fields-always-need-input-masks/"&gt;source&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;However, after trying a few of the libraries related to accessible inputs, such as react-aria's &lt;a href="https://react-spectrum.adobe.com/react-aria/useNumberField.html"&gt;useNumberField&lt;/a&gt; and &lt;a href="https://nosir.github.io/cleave.js/"&gt;cleave.js&lt;/a&gt;, I have found that it is inherently unable to speak the truth to screen-readers and therefore it is not accessible.&lt;/p&gt;

&lt;h2&gt;
  
  
  But How Is It Not Accessible?
&lt;/h2&gt;

&lt;p&gt;Let’s assume we have a masking scenario where the asterisk character that is illegal:&lt;/p&gt;

&lt;p&gt;Let's see how that works with pasting a value and then how that works with typing a value,&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;If you paste “123*456” then the masking library will be unable to process any of it and will likely remove the entire thing which will leave the user with a blank input. React-aria does this, and you can see it by &lt;a href="https://react-spectrum.adobe.com/react-aria/useNumberField.html#decimals"&gt;trying out their decimal example&lt;/a&gt;. There’s an even scarier example for which I used &lt;a href="https://github.com/adobe/react-spectrum/issues/4967"&gt;when I raised this as a bug to the react-aria team&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If you type “123*456” then the masking library will let you type “123” then it will eat the asterisk (meaning the screen reader will say “asterisk” but the input will not show the asterisk) and then it will let you type “456” so what you’ll be left with is “123456” even though the screen reader will have told the user that “123*456” was entered. This is the scenario why I believe that masking is inherently not an accessible solution.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  So what now?
&lt;/h2&gt;

&lt;p&gt;Due to this, I now recommend that designers and developers opt to not use masking but to instead use error validation. This allows the user to type or paste what they want, but they will be told that what they typed was not allowed. In summary, it’s better to not “lie” to the screen reader, but instead to give good feedback to the user. Do they lose the nice formatting? Absolutely, but at least you've insulated yourself from ADA lawsuits and, more importantly, you've made your website more inclusive.&lt;/p&gt;




&lt;p&gt;I'd love to hear people's thoughts in the comments. I should note that &lt;a href="https://giovanicamara.com/blog/accessible-input-masking/"&gt;Giovani Camara&lt;/a&gt; has written beautifully about how to do your best to make masking accessible, but I would suspect that the test scenarios I mention above are still reproduceable. So, I would still recommend avoiding it.&lt;/p&gt;

</description>
      <category>a11y</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>react</category>
    </item>
    <item>
      <title>Can you just combine region and language to make a locale?</title>
      <dc:creator>Dan Greene</dc:creator>
      <pubDate>Fri, 11 Aug 2023 16:18:41 +0000</pubDate>
      <link>https://dev.to/dgreene1/can-you-just-combine-region-and-language-to-make-a-locale-1ph6</link>
      <guid>https://dev.to/dgreene1/can-you-just-combine-region-and-language-to-make-a-locale-1ph6</guid>
      <description>&lt;p&gt;As I continue to grow my knowledge in internationalization (i18n), I've had the request from internal and external customers to support something strange.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Hey, can we support the region of "Spain" but avoid taking on translation since translation is costly and requires hiring translators?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As any developer, I thought "sure, I can do this!"&lt;/p&gt;

&lt;p&gt;As it turns out, the more important question is not “can you do it” but &lt;em&gt;“should&lt;/em&gt; you do it?”&lt;/p&gt;

&lt;h2&gt;
  
  
  How I Tried To Solve This
&lt;/h2&gt;

&lt;p&gt;My first attempt to solve this was to look at &lt;code&gt;date-fns&lt;/code&gt; since many UI developers use that for formatting. If &lt;code&gt;date-fns&lt;/code&gt; had the “en-SA” locale or if it allowed me to pass it anyway, then my journey would be over. Sadly, I quickly found out that their locale support was limited to a pretty small set of countries and it is &lt;a href="https://date-fns.org/v2.30.0/docs/I18n-Contribution-Guide"&gt;manually maintained&lt;/a&gt; as opposed to taken from a continuously updated source.&lt;/p&gt;

&lt;p&gt;So then I started to look for a way to get the most up-to-date locale information. This search brought me to the browser supplied &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl"&gt;Intl&lt;/a&gt; API. Seemed pretty great (at first), except Intl doesn’t allow me to get the formats, which hurts my ability to communicate to the user what they are expected to type into a date input widget. &lt;a href="https://github.com/tc39/ecma402/issues/809#issue-1820992725"&gt;I’ve since submitted this as a feature request&lt;/a&gt;, but since support would only come if the ECMAScript spec committee agreed to it and all browsers implement the enhanced spec, it would take a very long time to get a full solution.&lt;/p&gt;

&lt;p&gt;After researching it a lot, I finally came to the source of truth, the &lt;a href="https://cldr.unicode.org/index"&gt;CLDR&lt;/a&gt;. This is actually what the browsers use under the hood with Intl. By using the CLDR data directly, we have an opportunity to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;stay continually up-to-date with locales (since new countries/regions form and existing countries/regions change preferences)&lt;/li&gt;
&lt;li&gt;get access to the formats for each locale’s dates, date/time, etc. so that we can inform screen reader users of the expected string to type (Which again, &lt;code&gt;Intl&lt;/code&gt; &lt;a href="https://github.com/tc39/ecma402/issues/809#issuecomment-1650407203"&gt;does not support at this time&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;get access to the source data so we can finally see if there is data for a locale like “en-SA”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But wait… the CLDR data doesn’t have “en-SA” either! So what should we do?&lt;/p&gt;

&lt;h2&gt;
  
  
  How Does CLDR Handle Missing Locales
&lt;/h2&gt;

&lt;p&gt;So my immediate finding was: there is no "en-SA" locale, there is only "ar-SA." In other words, there is Saudi Arabia that speaks Arabic, but no Saudi Arabia that speaks English. This reflects reality. So why would we try to fake "en-SA"?&lt;/p&gt;

&lt;p&gt;Let's see what would happen anyway. Luckily, the &lt;a href="https://hexdocs.pm/ex_cldr/1.5.1/Cldr.Locale.html#module-locale-name-validity"&gt;CLDR Elixir library &lt;/a&gt;has a very clear (but less-than-ideal answer):&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;When validating a locale name, Cldr will attempt to match the requested locale name to a configured locale. Therefore Cldr.Locale.new/1 may return an {:ok, language_tag} tuple even when the locale returned does not exactly match the requested locale name. For example, the following attempts to create a locale matching the non-existent “English as spoken in Spain” local name. Here Cldr will match to the nearest configured locale, which in this case will be “en”.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That one part is so important that it is worth repeating:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;the non-existent “English as spoken in Spain” locale name&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;It doesn't exist.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;While I like the clarity of their documentation, I am not pleased with the resolving that happens (i.e. "match to the nearest configured locale, which in this case will be 'en'"). So if you were to pass "en-SA", you don't get an error, you get an unexpected mutation.&lt;/p&gt;

&lt;p&gt;So now that we know that the Elixir library for CLDR will silently resolve our fake "English Saudi Arabia" locale to English, let's see how Intl handles it.&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="nx"&gt;Intl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DateTimeFormat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;en-SA&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="c1"&gt;// '8/11/2023'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, it is using English United States standard for date where the month is first. This is NOT how Saudi Arabia prefers dates. They use the &lt;code&gt;d‏/M‏/y&lt;/code&gt; pattern as shown in LocalePlanet, which is nearly identical to CLDR in my experience. So Saudi Arabia expects 11/8/2023 and yet if used our "fake locale" approach, we would be accidentally giving them 8/11/2023.&lt;/p&gt;

&lt;p&gt;This would not be helpful to the user.&lt;/p&gt;

&lt;h2&gt;
  
  
  So What Should We Do?
&lt;/h2&gt;

&lt;p&gt;Often the simplest answer is best for the user, and we have a simple answer:&lt;/p&gt;

&lt;p&gt;Do not give your user to select a locale that does not exist in the CLDR.&lt;/p&gt;

&lt;p&gt;Instead, give them some kind of UX feedback that helps them to find a locale that most closely matches their preferences.&lt;/p&gt;

&lt;p&gt;For example, you could even give them a questionnaire.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Which of these number formats looks most normal to you? Which of these date formats look best to you?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Once they click on the radio buttons for that questionnaire, you can give them a list of commonly used locales that utilize those formats. For example, people who like to see months first, often will select "en-GB" for English as it is spoken in Great Britain. By doing this, you've:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🌈 helped your user to get the end result they want&lt;/li&gt;
&lt;li&gt;🌈 you didn't have to mislead the user by giving them the false sense that their region/country is supported, which prevents a great many bugs&lt;/li&gt;
&lt;li&gt;🌈you didn't have to write a bunch of fancy code just to workaround the problem. This would have led to hacky code.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ultimately, honesty is the best policy.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>frontend</category>
      <category>coding</category>
    </item>
    <item>
      <title>Making your datepicker easier to work with</title>
      <dc:creator>Dan Greene</dc:creator>
      <pubDate>Thu, 28 Apr 2022 16:57:42 +0000</pubDate>
      <link>https://dev.to/dgreene1/making-your-datepicker-easier-to-work-with-21n4</link>
      <guid>https://dev.to/dgreene1/making-your-datepicker-easier-to-work-with-21n4</guid>
      <description>&lt;p&gt;Every programmers worst nightmare is (or should be) the scenario where a date based bug is caught years later. Why? Because that bug has now probably ended up persisting to your production database and now you don't just have to fix the code but you have to fix the data too, which is an extremely costly recovery that might require apologizing to your customers.&lt;/p&gt;

&lt;p&gt;Which is why I was a pretty disappointed to see &lt;a href="https://github.com/Hacker0x01/react-datepicker/issues/1018"&gt;this bug&lt;/a&gt; still open in the &lt;code&gt;react-datepicker&lt;/code&gt; issues list.&lt;/p&gt;

&lt;p&gt;You might ask: &lt;em&gt;why don't they just fix the bug?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Well... it's a logical bug, not a coding error. In fact, this "bug" is probably in every date picker library on the internet... unless it uses the techniques I will be showing below.&lt;/p&gt;

&lt;p&gt;Thankfully, you can prevent logical errors by using &lt;a href="https://www.infoq.com/news/2018/02/practicing-domain-driven-design/"&gt;domain driven design&lt;/a&gt; and types that help enforce the logic (stay with me, don't get scared off by types/OO/DDD concepts).&lt;/p&gt;

&lt;p&gt;So follow along and I'll show a way to continue to use the robust and highly-accessible &lt;code&gt;react-datepicker&lt;/code&gt; library without introducing logical bugs that are hard to track down.&lt;/p&gt;

&lt;h2&gt;
  
  
  How would that help?
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;"say what you mean, mean what you say"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Clear communication is vitally important. Let's imagine that I want to buy my friend a birthday card. So I ask them what their birthday is. Should I expect them to respond with "My birthday is January 1st 1990 at 2:13am" or would you expect them to say "January 1st"?&lt;/p&gt;

&lt;p&gt;Of course you wouldn't expect to get the hours or minutes back because you didn't ask that person for the moment that doctor announced the birth of the baby.&lt;/p&gt;

&lt;p&gt;I like to imagine that the same clarity of communication can and should be applied to programming.&lt;/p&gt;

&lt;p&gt;So a birthday is a &lt;code&gt;LocalDate&lt;/code&gt; and the moment they were born is a &lt;code&gt;ZonedDateTime&lt;/code&gt;. However, if I wanted to know the moment they were born without time zone information, it would be an &lt;code&gt;Instant&lt;/code&gt; (think ISO format in the GMT time zone).&lt;/p&gt;

&lt;p&gt;By specifying what you want in the code, you make it clear what is accepted. Would you want someone to pass a &lt;code&gt;number&lt;/code&gt; when you really wanted a &lt;code&gt;string&lt;/code&gt;? Being clear on your inputs allows you to catch errors at compile time instead of finding the bug in production or having to write expensive unit tests (that might be brittle and therefore leave you with the bug in production anyway). Follow along below to see how you can prevent bugs by simply saying "no, I do not accept a Date, I only accept a LocalDate."&lt;/p&gt;

&lt;h2&gt;
  
  
  Hold up, I have to learn new terms like LocalDate?
&lt;/h2&gt;

&lt;p&gt;Sure, if you want to prevent extremely expensive bugs in your code you do. But don't worry, once you learn them it's hard to not think in the terms of &lt;code&gt;Instant&lt;/code&gt;, &lt;code&gt;LocalDate&lt;/code&gt;, and &lt;code&gt;ZonedDateTime&lt;/code&gt;. And I have a &lt;a href="https://dev.to/dgreene1/temporaljoda-concept-breakdown-51gk"&gt;cheat sheet for you on my prior article&lt;/a&gt; if you want to catch up the terms.&lt;/p&gt;

&lt;p&gt;And frankly, you should &lt;a href="https://dev.to/dgreene1/temporaljoda-concept-breakdown-51gk"&gt;take 2 minutes to learn the terms&lt;/a&gt; since the future is coming when it will be a code smell to use Date or even a library that exposes a Date. That's because the JavaScript community is finalizing the &lt;a href="https://github.com/tc39/proposal-temporal"&gt;Temporal RFC&lt;/a&gt; spec. A polyfill is being worked on already, but soon it will be in all of our browsers so you won't need to use the native JS Date class. And Java has had these concepts since since Java 8.&lt;/p&gt;

&lt;p&gt;While we wait for the &lt;a href="https://github.com/tc39/proposal-temporal"&gt;Temporal RFC&lt;/a&gt; spec to be adopted and implemented in browsers, we can use &lt;a href="https://js-joda.github.io/js-joda/"&gt;JsJoda&lt;/a&gt; which implements the Java 8 / Threeten spec in JavaScript/TypeScript since JsJoda uses all of the same concepts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Okay, show me
&lt;/h2&gt;

&lt;p&gt;So first, a simple example of how this works. Using our "What is your birthday" example, we can mock up this code. Note: I'm using TypeScript because it enforces the concepts at compile time, but the &lt;a href="https://js-joda.github.io/js-joda/"&gt;JsJoda&lt;/a&gt; library itself enforces the concepts at runtime so that we get the best of both.&lt;/p&gt;

&lt;p&gt;This is essentially the conversation above but in code:&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;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;LocalDate&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@js-joda/core&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="c1"&gt;// Notice that the type of the parameter forces us to box the type first&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;saveDateToDatabase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;day&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;LocalDate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;day&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;whatIsYourBirthday&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;inputFromKeyboard&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Okay, it's time to try to see if the string can become a LocalDate&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;day&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;LocalDate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;inputFromKeyboard&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="p"&gt;){&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`It seems like what you entered is not a date.
      Maybe it has too much (like it shouldn't have the year or time).
      See the full 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="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;saveDateToDatabase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;day&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;If you want to play around with JsJoda, I'd recommend opening up the homepage since it has the library loaded into the window object for you to experiment. Note: the doc pages do not.&lt;/p&gt;

&lt;p&gt;I think you'll find that the learning curve is a bit steep; however, the cost savings long term are significant. Think of it as a "slow down so you can speed up" type of situation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Okay, I'm sold... but can we make it easier?
&lt;/h2&gt;

&lt;p&gt;If you like the idea of clarifying when you mean a day vs an moment in a time zone then you still might want to make it easier on yourself to start with those terms. You might not want to have to do that necessary conversion between the JS standard &lt;code&gt;Date&lt;/code&gt; object when you're in a callback of a form element. I can't blame you.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;So what if you never had to use &lt;code&gt;Date&lt;/code&gt; at all?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The following is a CodePen that demonstrates a way to encapsulate the conversion so that you're always dealing with the safer concepts.&lt;/p&gt;

&lt;p&gt;Essentially you wouldn't every directly render &lt;code&gt;react-datepicker&lt;/code&gt;, but instead would render a custom &lt;code&gt;LocalDatePicker&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/dgreene1/embed/ZEvgLpy?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Notice that the above CodePen uses &lt;code&gt;LocalDate&lt;/code&gt; because the date picker does not allow the user to select the time.&lt;/p&gt;

&lt;p&gt;So let's show another example but this time a &lt;code&gt;ZonedDateTimePicker&lt;/code&gt; where we're using &lt;code&gt;react-datepicker&lt;/code&gt;'s &lt;a href="https://reactdatepicker.com/#example-input-time"&gt;showTimeInput&lt;/a&gt; prop. An example where this would be helpful would be an insurance adjuster calling you to ask "what time did your car get into a collision?" You would want to know the &lt;code&gt;ZonedDateTime&lt;/code&gt; that this occurred, so that's the JsJoda type we'll use in the CodePen.&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/dgreene1/embed/LYewONr?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;It's important to call out that I'm not showing an example of an &lt;code&gt;InstantPicker&lt;/code&gt; since the question being asked is "what time did your car get hit in your timezone?" So that's why it would be a &lt;code&gt;ZonedDateTime&lt;/code&gt;. Again, don't get scared by the differences between the concepts-- once you speak the language you'll find it hard to use ambiguous terms like "date."&lt;/p&gt;

&lt;p&gt;I'd encourage you to look at the source code of that CodePen above (under the "Babel" tab); however, to understand how this encapsulation solves the logical bug, consider this portion:&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="o"&gt;!!&lt;/span&gt;&lt;span class="nx"&gt;selected&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;ZoneId&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;selected&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;equals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;zone&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s2"&gt;`The provided date ("&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;selected&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;") was not in the expected ZoneId ("&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;zone&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&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;What that does is ensure that if a value for the selected date comes back in a different time zone / offset, the component will stop in it's tracks. It's not the ideal behavior for your users, but it's a good example of how it can prevent a bug from going un-noticed. This is only possible due to a beautifully expressed domain language that expresses the concept of a Zone. You can't do that with regular ole' &lt;code&gt;Date&lt;/code&gt;!&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;If you chose to adopt this approach, you and your peers will be able to have a clear conversation about if the current feature you're writing needs &lt;code&gt;ZonedDateTime&lt;/code&gt; or &lt;code&gt;LocalDatePicker&lt;/code&gt;. By doing that you'll protect your software and your users for years to come.&lt;/p&gt;

&lt;h2&gt;
  
  
  Attribution
&lt;/h2&gt;

&lt;p&gt;Note: I would probably build this into a library but I'm maxed out on other maintainer work at the moment. So if you choose to turn my codepen into a library, please just share a link to this article! :)&lt;/p&gt;

&lt;p&gt;By the way, you know that hypothetical scenario I mentioned at the top? That actually happened to me. I had to spend nights and weekends for over a month to fix the incorrect data in the database caused by a previous, long-gone developer. Thankfully, a mentor shared with me the concepts I described in this article so I was able to improve the code more easily. So be like that mentor and share this article with friends and coworkers so they can prevent bugs too! :)&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>tutorial</category>
      <category>webdev</category>
      <category>react</category>
    </item>
    <item>
      <title>Temporal/Joda concept breakdown</title>
      <dc:creator>Dan Greene</dc:creator>
      <pubDate>Thu, 28 Apr 2022 16:53:35 +0000</pubDate>
      <link>https://dev.to/dgreene1/temporaljoda-concept-breakdown-51gk</link>
      <guid>https://dev.to/dgreene1/temporaljoda-concept-breakdown-51gk</guid>
      <description>&lt;p&gt;So, you really want to get off of the &lt;a href="https://momentjs.com/docs/#/-project-status/" rel="noopener noreferrer"&gt;deprecated MomentJS&lt;/a&gt; library and you're excited about the new JavaScript proposal for &lt;a href="https://tc39.es/proposal-temporal/docs/" rel="noopener noreferrer"&gt;Temporal &lt;/a&gt;. This article is designed to help you get familiar with the types for Temporal. Given that Temporal has not been accepted by browsers yet, I'm including the &lt;code&gt;https://js-joda.github.io/js-joda/&lt;/code&gt; types since they are 99.99% the same. Sure, the APIs for JsJoda are different, but you can use JsJoda while you wait for Temporal to be adopted.&lt;/p&gt;

&lt;h2&gt;
  
  
  LocalDate / PlainDate
&lt;/h2&gt;

&lt;p&gt;( &lt;a href="https://js-joda.github.io/js-joda/class/packages/core/src/LocalDate.js~LocalDate.html" rel="noopener noreferrer"&gt;JsJoda docs&lt;/a&gt; | &lt;a href="https://tc39.es/proposal-temporal/docs/plaintime.html" rel="noopener noreferrer"&gt;Temporal RFC docs&lt;/a&gt; )&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;represents a calendar date that is not associated with a particular time or time zone, e.g. August 24th, 2006.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Note, Temporal calls this &lt;code&gt;PlainDate&lt;/code&gt; and Joda calls this &lt;code&gt;LocalDate&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Stringified version:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;"2022-04-28"&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Real World examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the day you were born&lt;/li&gt;
&lt;li&gt;the day you first tried icecream&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  ZonedDateTime
&lt;/h2&gt;

&lt;p&gt;( &lt;a href="https://js-joda.github.io/js-joda/class/packages/core/src/ZonedDateTime.js~ZonedDateTime.html" rel="noopener noreferrer"&gt;JsJoda docs&lt;/a&gt; | &lt;a href="https://tc39.es/proposal-temporal/docs/zoneddatetime.html" rel="noopener noreferrer"&gt;Temporal RFC docs&lt;/a&gt; )&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A date-time with a time-zone in the ISO-8601 calendar system, such as &lt;code&gt;2007-12-03T10:15:30+01:00 Europe/Paris&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Stringified version:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;"2022-04-28T11:49:57.999-04:00[America/New_York]"&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Real World Examples of ZonedDateTime:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;"When will we be landing in New York City?"&lt;/em&gt;

&lt;ul&gt;
&lt;li&gt;The person asking this likely wants to know what the time is relative to that offset (note &lt;a href="https://spin.atomicobject.com/2016/07/06/time-zones-offsets/#:~:text=A%20time%20zone%20is%20a,because%20of%20Daylight%20Saving%20Time." rel="noopener noreferrer"&gt;timezones and offsets are different&lt;/a&gt;). Like does the asker want to know what time it is in New York City? Or do they want to know what time it is on their not-automatically-updating wrist watch since that's what is going to help them understand when they need to get sleep?&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;em&gt;"What time did your car get hit by another car?"&lt;/em&gt;

&lt;ul&gt;
&lt;li&gt;the insurance claims adjuster probably wants to know what time of the day it was in that area so they can determine what time of the day in Philadelphia has the most traffic accidents. It would be very hard to determine that if all you had was an &lt;code&gt;Instant&lt;/code&gt; since &lt;code&gt;Instant&lt;/code&gt;s do not have timezone/offset information.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Instant
&lt;/h2&gt;

&lt;p&gt;( &lt;a href="https://js-joda.github.io/js-joda/class/packages/core/src/Instant.js~Instant.html" rel="noopener noreferrer"&gt;JsJoda docs&lt;/a&gt; | &lt;a href="https://tc39.es/proposal-temporal/docs/instant.html" rel="noopener noreferrer"&gt;Temporal RFC docs&lt;/a&gt; )&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A &lt;code&gt;Temporal.Instant&lt;/code&gt; is a single point in time (called "exact time"), with a precision in nanoseconds. No time zone or calendar information is present. To obtain local date/time units like year, month, day, or hour, a &lt;code&gt;Temporal.Instant&lt;/code&gt; must be combined with a &lt;code&gt;Temporal.TimeZone&lt;/code&gt; instance or a time zone string.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Stringified version:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;"2022-04-28T15:49:57.999Z"&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Real World Examples of Instant:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Instant&lt;/code&gt; (in my experience) is pretty much exclusively used for sending a datetime string over HTTP. Some times you just don't need to store the offset, so that's why &lt;code&gt;Instant&lt;/code&gt; is helpful.

&lt;ul&gt;
&lt;li&gt;If you do need to store the offset, ZonedDateTime since that will keep the offset.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  LocalTime / PlainTime
&lt;/h2&gt;

&lt;p&gt;( &lt;a href="https://js-joda.github.io/js-joda/class/packages/core/src/LocalTime.js~LocalTime.html" rel="noopener noreferrer"&gt;JsJoda docs&lt;/a&gt; | &lt;a href="https://tc39.es/proposal-temporal/docs/plaintime.html" rel="noopener noreferrer"&gt;Temporal RFC docs&lt;/a&gt; )&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;represents a wall-clock time that is not associated with a particular date or time zone, e.g. 11:49 AM&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Stringified version:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;"11:49:57.999"&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Real World Example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What you would answer with if a friend (who lives in the same town) asks "What time do you want to meet at the restaurant?"&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Other types
&lt;/h2&gt;

&lt;p&gt;Joda and Temporal both have many other types that you might need to help with conversions between the above concepts. &lt;/p&gt;

&lt;p&gt;For instance, &lt;code&gt;LocalDateTime&lt;/code&gt; (or Temporal's &lt;code&gt;PlainDateTime&lt;/code&gt;) is a type I can't imagine every using in the real world. Why would I want to know the date and time but without the timezone? Because with &lt;code&gt;LocalDateTime&lt;/code&gt; you don't even know if the time is relative to Zulu/GMT or if the moment occurred is in New York City.&lt;/p&gt;

&lt;p&gt;Personally, I have found that when you need to know about these more rare types (like &lt;code&gt;LocalDateTime&lt;/code&gt; or &lt;code&gt;OffsetDateTime&lt;/code&gt;), you'll have end up naturally discovering them through StackOverflow or through the library docs when you're looking up how to accomplish something. For now, get familiar with the types above and the rest you'll learn as you go.&lt;/p&gt;

&lt;h2&gt;
  
  
  Visual Depictions
&lt;/h2&gt;

&lt;p&gt;When you see the types here, you realize two things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The people behind the Temporal spec didn't like the word "Local"&lt;/li&gt;
&lt;li&gt;We should have had these terms at the start of Javascript!&lt;/li&gt;
&lt;/ul&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%2Fhsbmjs2z38atq9uypuuk.png" 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%2Fhsbmjs2z38atq9uypuuk.png" alt="Image description" width="800" height="469"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>newbie</category>
      <category>webdev</category>
      <category>tutorial</category>
      <category>javascript</category>
    </item>
    <item>
      <title>How to properly deprecate</title>
      <dc:creator>Dan Greene</dc:creator>
      <pubDate>Thu, 10 Feb 2022 15:42:09 +0000</pubDate>
      <link>https://dev.to/dgreene1/how-to-properly-deprecate-3027</link>
      <guid>https://dev.to/dgreene1/how-to-properly-deprecate-3027</guid>
      <description>&lt;h2&gt;
  
  
  Why would I deprecate?
&lt;/h2&gt;

&lt;p&gt;Sometimes you release a function or widget with your library and you later think "wow I could have done that better." After all, if you're not looking back at your old code and thinking "who wrote this" then you're not improving as a developer.&lt;/p&gt;

&lt;p&gt;But... you can't just delete that function in your next library release. If you did that, your consumers would get 💥 a in their build, or (if they're not using static compilation like TypeScript) the end user will get a bug in production. 🤕&lt;/p&gt;

&lt;p&gt;So you've got to give your library's consumers some advanced notice. &lt;/p&gt;

&lt;h2&gt;
  
  
  How to do it
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Make a plan to only remove the item from your next major version (i.e. &lt;strong&gt;x&lt;/strong&gt;.1.1) This is because users only expect functionality removal in major versions due to how &lt;a href="https://semver.org/" rel="noopener noreferrer"&gt;SemVer&lt;/a&gt; works.&lt;/li&gt;
&lt;li&gt;In your next patch version (i.e. 1.1.&lt;strong&gt;x&lt;/strong&gt;), plan to do the next steps&lt;/li&gt;
&lt;li&gt;Add a &lt;code&gt;@deprecated&lt;/code&gt; JSDoc tag to the JSDoc comment for that function/class/component. See an example of how to do that in the &lt;a href="https://jsdoc.app/tags-deprecated.html" rel="noopener noreferrer"&gt;JSDoc website&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Since the JSDoc tag only helps developers if they have &lt;a href="https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-deprecated.md" rel="noopener noreferrer"&gt;eslint-plugin-import/no-deprecated&lt;/a&gt; and/or &lt;a href="https://github.com/Drawbotics/eslint-plugin-deprecated-props" rel="noopener noreferrer"&gt;eslint-plugin-deprecated-props&lt;/a&gt; installed, you should do the developer a favor by using &lt;code&gt;console.warn&lt;/code&gt; when that function or property is used. I'll provide an example below.&lt;/li&gt;
&lt;li&gt;Here's the most important step: tell your consumers about the upcoming change. That means updating your release notes to explain that the item is going to be removed soon. It also means sharing it with your twitter followers, your Slack channel, dev.to, and (if your library is private) share it in your company's internal communications. Do you have to do this last step? Sure, you could skip it since the steps above will give runtime and compilation time feedback... however, why not give your users advanced heads up?&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Bringing it all together
&lt;/h2&gt;

&lt;p&gt;Here's how you'd deprecate a function:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="cm"&gt;/**
 * this is what you get when you trust a mouse talk show
 * @deprecated please use our new function mult instead
 * @returns {Number}
 */&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;multiply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Here's how you'd deprecate a property in a function. This is only possible in TypeScript (see &lt;a href="https://stackoverflow.com/a/42457901/706768" rel="noopener noreferrer"&gt;source&lt;/a&gt;).&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;ComponentProps&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="cm"&gt;/**
   * Some prop that is going to be removed in the future
   * @deprecated This will be removed soon in favor of colorHex
   */&lt;/span&gt;
  &lt;span class="nl"&gt;colorName&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;colorHex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;someOtherProp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="cm"&gt;/**
 * Note that the @deprecated prop is used in the implementation
 * since it should still work. This does not throw a warning per se.
 */&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;colorHex&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;colorName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;someOtherProp&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;ComponentProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;colorName&lt;/span&gt;&lt;span class="p"&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;warn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;colorName is deprecated. Please use colorHex instead&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;colorClassName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;determineClassName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;colorHex&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;colorName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;colorClassName&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;someOtherProp&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Side note, isn't it cool that VSCode shows that &lt;code&gt;colorName&lt;/code&gt; is deprecated by putting a strikethrough style on it?&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1ds59bivlgka3ef0lmpz.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1ds59bivlgka3ef0lmpz.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Any questions?
&lt;/h2&gt;

&lt;p&gt;Given how quickly the "developer experience" (DX) area is evolving, I'm sure there are improvements on this approach. So please comment below if you have suggestions, questions, or tips. Thanks for reading! :) &lt;/p&gt;

</description>
    </item>
    <item>
      <title>When React Hooks "just clicked" in my head 💡🤩</title>
      <dc:creator>Dan Greene</dc:creator>
      <pubDate>Wed, 19 May 2021 20:43:08 +0000</pubDate>
      <link>https://dev.to/dgreene1/when-react-hooks-just-clicked-in-my-head-4hd3</link>
      <guid>https://dev.to/dgreene1/when-react-hooks-just-clicked-in-my-head-4hd3</guid>
      <description>&lt;p&gt;A lot of people writing React think that when they initialize a variable, it's going to stay that way every time.&lt;/p&gt;

&lt;p&gt;For instance, let's imagine a very simple React component.&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Demo&lt;/span&gt; &lt;span class="o"&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Bob&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;Hello&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;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 might come away thinking that the &lt;code&gt;name&lt;/code&gt; variable will always be the same piece of memory no matter how many times the &lt;code&gt;Demo&lt;/code&gt; component is rendered.&lt;/p&gt;

&lt;p&gt;In reality, React calls that &lt;code&gt;Demo&lt;/code&gt; function every time it renders the parent components that contain the Demo component.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wait a second...
&lt;/h2&gt;

&lt;p&gt;Yes, that means that &lt;code&gt;name&lt;/code&gt; is going to be a new variable every time &lt;code&gt;Demo&lt;/code&gt; is called (which is every time React needs to render it).&lt;/p&gt;

&lt;p&gt;So, it's almost like each time &lt;code&gt;Demo&lt;/code&gt; is rendered, the &lt;code&gt;name&lt;/code&gt; property is born again. That realization is what helped make React Hooks click. Hooks lets you make &lt;code&gt;name&lt;/code&gt; immortal (for the life of the browser tab being open).&lt;/p&gt;

&lt;h2&gt;
  
  
  What if I wanted it to stay the same?
&lt;/h2&gt;

&lt;p&gt;Well, that's what hooks were more or less invented for. Hooks predominantly are about allowing React devs to use simple functions to describe their creational patterns but to allow these functions to express stateful concerns.&lt;/p&gt;

&lt;p&gt;Before hooks, you would have had to use a Class to describe a component that has state.&lt;/p&gt;

&lt;p&gt;But with React Hooks like &lt;code&gt;useRef&lt;/code&gt;, you can say "hey React, would you mind keeping this variable around?"&lt;/p&gt;

&lt;h2&gt;
  
  
  K, but let me see this in action
&lt;/h2&gt;

&lt;p&gt;Sure! Here's a demo that shows starts off showing how the &lt;code&gt;Demo&lt;/code&gt; component is essentially stateless and therefore the &lt;code&gt;name&lt;/code&gt; property can never be the same between renders.&lt;/p&gt;

&lt;p&gt;If you follow along the comments in the code example below, you'll be able to uncomment the correct lines to show how you can inform React of which pieces you want it to keep the same between renders.&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/react-memory-ref-demo?embed=1&amp;amp;&amp;amp;" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

</description>
      <category>react</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Stop dividing microservices the wrong way with this 1 simple tip</title>
      <dc:creator>Dan Greene</dc:creator>
      <pubDate>Wed, 24 Feb 2021 19:59:25 +0000</pubDate>
      <link>https://dev.to/dgreene1/stop-dividing-microservices-the-wrong-way-with-this-1-simple-tip-3ec6</link>
      <guid>https://dev.to/dgreene1/stop-dividing-microservices-the-wrong-way-with-this-1-simple-tip-3ec6</guid>
      <description>&lt;p&gt;If one of the promise of microservices is greater development is greater productivity, then why do most companies find that microservices are slowing them down?&lt;/p&gt;

&lt;p&gt;The answer is often: we divided the monolithic application into microservices &lt;em&gt;at the wrong boundaries.&lt;/em&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Where did we go wrong?
&lt;/h1&gt;

&lt;p&gt;Here's the tip:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Stop using domain decomposition&lt;/em&gt; as your sole criteria.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Hold on a sec, I thought that domain decomposition was the standard way to break up a monolith? Why is it a problem?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;While it's important to understand the business needs, there is a better technique (read below). The reason why domain decomposition alone can be dangerous is because it can cause:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;slow delivery of value as a result of having to deploy and promote multiple microservices whenever a new feature is developed&lt;/li&gt;
&lt;li&gt;late feedback of bugs due to the distributed nature of microservices

&lt;ul&gt;
&lt;li&gt;put nicely, this means:
&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8Q3ostnO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5qdaffqkahjn8ciire8d.png" alt="image"&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Okay, so how should we divide the monolith?
&lt;/h1&gt;

&lt;p&gt;Ask yourself this question:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If I divide the monolith this way, will I have to deploy two or more pull requests every time I want to make a substantial change?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I do not claim to be an expert in this matter. But I'll let my favorite architect speak to this topic in this tweet:&lt;/p&gt;


&lt;blockquote class="ltag__twitter-tweet"&gt;

  &lt;div class="ltag__twitter-tweet__main"&gt;
    &lt;div class="ltag__twitter-tweet__header"&gt;
      &lt;img class="ltag__twitter-tweet__profile-image" src="https://res.cloudinary.com/practicaldev/image/fetch/s--9uIEx04Q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pbs.twimg.com/profile_images/1230388498705895425/GAWp0UhW_normal.jpg" alt="Stefan Tilkov profile image"&gt;
      &lt;div class="ltag__twitter-tweet__full-name"&gt;
        Stefan Tilkov
      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__username"&gt;
        @stilkov
      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__twitter-logo"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ir1kO05j--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-f95605061196010f91e64806688390eb1a4dbc9e913682e043eb8b1e06ca484f.svg" alt="twitter logo"&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__body"&gt;
      “Microservices” are building blocks of an architectural style where deployment boundaries are a first-class software architecture principle
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__date"&gt;
      08:29 AM - 09 Sep 2016
    &lt;/div&gt;


    &lt;div class="ltag__twitter-tweet__actions"&gt;
      &lt;a href="https://twitter.com/intent/tweet?in_reply_to=774162800008585216" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fFnoeFxk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-reply-action-238fe0a37991706a6880ed13941c3efd6b371e4aefe288fe8e0db85250708bc4.svg" alt="Twitter reply action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/retweet?tweet_id=774162800008585216" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--k6dcrOn8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-retweet-action-632c83532a4e7de573c5c08dbb090ee18b348b13e2793175fea914827bc42046.svg" alt="Twitter retweet action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/like?tweet_id=774162800008585216" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SRQc9lOp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-like-action-1ea89f4b87c7d37465b0eb78d51fcb7fe6c03a089805d7ea014ba71365be5171.svg" alt="Twitter like action"&gt;
      &lt;/a&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/blockquote&gt;


&lt;p&gt;Surely, there are many experts who have spoken on this (and I'd encourage you to share your favorite links in the comments). However, I have lived through the monolith -&amp;gt; microservices transformation at a few companies.&lt;/p&gt;

&lt;p&gt;What I've learned is that you have to constantly think about developer productivity when considering how you'll break the monolith into separate microservices.&lt;/p&gt;

&lt;h1&gt;
  
  
  How do I factor developer productivity into my designs?
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Solution 1: Pull request heatmap
&lt;/h2&gt;

&lt;p&gt;One way is to look at your previous pull requests (PRs) in the monolith.&lt;/p&gt;

&lt;p&gt;Ask yourself, "which of the proposed microservives are being touched with this change?"&lt;/p&gt;

&lt;p&gt;That "gut-level check" question can be answered somewhat objectively by looking at commit history. If you already are in a "nano service" landscape where you microservices have been sliced-and-diced to thinly, you can use Github commit graphs to see the frequency of commits to each microservice. You can then turn that into a heatmap to see which microservices&lt;/p&gt;

&lt;p&gt;In the absence of git commit data, you'll need to rely on thinking through the flows of functionality and which parts of the system are touched. This is essentially a simplistic version of &lt;a href="https://www.eventstorming.com/"&gt;event storming&lt;/a&gt; (which is beyond the scope of this article), but we'll look at how an event passes through the system. The emphasis is on functionality as opposed to entities (i.e. like the distinction between typical hierarchical object oriented design versus functional programming). &lt;/p&gt;

&lt;p&gt;For instance, imagine that we have one PR that introduces the functionality to let an end user check if a pet is ready to be picked up from their haircut appointment. In the past, the sequence diagram for this would have looked like one large box since it was just a monolithic application.&lt;/p&gt;

&lt;p&gt;But when you think back to the PR for this schedule lookup feature and you consider the potential microservices that would be necessary, you might see that your "customer" microservice and your "permissions" microservices have to be touched whenever you want to introduce a change.&lt;/p&gt;

&lt;p&gt;Let's further this point by introducing a feature that involves paying for the haircut. The sequence diagrams again that your deployment boundary is essentially the entire system. So why even have separate microservices?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--59D43EoY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ynlxidmiw51u4z2bm8mn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--59D43EoY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ynlxidmiw51u4z2bm8mn.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Solution 2: look through the lens of testing
&lt;/h1&gt;

&lt;p&gt;While reviewing the flow of functionality in your system, you can also think: "How am I going to test this?"&lt;/p&gt;

&lt;p&gt;Deeper questions for that same thought process involve:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;if we separate the customer DB from the permissions DB, is there a way for us to test the end-to-end functionality easily?&lt;/li&gt;
&lt;li&gt;if we don't have end-to-end tests for this functionality, are we willing to invest in the cost of contract testing?

&lt;ul&gt;
&lt;li&gt;are we willing to make sure that every one of our APIs is upholding that contract and updating all consumers? (I mean, you always should, but this might not be achievable for smaller companies)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;if don't plan to use end-to-end tests or contract testing, are you willing to invest in running containerized versions of each dependency in the PR to get fast-feedback?&lt;/li&gt;
&lt;li&gt;if you can't find any way to get fast-feedback (i.e. the PR being rejected by a failing automation test), are you willing to let bugs get into the hands of the end user?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hopefully the answer to the last question is always "no."&lt;/p&gt;

&lt;h1&gt;
  
  
  So what would the ideal breakdown of the monolith look like?
&lt;/h1&gt;

&lt;p&gt;I don't have a simple, general answer. But I feel confident that you will be able to define better boundaries than ever before if you ask yourself those test-driven questions above and continue to place emphasis on flows not entities.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>architecture</category>
      <category>tutorial</category>
      <category>testing</category>
    </item>
    <item>
      <title>Make 2020 brighter --&gt; send an open source maintainer some gratitude</title>
      <dc:creator>Dan Greene</dc:creator>
      <pubDate>Wed, 09 Dec 2020 02:32:36 +0000</pubDate>
      <link>https://dev.to/dgreene1/make-2020-brighter-send-an-open-source-maintainer-some-gratitude-51i0</link>
      <guid>https://dev.to/dgreene1/make-2020-brighter-send-an-open-source-maintainer-some-gratitude-51i0</guid>
      <description>&lt;p&gt;Hi there. We all know that practicing gratitude is one of those Oprah magazine tricks to getting happier.&lt;/p&gt;

&lt;p&gt;So in the spirit of that, why not send some gratitude to an underappreciated library and/or it's maintainers that you feel could use a little boost of happiness. Being a library maintainer can be a tough and thankless job since you rarely get to see the impact of your work. Let's change that. :)&lt;/p&gt;

&lt;p&gt;Which library comes to mind for you?&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>webdev</category>
      <category>typescript</category>
      <category>programming</category>
    </item>
    <item>
      <title>Wow! Cypress can run unit tests! 🥳</title>
      <dc:creator>Dan Greene</dc:creator>
      <pubDate>Thu, 12 Nov 2020 21:09:09 +0000</pubDate>
      <link>https://dev.to/dgreene1/wow-cypress-can-run-unit-tests-15l5</link>
      <guid>https://dev.to/dgreene1/wow-cypress-can-run-unit-tests-15l5</guid>
      <description>&lt;p&gt;Seriously, I am super excited about this. You can write unit tests in Cypress without even having to run a web server. That makes Cypress the ideal tool for testing a JS/TS library that is meant to be used in the browser.&lt;/p&gt;

&lt;p&gt;I know what you're thinking... "I've got {some other testing library}, why would I need to use Cypress?"&lt;/p&gt;

&lt;p&gt;Well, if you haven't tried it yet, Cypress really is rather lovely. &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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fakjgtch13v45i65ek3ke.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fakjgtch13v45i65ek3ke.jpg" alt="But Don't Take My Word For It"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It's not just that Cypress is super user-friendly and easy to learn. No, there's something incredibly important that Cypress does that other tools don't do (by default). Cypress actually runs in a browser.&lt;/p&gt;

&lt;h1&gt;
  
  
  Huh? Why not Jest?
&lt;/h1&gt;

&lt;p&gt;And as great as Jest is (and it has basically won the unit testing war), there's a not very clearly advertised problem with Jest...&lt;/p&gt;

&lt;p&gt;&lt;em&gt;... Jest doesn't run code in a browser.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;It runs in JSDom which is really just a wrapper on NodeJS that mocks out different browser APIs.&lt;/p&gt;

&lt;p&gt;Which means... &lt;strong&gt;a test can pass in Jest but fail in the production code.&lt;/strong&gt; That's not what you want out of your test automation code. You want confidence.&lt;/p&gt;

&lt;h1&gt;
  
  
  But hold up, what about Karma?
&lt;/h1&gt;

&lt;p&gt;Ah, I see you've been doing this for a while. Yes, Karma is/was a thing and in some cases is still quite popular.&lt;/p&gt;

&lt;p&gt;But after spending more than a few hours trying to get Karma set up, I eventually bailed. I guess I've been spoiled by the incredibly easy setup of Jest and Cypress.&lt;/p&gt;

&lt;h1&gt;
  
  
  Alright, I'm sold. What do I need to do?
&lt;/h1&gt;

&lt;p&gt;The Cypress.io team has made some pretty &lt;a href="https://docs.cypress.io/examples/examples/recipes.html#Unit-Testing" rel="noopener noreferrer"&gt;useful examples of Cypress unit testing&lt;/a&gt;, but the one that has me most excited is &lt;a href="https://github.com/cypress-io/cypress-example-recipes/tree/master/examples/unit-testing__application-code" rel="noopener noreferrer"&gt;the example where you don't need to run a web server&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It's really as simple as:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Install Cypress&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;npx cypress open&lt;/code&gt; to get the folder hierarchy set up&lt;/li&gt;
&lt;li&gt;(optional) If you want type safety, add a &lt;code&gt;tsconfig.json&lt;/code&gt; file to the &lt;code&gt;./cypress&lt;/code&gt; folder and rename the spec files from &lt;code&gt;.js&lt;/code&gt; to &lt;code&gt;.ts&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;import your library (or whatever software you're testing) at the top of the test file&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I honestly can't believe that it's as simple as just importing the function you want to test.&lt;/p&gt;

&lt;h2&gt;
  
  
  Caveat
&lt;/h2&gt;

&lt;p&gt;This is a little bit harder for React code, so the steps I provided above are more for testing "vanilla JS/TS" code (i.e. code that isn't specific to any UI framework).&lt;/p&gt;

&lt;p&gt;But again, the Cypress.io team has you covered with &lt;a href="https://docs.cypress.io/examples/examples/recipes.html#Unit-Testing" rel="noopener noreferrer"&gt;example of React unit test examples too.&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Wrap Up
&lt;/h1&gt;

&lt;p&gt;Please give this a try and let me know what you think of it. Ultimately, I feel incredibly grateful to be developing code at a time when we have such wonderfully fast and easy to use tooling at our disposal.&lt;/p&gt;

&lt;p&gt;I'd love to hear what your experiences are, so please share! :)&lt;/p&gt;




&lt;p&gt;P.S. If you're already a pro with Cypress and you're looking to level-up, &lt;a href="https://dev.to/dgreene1/don-t-use-fixtures-in-cypress-and-unit-tests-use-factories-5cnh"&gt;learn how "fixture factories" can improve your test code.&lt;/a&gt;&lt;/p&gt;

</description>
      <category>testing</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Does your UI use "build once" for promoting to environments?</title>
      <dc:creator>Dan Greene</dc:creator>
      <pubDate>Wed, 11 Nov 2020 18:02:28 +0000</pubDate>
      <link>https://dev.to/dgreene1/does-your-ui-use-build-once-for-promoting-to-environments-46op</link>
      <guid>https://dev.to/dgreene1/does-your-ui-use-build-once-for-promoting-to-environments-46op</guid>
      <description>&lt;p&gt;Please comment below with which approach you take:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;build once and then promote multiple times per environment&lt;/li&gt;
&lt;li&gt;build every time you want to move code to an environment&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For those of us who have worked at medium to large companies, it's not uncommon to have multiple environments like:&lt;/p&gt;

&lt;p&gt;Dev -&amp;gt; QA -&amp;gt; Staging -&amp;gt; Production&lt;/p&gt;

&lt;p&gt;What I want to know is, do you follow an approach similar to &lt;a href="https://12factor.net/build-release-run"&gt;the "Twelve Factor App" guide&lt;/a&gt; where you build once and then promote that artifact? Or do you build the UI code each time for every pipeline?&lt;/p&gt;

&lt;p&gt;Here's an image of taken right from &lt;a href="https://12factor.net/build-release-run"&gt;the "Twelve Factor App" guide&lt;/a&gt; that I find helps to demonstrate the goal.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZnJ3hlIH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ts4wguanqbmppauasu8v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZnJ3hlIH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ts4wguanqbmppauasu8v.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But typically that's pretty hard to do with UIs where the configuration is typically in webpack (meaning that the config is "baked" into the UI code at build time).&lt;/p&gt;

&lt;p&gt;So which approach do your teams use?&lt;/p&gt;

</description>
      <category>devops</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>discuss</category>
    </item>
    <item>
      <title>How to eliminate "magic strings" with a fancy Typescript trick </title>
      <dc:creator>Dan Greene</dc:creator>
      <pubDate>Thu, 01 Oct 2020 21:11:23 +0000</pubDate>
      <link>https://dev.to/dgreene1/how-to-eliminate-magic-strings-with-a-fancy-typescript-trick-4gd7</link>
      <guid>https://dev.to/dgreene1/how-to-eliminate-magic-strings-with-a-fancy-typescript-trick-4gd7</guid>
      <description>&lt;p&gt;One of the first things you learn as a professional developer is that magic strings are bad. Why? 🤔 Because typos stink and can really ruin an application in a way that's hard to track down.&lt;/p&gt;

&lt;p&gt;For instance, my team and I were use Storybook to display all of the UI widgets that we have available in our library. And there were a couple of times where we misspelled something only to find that one of the widgets was missing from the final output.&lt;/p&gt;

&lt;h1&gt;
  
  
  The Ideal Goal
&lt;/h1&gt;

&lt;p&gt;Ideally a developer wouldn't have to remember the full path or the agreed upon folder names for storybook. If we rely on memory, they're going to type things wrong.&lt;/p&gt;

&lt;h1&gt;
  
  
  The Solution?
&lt;/h1&gt;

&lt;p&gt;We'll create a function that lets developers "crawl" the paths to create a concatenated path.&lt;/p&gt;

&lt;p&gt;For instance, if we wanted the folder structure in the image below, I'll show you how we would initialize the title.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F9ifr172e47rabu5g6jwu.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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F9ifr172e47rabu5g6jwu.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That would mean inside the &lt;code&gt;dateAndTimePicker.stories.tsx&lt;/code&gt; file, I would initialize the title 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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;makeTitle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Widgets&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;Temporal&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;Date Range Picker&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;finalize&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The coolest part of this approach is that you can't spell "Widgets" wrong... Typescript won't let you. And you also get Intellisense to help you remember what options are allowed.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F9xodxkox4vz4vmwunfdu.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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F9xodxkox4vz4vmwunfdu.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's show how to make this possible.&lt;/p&gt;

&lt;h1&gt;
  
  
  Step 1: Store the hierarchy  in a series of nested objects
&lt;/h1&gt;

&lt;p&gt;This first step is basically the same as how you would eliminate "magic strings" in any project-- by creating constants. But the cool part here is that Typescript naturally lets you store a hierarchy of constants as a series of nested objects. You'll see the power that gives us later when we start to use &lt;code&gt;keyof&lt;/code&gt; to create smarter types.&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;headingsMapObj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;Widgets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;Temporal&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;Date Range Picker&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;Date Range Picker&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="na"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Input&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;Checkbox&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;Single Checkbox&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;Single Checkbox&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;Checkbox Group&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;Checkbox Group&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;An Introduction&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="na"&gt;Welcome&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Welcome&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="na"&gt;Patterns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;Spacing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Spacing&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;Flow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Flow&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Step 2: Turn this into a type
&lt;/h1&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;HeadingsMap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;headingsMapObj&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Step 3: Create the path builder
&lt;/h1&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;makeTitle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;K1&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;HeadingsMap&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;level1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;K1&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="na"&gt;paths&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
    &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;pushKeyIfStringOrThrow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;symbol&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="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
            &lt;span class="nx"&gt;paths&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;TypeError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Unsupported type: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;finalize&lt;/span&gt; &lt;span class="o"&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="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;paths&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt; / &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;pushKeyIfStringOrThrow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;level1&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;builderFnLevel2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;K2&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;HeadingsMap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;K1&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="na"&gt;level2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;K2&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;pushKeyIfStringOrThrow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;level2&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;builderFnLevel3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;K3&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;HeadingsMap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;K1&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="nx"&gt;K2&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="na"&gt;level3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;K3&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;pushKeyIfStringOrThrow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;level3&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;builderFnLevel4&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;K4&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;HeadingsMap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;K1&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="nx"&gt;K2&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="nx"&gt;K3&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="na"&gt;level3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;K4&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;pushKeyIfStringOrThrow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;level3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="nx"&gt;finalize&lt;/span&gt;
                &lt;span class="p"&gt;};&lt;/span&gt;
            &lt;span class="p"&gt;};&lt;/span&gt;
            &lt;span class="nx"&gt;builderFnLevel4&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;finalize&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;finalize&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;builderFnLevel4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;
        &lt;span class="nx"&gt;builderFnLevel3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;finalize&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;finalize&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;builderFnLevel3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="nx"&gt;builderFnLevel2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;finalize&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;finalize&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;builderFnLevel2&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;And that's it! :)&lt;/p&gt;

&lt;h1&gt;
  
  
  Okay, cool... but how does that work?
&lt;/h1&gt;

&lt;p&gt;It would probably take a while to explain how and why that works. And I'll be honest, it's taken me a long time working with Typescript to create something this wild. And if you're interested in a detailed breakdown of how the above code works, reach out in the comments and I'll create a follow up post.&lt;/p&gt;

&lt;p&gt;But the basic idea is that the &lt;code&gt;keyof&lt;/code&gt; type operator creates a more strict type that is more narrow than a string.&lt;/p&gt;

&lt;p&gt;So in the case of a type like:&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;exampleObj&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;hello&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;Bill&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;goodbye&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;Ted&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can create a type that only allows &lt;code&gt;'hello' | 'goodbye'&lt;/code&gt; by writing:&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="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;exampleKeys&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;exampleObj&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Here's the next bit of magic.&lt;/em&gt; Let's say we wanted to get a type that was only &lt;code&gt;'Bill' | 'Ted'&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;All we'd have to do is write:&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="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Example&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;exampleObj&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ExampleValues&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Example&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;Example&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note: if &lt;code&gt;ExampleValues&lt;/code&gt; is still &lt;code&gt;string&lt;/code&gt; when you hover over it, you might have forgotten to add &lt;code&gt;as const&lt;/code&gt; to the end of the &lt;code&gt;exampleObj&lt;/code&gt; instantiation. Another dev.to user has &lt;a href="https://dev.to/tkudlinski/as-const-in-typescript-5390"&gt;a great explanation of what makes &lt;code&gt;as const&lt;/code&gt; work&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Wrapping Up
&lt;/h1&gt;

&lt;p&gt;Thanks for coming along in this brief journey on why Typescript is so fun and how it can solve unique code problems that no other language can solve. :)&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
