<?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: Elizabeth Efeelobari</title>
    <description>The latest articles on DEV Community by Elizabeth Efeelobari (@elizabethefeelobari).</description>
    <link>https://dev.to/elizabethefeelobari</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%2F3829768%2F68b60612-9c7d-41ae-a09e-67ec582e1481.png</url>
      <title>DEV Community: Elizabeth Efeelobari</title>
      <link>https://dev.to/elizabethefeelobari</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/elizabethefeelobari"/>
    <language>en</language>
    <item>
      <title>A hands-on guide to designing interfaces that fail with dignity. Learn practical UI patterns and examples to make your interfaces resilient, handle network failures, API errors, and keep users in control</title>
      <dc:creator>Elizabeth Efeelobari</dc:creator>
      <pubDate>Thu, 23 Apr 2026 21:09:10 +0000</pubDate>
      <link>https://dev.to/elizabethefeelobari/a-hands-on-guide-to-designing-interfaces-that-fail-with-dignity-learn-practical-ui-patterns-and-4na</link>
      <guid>https://dev.to/elizabethefeelobari/a-hands-on-guide-to-designing-interfaces-that-fail-with-dignity-learn-practical-ui-patterns-and-4na</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/elizabethefeelobari/designing-interfaces-that-fail-gracefully-what-happens-when-things-break-and-how-good-systems-4m88" class="crayons-story__hidden-navigation-link"&gt;Resilient Interfaces: Designing UIs That Survive the Real Web&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/elizabethefeelobari" class="crayons-avatar  crayons-avatar--l  "&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%2Fuser%2Fprofile_image%2F3829768%2F68b60612-9c7d-41ae-a09e-67ec582e1481.png" alt="elizabethefeelobari profile" class="crayons-avatar__image" width="96" height="96"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/elizabethefeelobari" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Elizabeth Efeelobari
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Elizabeth Efeelobari
                
              
              &lt;div id="story-author-preview-content-3534498" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/elizabethefeelobari" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&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%2Fuser%2Fprofile_image%2F3829768%2F68b60612-9c7d-41ae-a09e-67ec582e1481.png" class="crayons-avatar__image" alt="" width="96" height="96"&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Elizabeth Efeelobari&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/elizabethefeelobari/designing-interfaces-that-fail-gracefully-what-happens-when-things-break-and-how-good-systems-4m88" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Apr 22&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/elizabethefeelobari/designing-interfaces-that-fail-gracefully-what-happens-when-things-break-and-how-good-systems-4m88" id="article-link-3534498"&gt;
          Resilient Interfaces: Designing UIs That Survive the Real Web
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/javascript"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;javascript&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/frontend"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;frontend&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/googleappsscript"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;googleappsscript&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/webdev"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;webdev&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/elizabethefeelobari/designing-interfaces-that-fail-gracefully-what-happens-when-things-break-and-how-good-systems-4m88" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/exploding-head-daceb38d627e6ae9b730f36a1e390fca556a4289d5a41abb2c35068ad3e2c4b5.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/multi-unicorn-b44d6f8c23cdd00964192bedc38af3e82463978aa611b4365bd33a0f1f4f3e97.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;4&lt;span class="hidden s:inline"&gt; reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/elizabethefeelobari/designing-interfaces-that-fail-gracefully-what-happens-when-things-break-and-how-good-systems-4m88#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              Comments


              &lt;span class="hidden s:inline"&gt;Add Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            4 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
    </item>
    <item>
      <title>Resilient Interfaces: Designing UIs That Survive the Real Web</title>
      <dc:creator>Elizabeth Efeelobari</dc:creator>
      <pubDate>Wed, 22 Apr 2026 05:35:54 +0000</pubDate>
      <link>https://dev.to/elizabethefeelobari/designing-interfaces-that-fail-gracefully-what-happens-when-things-break-and-how-good-systems-4m88</link>
      <guid>https://dev.to/elizabethefeelobari/designing-interfaces-that-fail-gracefully-what-happens-when-things-break-and-how-good-systems-4m88</guid>
      <description>&lt;p&gt;When you build in your local development environment, everything works perfectly. When you test your code on your own machine, your internet connection is flawless, and API endpoints respond in milliseconds.&lt;/p&gt;

&lt;p&gt;The Google Apps Script backend executes without a hitch. In this pristine environment, it is incredibly easy to build a &lt;strong&gt;happy path&lt;/strong&gt; user interface. Users clicks a button, the data sends, and a green "Success" message appears.&lt;/p&gt;

&lt;p&gt;But to be honest, the real internet is a very chaotic, hostile environment.&lt;/p&gt;

&lt;p&gt;Users access your site on trains going through tunnels with 3G connections. API gateways throttle requests. Cross-Origin Resource Sharing (CORS) policies fail. If you only design for the happy path, your application will break the moment it hits the real world scenario.&lt;/p&gt;

&lt;p&gt;When I built the &lt;a href="https://leemeeooo.github.io" rel="noopener noreferrer"&gt;Contact&lt;/a&gt; and &lt;a href="https://leemeeooo.github.io" rel="noopener noreferrer"&gt;Ghost Network panels&lt;/a&gt; in my &lt;a href="https://leemeeooo.github.io" rel="noopener noreferrer"&gt;interactive portfolio&lt;/a&gt;, the most complex code wasn't the data transmission. It was the defensive engineering designed to handle failure.&lt;/p&gt;

&lt;p&gt;Going forward, we'll dive into designing UI resilience, handling asynchronous network chaos, and ensuring that when your application fails, it fails gracefully.&lt;/p&gt;

&lt;h3&gt;
  
  
  Phase 1: The Illusion of Immediate Success (Optimistic UI)
&lt;/h3&gt;

&lt;p&gt;When a user clicks "Send Message" on a contact form, the worst thing you can do is leave the button active while the browser waits for the server.&lt;/p&gt;

&lt;p&gt;For instance, If the server takes three seconds to respond, a confused user will click the "Send" button five more times, firing off five duplicate network requests.&lt;/p&gt;

&lt;p&gt;The first rule of resilience is &lt;strong&gt;State Lockdown&lt;/strong&gt;. The moment a network request begins, the UI must immediately reflect a pending state.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;contactForm&lt;/span&gt;&lt;span class="dl"&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;submitBtn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;submitBtn&lt;/span&gt;&lt;span class="dl"&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;feedbackMsg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;formMsg&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;submit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; 

  &lt;span class="c1"&gt;// 1. Clear any previous errors&lt;/span&gt;
  &lt;span class="nx"&gt;feedbackMsg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;feedbackMsg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;className&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// 2. STATE LOCKDOWN: Disable the button and change the text&lt;/span&gt;
  &lt;span class="nx"&gt;submitBtn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;disabled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
  &lt;span class="nx"&gt;submitBtn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Sending...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// ... proceed to network request&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By instantly disabling the button (&lt;code&gt;submitBtn.disabled = true;&lt;/code&gt;), we physically prevent the user from spamming the server. By changing the text to "Sending...", we provide immediate psychological feedback that the machine is working on the request.&lt;/p&gt;

&lt;h3&gt;
  
  
  Phase 2: Taming Asynchronous Chaos (The Fetch Wrapper)
&lt;/h3&gt;

&lt;p&gt;When we send data to a Google Apps Script backend using the &lt;code&gt;fetch()&lt;/code&gt; API, we are entering the realm of asynchronous programming. We have asked the browser to go do a job on the internet, and we have to wait for the answer.&lt;/p&gt;

&lt;p&gt;A junior developer handles a &lt;code&gt;fetch&lt;/code&gt; request like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// The UI dead Path&lt;/span&gt;
&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;WEB_APP_URL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&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;payload&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&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;// Assumed success and celebrate&lt;/span&gt;
    &lt;span class="nx"&gt;submitBtn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;disabled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;feedbackMsg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Message Sent!&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This particular code is a time bomb, a disaster. What happens if the Google server returns a &lt;code&gt;500 Internal Server Error&lt;/code&gt;? What happens if the user's WiFi drops mid-request?&lt;/p&gt;

&lt;p&gt;Simple, the &lt;code&gt;.then()&lt;/code&gt; block will fail, the button will remain permanently disabled, and the user will be stuck staring at a "Sending..." message forever.&lt;/p&gt;

&lt;p&gt;In essence, the UI is dead.&lt;/p&gt;

&lt;p&gt;However, a resilient system uses strict &lt;code&gt;Promise&lt;/code&gt; chaining and an ironclad &lt;code&gt;.catch()&lt;/code&gt; block.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// THE RESILIENT PATH&lt;/span&gt;
&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;WEB_APP_URL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
  &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&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;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&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;// 1. Check if the HTTP status is actually OK&lt;/span&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;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ok&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="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="s1"&gt;Network response was not ok.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&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;// 2. The server responded, but did our specific logic succeed?&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;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;success&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// THE HAPPY PATH&lt;/span&gt;
    &lt;span class="nx"&gt;submitBtn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;disabled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
    &lt;span class="nx"&gt;submitBtn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Send Message&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;feedbackMsg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;color&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;currentAccent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
    &lt;span class="nx"&gt;feedbackMsg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Secure message transmitted. Expect a reply shortly.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reset&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="c1"&gt;// The server replied, but the Apps Script logic failed&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="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Backend logic failed.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// 3. THE SAFETY NET: Catch ALL errors (Network drops, CORS, Server crashes)&lt;/span&gt;
  &lt;span class="nx"&gt;submitBtn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;disabled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
  &lt;span class="nx"&gt;submitBtn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Send Message&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nx"&gt;feedbackMsg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;color&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;red&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// indicator&lt;/span&gt;
  &lt;span class="nx"&gt;feedbackMsg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Connection failed. Please email directly: efeelobarie@gmail.com&lt;/span&gt;&lt;span class="dl"&gt;'&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;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;Transmission Error:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Phase 3: The Ultimate Fallback (Graceful Degradation)
&lt;/h3&gt;

&lt;p&gt;The most important line of code in the entire sequence above is the error message itself: &lt;code&gt;"Connection failed. Please email directly: efeelobarie@gmail.com"&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This is the principle of &lt;strong&gt;Graceful Degradation&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If my custom Google Apps Script backend fails, or if a browser extension completely blocks the &lt;code&gt;fetch&lt;/code&gt; request, the user's goal (which is contacting me) is not destroyed. The application admits failure, then releases the locked UI state, and immediately provides a low-tech, unbreakable alternative, which is a plain text email address (or directive)&lt;/p&gt;

&lt;h3&gt;
  
  
  The Empathy of Error Handling
&lt;/h3&gt;

&lt;p&gt;This represents a shift in software design and user experience (UX) from purely technical, machine-oriented messaging to human-centric communication. It recognizes that error messages are not just functional interruptions but critical psychological events that can either build trust or cause anxiety (&lt;a href="https://medium.com/design-bootcamp/error-handling-ux-design-patterns-c2a5bbae5f8d" rel="noopener noreferrer"&gt;medium&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Writing defensive code is not just about preventing crashes. It is an exercise in user empathy.&lt;/p&gt;

&lt;p&gt;Imagine an application breaks and leaves a user staring at a frozen screen. This creates frustration and erodes trust.&lt;/p&gt;

&lt;p&gt;When an application encounters an error, the system should immediately inform the user and offer a clear alternative path. This approach builds professionalism and trust through prevention, rather than just reaction.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;F A I L&lt;/p&gt;

&lt;p&gt;Feedback : Always tell the user what happened&lt;/p&gt;

&lt;p&gt;Actions : Give next step&lt;/p&gt;

&lt;p&gt;Integrity : Don’t lose user data&lt;/p&gt;

&lt;p&gt;Latency handling: Handle delays properly&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;We unknownly spend so much time building the perfect happy path, but a system's true quality is defined by how it behaves when everything goes wrong.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If a company’s web application is fragile, frustrating, and prone to silent failures, there is a need for a more resilient system.&lt;/p&gt;

&lt;p&gt;Thank you for reading till the end. I hope you learnt something new and if you have any &lt;strong&gt;questions&lt;/strong&gt;, feel free to reach out or drop &lt;strong&gt;them&lt;/strong&gt; in the &lt;strong&gt;comments&lt;/strong&gt; below.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>frontend</category>
      <category>googleappsscript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>How to Build a Code Visualizer in Google Apps Script</title>
      <dc:creator>Elizabeth Efeelobari</dc:creator>
      <pubDate>Tue, 17 Mar 2026 16:50:28 +0000</pubDate>
      <link>https://dev.to/elizabethefeelobari/how-to-build-a-code-visualizer-in-google-apps-script-44gc</link>
      <guid>https://dev.to/elizabethefeelobari/how-to-build-a-code-visualizer-in-google-apps-script-44gc</guid>
      <description>&lt;p&gt;Lately I am doing more of documentation and record keeping. Having fun teaching what I know.&lt;/p&gt;

&lt;p&gt;Everyone is vibe coding and It is getting saturated to the point everyone feels like a creator, full-stack dev. &lt;br&gt;
Until the bug hits, then prompt prompt prompt, prompt it away. &lt;br&gt;
I miss the old days of research and actually trying to understand what is happening.&lt;/p&gt;

&lt;p&gt;I write a lot, so I decided to just specialize as Apps Script developer. Build around the Google ecosystem. Have fun, document, teach, build.&lt;br&gt;
I finally finished one.&lt;/p&gt;

&lt;p&gt;Although, I kept debugging for the fun and emotional turbulence.&lt;br&gt;
So I built something that shows me and records activities. A Code Visualizer that streams every operation to a live browser dashboard in real time. Just Apps Script doing what its good at.&lt;/p&gt;

&lt;p&gt;I walk through monkey-patching, setting up the live logging dashboard, and visualizing exactly what your spreadsheet is doing as it happens.&lt;/p&gt;

&lt;p&gt;If you have ever debugged a spreadsheet and felt completely in the dark, this one is for you.&lt;/p&gt;

&lt;p&gt;Full article here:&lt;br&gt;
&lt;a href="https://elizabethefeelobari.hashnode.dev/how-to-build-a-code-visualizer-in-google-apps-script" rel="noopener noreferrer"&gt;How to Build a Code visualizer in Google Apps Script&lt;/a&gt;&lt;/p&gt;

</description>
      <category>googleappsscript</category>
      <category>monkeypatching</category>
      <category>javascript</category>
      <category>automation</category>
    </item>
  </channel>
</rss>
