<?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: LTV Co. Engineering</title>
    <description>The latest articles on DEV Community by LTV Co. Engineering (@ltvengineering).</description>
    <link>https://dev.to/ltvengineering</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%2F414562%2Fea0180e1-97f1-4ec8-8a11-4af42f198ef3.png</url>
      <title>DEV Community: LTV Co. Engineering</title>
      <link>https://dev.to/ltvengineering</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ltvengineering"/>
    <language>en</language>
    <item>
      <title>From Kubernetes to OpenFaaS: A Lesson in Configuration and Container Lifecycles</title>
      <dc:creator>LTV Co. Engineering</dc:creator>
      <pubDate>Wed, 20 Mar 2024 20:21:20 +0000</pubDate>
      <link>https://dev.to/ltvengineering/from-kubernetes-to-openfaas-a-lesson-in-configuration-and-container-lifecycles-4ibj</link>
      <guid>https://dev.to/ltvengineering/from-kubernetes-to-openfaas-a-lesson-in-configuration-and-container-lifecycles-4ibj</guid>
      <description>&lt;h1&gt;
  
  
  In this post
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;Setting the stage&lt;/li&gt;
&lt;li&gt;The issue&lt;/li&gt;
&lt;li&gt;Exploration phase: Understanding container lifecycle&lt;/li&gt;
&lt;li&gt;Gained insights&lt;/li&gt;
&lt;li&gt;Additional references&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;a href="https://www.openfaas.com/"&gt;OpenFaaS&lt;/a&gt; has emerged as a powerful platform for deploying functions in the realm of serverless computing. In this blog post, we will cover an intriguing problem we encountered while utilizing OpenFaaS cron jobs for a process that involved JWT authentication. Our exploration took us through the basics of containerization, code configuration, and comprehension of container lifecycles, which ultimately revealed an unforeseen solution.&lt;/p&gt;




&lt;h1&gt;
  
  
  Setting the stage &lt;a&gt;
&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;Our Data Engineering team had grown accustomed to deploying processes directly within Kubernetes (K8s) environments and managing them through &lt;a href="https://kubernetes.io/docs/concepts/workloads/controllers/cron-jobs/"&gt;Kubernetes cron jobs&lt;/a&gt;. Our familiarity with Kubernetes prompted certain presumptions as we embarked on our exploration of the OpenFaaS domain.&lt;/p&gt;




&lt;h1&gt;
  
  
  The issue &lt;a&gt;
&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;Our task seemed relatively simple. We needed to create a process that periodically connects to an API endpoint, analyzes the response, and sends messages to a Slack channel when data is present. The process was hosted on OpenFaaS, and JWT was used for authentication. However, an inexplicable issue arose: despite a seemingly correct configuration, the process consistently failed with a 401 Unauthorized status code after the first successful run.&lt;/p&gt;

&lt;p&gt;Our authentication configuration was defined using a JWT (JSON Web Token) claims structure and included an expiration time calculated based on the current time. The initial code appeared as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;processor&lt;/span&gt;

&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;conf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;configuration&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;SigningKey&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"SHARED_SECRET"&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
      &lt;span class="n"&gt;SigningMethod&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;jwt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SigningMethodHS256&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="n"&gt;StaticClaims&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;jwt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MapClaims&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="s"&gt;"iss"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetWithDefault&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"CREDENTIALS_KEY"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"data-engineering"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
          &lt;span class="s"&gt;"iat"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unix&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
          &lt;span class="s"&gt;"exp"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Minute&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unix&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The logic to execute the process resided within a function that was scheduled using the OpenFaaS &lt;a href="https://docs.openfaas.com/reference/cron/"&gt;cron-connector feature&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;ProcessLatest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;newProcessor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;conf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&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;Strikingly, the issue presented itself inconsistently: local runs succeeded while executions from OpenFaaS failed.  To further complicate matters, a fresh build of the code resolved the issue temporarily. After meticulous analysis, a pattern emerged: the token expiration was at the heart of the matter because their premature expiration led to unauthorized API access. &lt;/p&gt;




&lt;h1&gt;
  
  
  Exploration phase: Understanding container lifecycle &lt;a&gt;
&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;Let’s contrast how Kubernetes cron jobs operate with the unique mechanics of OpenFaaS functions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Kubernetes cron jobs
&lt;/h2&gt;

&lt;p&gt;Kubernetes operates with a distributed architecture, orchestrated by its control plane and executed on worker nodes. At the core of this architecture are nodes, the worker machines within a Kubernetes cluster. Each node runs containers grouped within pods, forming a unit of deployment.&lt;/p&gt;

&lt;p&gt;Containers provide isolated environments tailored for running specific applications. Kubernetes jobs are designed to run pods until a designated task is completed, after which the pods are terminated. A cron job (a specialized type of job) is responsible for executing tasks on a schedule.&lt;/p&gt;

&lt;p&gt;Of paramount relevance is the fact that each Kubernetes cron job initiates, executes, and eventually purges the pod upon task completion.&lt;/p&gt;

&lt;h2&gt;
  
  
  OpenFaaS mechanisms
&lt;/h2&gt;

&lt;p&gt;We encountered a unique set of OpenFaaS mechanics that differentiated it from Kubernetes. OpenFaaS functions are executed within containers that align with the ethos of serverless computing. These containers must adhere to certain &lt;a href="https://docs.openfaas.com/reference/workloads/"&gt;rules&lt;/a&gt;, that include serving HTTP traffic on port 8080, embracing ephemeral storage, and maintaining statelessness.&lt;/p&gt;

&lt;p&gt;The concept of the function watchdog lies at the heart of OpenFaaS’s function execution, a lightweight HTTP server. Among its various modes, the &lt;a href="https://github.com/openfaas/classic-watchdog"&gt;classic watchdog&lt;/a&gt; is of interest to us. While a detailed examination of how the watchdog operates is warranted, our focus lies on understanding isolation dynamics.&lt;/p&gt;

&lt;p&gt;In summary, there are a few things to keep in mind:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Container Separation: different functions are encapsulated within separate containers.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Container Lifecycle: Containers commence execution upon function deployment or scaling. Depending on scaling options, a function might comprise multiple containers to cater to demand.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Handling HTTP Requests: a single container can efficiently handle multiple HTTP requests, each treated as an independent unit with no relation to preceding requests.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Crucially, OpenFaaS operates atop Kubernetes, harnessing its capabilities while offering additional configurations to facilitate the creation of cron jobs for functions.&lt;/p&gt;




&lt;h1&gt;
  
  
  Untangling the riddle &lt;a&gt;
&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;Armed with this context, the intriguing issue we encountered—JWT token expiration and the inconsistency in OpenFaaS function behavior—began to unravel. The disparity in container lifecycle behavior between Kubernetes and OpenFaaS resided at the core of our confusion. While Kubernetes cron jobs naturally terminated pods after execution, OpenFaaS containers persisted, retaining configuration data. This difference fundamentally impacted the validity of JWT tokens and led to unauthorized API access.&lt;/p&gt;

&lt;p&gt;The code segment responsible for computing JWT claim details, including the issued and expiration time, resided as a package variable. This characteristic renders it global in scope, resulting in a single computation during the container’s lifecycle. Consequently, tokens were perpetually outdated, resulting in the recurring authentication failure.&lt;/p&gt;




&lt;h1&gt;
  
  
  Crafting the solution &lt;a&gt;
&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;With a comprehensive understanding of Kubernetes and OpenFaaS mechanics, the path to resolution was evident. We realized that it was essential to generate configuration values dynamically for every function execution instead of relying on package-level variables. This insight led us to encapsulate the configuration logic within its own function, guaranteeing fresh values with each execution.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;configuration&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;amp;&lt;/span&gt;&lt;span class="n"&gt;configuration&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="o"&gt;...&lt;/span&gt;
        &lt;span class="n"&gt;SigningKey&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"SHARED_SECRET"&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
        &lt;span class="n"&gt;SigningMethod&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;jwt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SigningMethodHS256&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;StaticClaims&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;jwt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MapClaims&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="s"&gt;"iss"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetWithDefault&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"CREDENTIALS_KEY"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"data-engineering"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="s"&gt;"iat"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unix&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
            &lt;span class="s"&gt;"exp"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Minute&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unix&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="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;ProcessLatest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;conf&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;newProcessor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&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;h1&gt;
  
  
  Gained insights &lt;a&gt;
&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;Our journey embraced exploration and experimentation, guided by our core values “Try, Fail, Learn and Repeat.” As novices in OpenFaaS, we transformed a stumbling block into a pivotal learning experience. We gained insights into OpenFaaS and containerization, improving our codebase and equipping us for future challenges.&lt;/p&gt;

&lt;p&gt;This experience affirmed that simple challenges harbor profound insights. The issue’s resolution reinforced the value of flexibility and platform-specific awareness, highlighting the need for adaptable approaches.&lt;/p&gt;




&lt;h1&gt;
  
  
  Additional references &lt;a&gt;
&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://iximiuz.com/en/posts/openfaas-case-study/"&gt;1. IXMIUZ - Open FaaS Case Study&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://kubernetes.io/docs/concepts/"&gt;2. Kubernetes Documentation&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Interested in working with us? Have a look at our careers page and reach out to us if you would like to be a part of our team!&lt;/p&gt;




&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhldsxlit7v37cc8n2byi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhldsxlit7v37cc8n2byi.png" alt="Image description" width="403" height="112"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>openfaas</category>
      <category>kubernetes</category>
      <category>containers</category>
    </item>
    <item>
      <title>Contributing to Open Source Software</title>
      <dc:creator>LTV Co. Engineering</dc:creator>
      <pubDate>Mon, 15 Jan 2024 20:06:24 +0000</pubDate>
      <link>https://dev.to/ltvengineering/contributing-to-open-source-software-3047</link>
      <guid>https://dev.to/ltvengineering/contributing-to-open-source-software-3047</guid>
      <description>&lt;h1&gt;
  
  
  In this post
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;What is Open Source Software?&lt;/li&gt;
&lt;li&gt;What is an open source license? &lt;/li&gt;
&lt;li&gt;Why is open source software important?&lt;/li&gt;
&lt;li&gt;How do we start contributing to Open Source Software? The LTV experience&lt;/li&gt;
&lt;li&gt;Some risks in OSS&lt;/li&gt;
&lt;li&gt;Recommendations&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;We love experimenting and trying new things at the Lifetime Value Company (LTV). Along this process, we usually leverage open-source software within different projects we have in the company. However, sometimes we find issues, missing features, and possible improvements that can be merged back into the open source software (OSS) so other developers can take advantage of them as well. &lt;/p&gt;

&lt;p&gt;In this post, we’ll share our experience as company developers working with open source software. First, let’s understand what open source software is and how we use it at LTV. Additionally, we’ll explore examples of how our company developers have contributed to the community and discuss potential risks associated with OSS.&lt;/p&gt;




&lt;h1&gt;
  
  
  What is Open Source Software? &lt;a&gt;
&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;Open source software is code designed to be publicly accessible—anyone can see, modify, and distribute the code as they see fit.&lt;/p&gt;

&lt;p&gt;In a real example, let’s say we have been building a new feature to automate or do any task we need, and we want to share it with other developers. That’s when an open source community starts being created. It’s important to know that every software or tool in the OSS is not free, and  there are some terms and conditions of usage, important concepts, and some legal arguments to know about it. Take a look here to find a legal guide about OSS. &lt;/p&gt;

&lt;p&gt;When it talks about OSS not being free at all, it means the conditions of how to share it vary. Stipulations include keeping the authors’ names and redistributing with the same license. Also, if the license permits modification or redistribution for only non-commercial purposes, it’s not open source.&lt;/p&gt;




&lt;h1&gt;
  
  
  What is an open source license? &lt;a&gt;
&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;An open-source license is a legally binding contract between the author of the software and the user. Software that’s publicly posted and available for free is not automatically open source. The license makes it officially open source. A lot of open-source software is free of charge, but that doesn’t mean that being free of charge is a requirement or guarantee of open-source software.&lt;/p&gt;

&lt;p&gt;There are two categories of licenses: Copyleft and Permissive. Copyleft requires the user to apply the same license to their version of the product. This means that if the user modifies and shares the software, they have to maintain the open-source license. On the other hand, Permissive licenses do not have copyleft provisions, so the user is not required to keep their version of the product open source.&lt;/p&gt;

&lt;p&gt;There are many types of licenses; here you will find a list of the common ones and some small descriptions for each one. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjv1hkg0p9o2j8z9f6g3c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjv1hkg0p9o2j8z9f6g3c.png" alt="Image description" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Apache License
&lt;/h3&gt;

&lt;p&gt;The Apache License is an open-source license by the Apache Software Foundation. Under the license, you can use, modify or distribute any Apache-licensed product.&lt;/p&gt;

&lt;h3&gt;
  
  
  Berkeley Software Distribution (BSD)
&lt;/h3&gt;

&lt;p&gt;There are two types of BSD licenses:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Modified BSD License (3-clause)&lt;/li&gt;
&lt;li&gt;Simplified BSD License, also called the FreeBSD License (2-clause)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each BSD license gives permission to modify and distribute software code, source, or binary. However, you must retain a copy of the conditions, copyright notice, and disclaimer.&lt;/p&gt;

&lt;h3&gt;
  
  
  Common Development and Distribution License (CDDL)
&lt;/h3&gt;

&lt;p&gt;The CDDL is an open-source license created by Sun Microsystems (acquired by Oracle). The current CDDL is version 2, and it’s a spin on the Mozilla Public License. It also replaced the Sun Public License, which came with free and open-source Sun products until 2004.&lt;/p&gt;

&lt;h3&gt;
  
  
  GNU General Public License (GPL)
&lt;/h3&gt;

&lt;p&gt;The GPL is the most popular open-source license (WordPress plugins and themes must have this license). It’s a copyleft license, so any software that uses any GPL component has to be open source, even if just a tiny percentage of the code is in the modified code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Massachusetts Institute of Technology (MIT) License
&lt;/h3&gt;

&lt;p&gt;The MIT license is one of the most flexible open-source licenses out there, and it grants all the end-user rights you’d expect from an open-source license: copying, distributing, merging, modifying, etc. It’s mostly known for what it doesn’t include, specifically an advertising clause. Also, it allows the copyright owner’s name in promotional content.&lt;/p&gt;




&lt;h1&gt;
  
  
  Why is open source software important? &lt;a&gt;
&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;OSS has fueled some of the most important software used by millions of developers and companies. Also, it is important to remember that most of the software we use to develop is OSS. &lt;/p&gt;

&lt;p&gt;At LTV, we are concerned about this and the importance of OSS and this is why we want to share knowledge and making aware everyone about OSS, this is part of our culture and our core value which is ‘Teach Each Other To Fish’ (Here in case you want to see our core values). OSS is the reason why technology has grown like foam for the past few decades.&lt;/p&gt;

&lt;p&gt;Also, it is important to mention how most of the frameworks developers used today, are fueled by OSS, including Rails, Golang, Angular, React, EmberJS, and libraries in software from the most diverse areas, these have been used by thousands of developers. From the Machine Learning fields, we also have some Pytorch, TensorFlow, OpenCV, YOLOv7, and many more. &lt;/p&gt;

&lt;p&gt;Another important area where OSS projects are, is in the DevOps culture; such as Docker, Kubernetes, Terraform, and many more. All these tools are now widely used and those are related to having a good architectural application that is used by millions of users.&lt;/p&gt;

&lt;p&gt;Open source software is more than just a set of code that anyone can use, modify, and distribute. It represents a different way of thinking about software development, one that is built on collaboration, transparency, and innovation. Below, we’ll explore some creative points of view on open-source software that highlights its unique benefits and potential.&lt;/p&gt;

&lt;h3&gt;
  
  
  Open-source software is a social movement
&lt;/h3&gt;

&lt;p&gt;At its core, open-source software is about people coming together to solve problems and create something of value. It represents a social movement that is driven by a shared vision of technology that is accessible, equitable, and empowering. By embracing open-source software, individuals and organizations can participate in this movement and contribute to a global community of developers, users, and advocates.&lt;/p&gt;

&lt;p&gt;Open-source software has the potential to be a powerful tool for social change. By making technology more accessible and equitable, open-source software can help to bridge the digital divide and promote greater participation in the digital economy. Additionally, by fostering collaboration and innovation, open-source software can help to create solutions to some of the world’s most pressing social and environmental challenges.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fez8duylo8cgke7prqpqx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fez8duylo8cgke7prqpqx.png" alt="Image description" width="800" height="426"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Open-source software is a platform for experimentation
&lt;/h3&gt;

&lt;p&gt;One of the key benefits of open-source software is that it enables developers to experiment with new ideas and approaches without fear of failure. Because the code is openly available, developers can try out new features and approaches, receive feedback from the community, and iterate on their work. This platform for experimentation can lead to innovative new technologies and approaches that might not be possible in a more closed, proprietary environment.&lt;/p&gt;

&lt;h3&gt;
  
  
  Open-source software is a source of inspiration
&lt;/h3&gt;

&lt;p&gt;The collaborative and creative nature of open-source software can be a source of inspiration for developers, designers, and entrepreneurs alike. By studying open-source projects and participating in open-source communities, individuals can learn from the successes and failures of others, and apply those lessons to their own work. Additionally, open-source software can inspire new ideas and approaches that might not have been considered otherwise.&lt;/p&gt;

&lt;h2&gt;
  
  
  Open-source software is a way to give back
&lt;/h2&gt;

&lt;p&gt;For many developers, contributing to open-source software is a way to give back to the community and support the greater good. By sharing their code and expertise, developers can help to improve the quality and reliability of open-source projects and enable others to build on their work. Additionally, by participating in open-source communities, developers can build valuable connections and relationships with like-minded individuals and organizations.&lt;/p&gt;




&lt;h1&gt;
  
  
  How do we start contributing to Open Source Software? The LTV experience &lt;a&gt;
&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;Contributing to OSS is a journey with multiple steps. It begins by identifying a need that an existing (or non-existing) library or project has. Next, it involves defining what needs to be done to fulfill this need. Afterward, it is important to validate this need with other developers in the community and the maintainers of the library, in order to understand why it hasn’t been implemented or addressed yet. Finally, it is time to discuss possible approaches to solve the need. It may be a long road, but one that brings immense satisfaction upon completion.&lt;/p&gt;

&lt;p&gt;At LTV, contributing to OSS has been key for the success of the career path of many of the engineers working here; There is no one or two, but multiple people in the company who have contributed and continue contributing to OSS. &lt;/p&gt;

&lt;p&gt;We shared some questions with some LTV employees who already contributed to OSS, here you will see their thoughts/responses. Each bullet is a response from a different person. &lt;/p&gt;

&lt;h3&gt;
  
  
  In which libraries/projects have you worked with OSS?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Rack, Resque (Patrick Tulskie, VP of Engineering)&lt;/li&gt;
&lt;li&gt;Zendesk Ruby Gem (Kevin Pedroza, Engineer 1)&lt;/li&gt;
&lt;li&gt;I contributed to an AVRO codec for Golang, adding support for unmarshaling union values to their logical type instead of their primitive type. &lt;a href="https://github.com/hamba/avro/pull/71"&gt;https://github.com/hamba/avro/pull/71&lt;/a&gt; (José García, Associate Director of Engineering 1)&lt;/li&gt;
&lt;li&gt;I worked on the go-gorm/bigquery project (Nazareth Roman, Engineer 3)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  What are some of the pitfalls you’ve found while doing OSS?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Getting stuff merged in/reviewed by the project’s maintainers can be difficult. I once had a PR get merged 2 years later for a feature I added. By that time we’d stopped using the library. (Patrick Tulskie, VP of Engineering)&lt;/li&gt;
&lt;li&gt;Trying to merge the change to main, it is difficult to get in touch with the maintainer even to get reviews. (Kevin Pedroza, Engineer 1)&lt;/li&gt;
&lt;li&gt;Trying to understand the whole project you’re contributing could be challenging, I would suggest for anyone wanting to contribute to open source projects to focus on a specific and small area instead. (José García, Associate Director of Engineering 1)&lt;/li&gt;
&lt;li&gt;I didn’t find anything really hard in that contribution, however, I would have loved the project to have unit tests for the piece of code that I was modifying, which it didn’t, so I had to test the cases on my own. (Nazareth Roman, Engineer 3)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Did you find it hard to contribute in OSS?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Not really. I just makes sure I look around and assess what is going on in the repo before I start trying to make changes or additions. (Patrick Tulskie, VP of Engineering)&lt;/li&gt;
&lt;li&gt;It is not really hard, you just need to find any issue or add a feature you would like to have or need in the library.(Kevin Pedroza, Engineer 1)&lt;/li&gt;
&lt;li&gt;Not really, it is just a matter of finding a good opportunity that benefits the company. (José García, Associate Director of Engineering 1)&lt;/li&gt;
&lt;li&gt;This contribution was not hard since Go is usually well documented and many projects follow best practices. (Nazareth Roman, Engineer 3)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  What would you do differently to lower the entry barrier for contribution to OSS projects?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Have a contribution guide in the readme for the project. Set expectations for contributors and steer them towards that when they submit things that don’t meet your expectations. (Patrick Tulskie, VP of Engineering)&lt;/li&gt;
&lt;li&gt;I would enhance people to know OSS; sometimes whatever repo you find, you will only care about how to use and how to install it. But we are not concerned about how to collaborate with them, even if there is the info on the readme. So, we have to promote that culture of collaboration. (Kevin Pedroza, Engineer 1)&lt;/li&gt;
&lt;li&gt;As I said before, focusing on specific and small areas of a project. A simple and small contribution are usually the best ones and the quickest ones to be released. (José García, Associate Director of Engineering 1)&lt;/li&gt;
&lt;li&gt;I wouldn’t do anything differently in specific because in my case this was a very clear and straightforward change; however, since we needed this change to be applied soon, I didn’t consider writing unit tests for the change because it had to be started from scratch in the project. I would like to open a new PR that introduces unit testing for many of the pieces of code that didn’t have. (Nazareth Roman, Engineer 3)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  In general terms, what insights could you share such as learnings, experiences or findings when contributed to OSS?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Don’t take things personally. When you submit something, you’re basically tapping a random stranger on the shoulder or shouting into a crowd. It may be necessary to reach out to maintainers outside of github or bump your request a few times. OSS maintainers are often doing this work for free and their work/lives will usually come first. (Patrick Tulskie, VP of Engineering)&lt;/li&gt;
&lt;li&gt;I think the most important one would be filling up our expectations and motivation, once we know about OSS and we want to collaborate, that thirst is not filled up till the PR is merged. Then, I would say, OSS is a new world and you understand the code differently cause in the end you are coding to optimize others’ work with your work, so that experience is very nutritious. (Kevin Pedroza, Engineer 1)&lt;/li&gt;
&lt;li&gt;It’s a great and rewarding experience. (José García, Associate Director of Engineering 1)&lt;/li&gt;
&lt;li&gt;I found that it is important to keep eyes open and be aware of opportunities that can really help my team and help outside users potentially. In my case, I think it was a straightforward contribution because I made sure to keep it as concrete as possible, trying to solve a single problem and focusing on not introducing breaking changes. I think those were some of the reasons why my PR was accepted without any problem. Also, as I mentioned before, Golang provides vast documentation about best practices and abstractions so that many pieces of code are compatible with each other.&lt;/li&gt;
&lt;li&gt;Something that was useful to me was to fork the repository and create an initial Pull Request in my own fork so that my teammates were able to give it a first round of reviews and provide me with feedback before submitting the PR to the project and of course, deeply test it locally. (Nazareth Roman, Engineer 3)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  How did the contribution help LTV CO?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;In the case of Rack, I patched a bug that could be leveraged for cache poisoning and XSS. I patched it for us so that we were protected and submitted the fix upstream. That one took a while to get merged in, but we were protected in the meantime. In the case of resque, I actually offered to help the maintainers out with shipping new releases since we are heavy users of resque. I now help get new releases out the door and review PRs from other people. (Patrick Tulskie, VP of Engineering)&lt;/li&gt;
&lt;li&gt;When adding the new feature to Zendesk Gem, we were running on the deadline from Zendesk. Since the old would get deprecated and would start reducing the number of requests, in LTV we have a huge amount of requests from Customer Service. So, keeping this up to date would increase the Customer Service Rate and, most importantly, our culture. (Kevin Pedroza, Engineer 1)&lt;/li&gt;
&lt;li&gt;We were able to create data pipelines that can handle optional timestamp fields and decoded them into dynamic (unknown) types. (José García, Associate Director of Engineering 1)&lt;/li&gt;
&lt;li&gt;Background: I’m part of the Data Engineering team and during the development of one of our data pipelines, we came across the need of implementing an extractor that uses the Gorm BigQuery driver and we required the use of scopes to get data from a view that is being populated by a Google Sheet. The current implementation of the driver didn’t handle the scopes option.

&lt;ul&gt;
&lt;li&gt;Feature: Being able to authenticate the bigquery client by passing OAuth2 scopes received in the uri as an optional value.&lt;/li&gt;
&lt;li&gt;Pull Request: &lt;a href="https://github.com/go-gorm/bigquery/pull/1"&gt;https://github.com/go-gorm/bigquery/pull/1&lt;/a&gt; (Nazareth Roman, Engineer 3)&lt;/li&gt;
&lt;/ul&gt;


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




&lt;h1&gt;
  
  
  Some risks in OSS &lt;a&gt;
&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;As you can see, the journey at LTV collaborating with OSS has been useful and very productive, but as you would imagine, there are some risks involved when we talk about OSS.Below is a non-exhaustive list of some of the common issues.&lt;/p&gt;

&lt;h3&gt;
  
  
  Compatibility risks
&lt;/h3&gt;

&lt;p&gt;Open Source software may not always be compatible with other software, especially proprietary software. This can cause compatibility issues that may require additional resources to resolve.&lt;/p&gt;

&lt;h3&gt;
  
  
  Abandonment by maintainers
&lt;/h3&gt;

&lt;p&gt;We have faced issues when for example, we want to collaborate with fixing issues or adding a new feature and in some cases, the maintainers do not collaborate on reviewing PRs or merging PRs that are ready. It could be annoying and critical when there is a deadline to conclude any task related to the feature or fix. &lt;/p&gt;

&lt;h3&gt;
  
  
  Toxic behavior
&lt;/h3&gt;

&lt;p&gt;Toxic behavior within the Open Source community is an unfortunate issue that can hinder collaboration and progress. Instances of such behavior, although not representative of the community as a whole, do occur and can have negative consequences.&lt;br&gt;
One form of toxicity commonly observed is harsh and disrespectful communication. This includes personal attacks, belittling remarks, and dismissive attitudes towards others’s ideas or contributions. Such behavior not only discourages newcomers from participating but also creates a hostile environment that inhibits open dialogue and constructive feedback.&lt;/p&gt;

&lt;h3&gt;
  
  
  Trust OSS
&lt;/h3&gt;

&lt;p&gt;It sounds weird to see the “Trust on OSS” as a risk. But, there are some cases where we trust others to provide us with more layers of abstractions so we can focus on delivering value. But what happens when the trust chain is broken?&lt;/p&gt;

&lt;p&gt;Leftpad was an example of this in 2016. Used by high-profile projects like React, Node, and Babel listed them as dependencies. It was taken out from NPM due to a developer being in conflict with a company due to a module naming. The developer was angry that NPM removed the conflicting package, and he removed 250 more packages from NPM. This caused multiple projects depending on this dependency to break. Imagine not being able to deploy because an open-source maintainer decided to remove his package.&lt;/p&gt;

&lt;p&gt;Another case that is most recent is the breaking news about “Color” and “Fake”’ npm packages that were sabotaged.If you want to know more about it, you can check it out here. &lt;/p&gt;

&lt;p&gt;Log4j Forever Changed What (Some) Cyber Pros Think About OSS, In late 2021, the Apache Software Foundation disclosed a vulnerability that set off a panic across the global tech industry. The bug, known as Log4Shell, was found in the ubiquitous open-source logging library Log4j, and it exposed a huge swath of applications and services. &lt;/p&gt;




&lt;h1&gt;
  
  
  Recommendations &lt;a&gt;
&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;As a company passionate about Open Source Software (OSS), we believe in the power of collaborative contributions. If you’re interested in contributing to OSS projects, we have some recommendations to make your experience rewarding and impactful:&lt;/p&gt;

&lt;h3&gt;
  
  
  Find projects aligned with your expertise and values
&lt;/h3&gt;

&lt;p&gt;Look for projects that align with your skills and align with your values or industry focus. This ensures that your contributions are meaningful and contribute to areas you are genuinely interested in.&lt;/p&gt;

&lt;h3&gt;
  
  
  Start with smaller tasks and build your way up
&lt;/h3&gt;

&lt;p&gt;Begin by tackling smaller, manageable tasks to gain familiarity with the project’s codebase, workflow, and community dynamics. This approach allows you to build confidence, learn from experienced contributors, and make a positive impact from the start.&lt;/p&gt;

&lt;h3&gt;
  
  
  Respect the project’s guidelines and processes
&lt;/h3&gt;

&lt;p&gt;Follow the project’s guidelines, including coding conventions, documentation standards, and version control practices. Adhering to these guidelines ensures consistency and facilitates the review and acceptance of your contributions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Contribute quality code and documentation
&lt;/h3&gt;

&lt;p&gt;Prioritize quality in your contributions. Write clean, well-documented code that adheres to best practices. Ensure your contributions include comprehensive documentation, including clear instructions and examples that make it easier for others to understand and use your work.&lt;/p&gt;

&lt;h3&gt;
  
  
  Test and validate your changes
&lt;/h3&gt;

&lt;p&gt;Thoroughly test your changes to ensure they function as intended and do not introduce new issues. Follow the project’s testing guidelines and consider different scenarios, edge cases, and compatibility across platforms. Reliable contributions are valuable to the project and its users.&lt;/p&gt;




&lt;h1&gt;
  
  
  Conclusion &lt;a&gt;
&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;Contributing to open source software can be a fulfilling and rewarding experience for developers at any level. By participating in open source projects, developers have the opportunity to collaborate with others, learn from experienced programmers, build their skills, and make meaningful contributions to the technology industry.&lt;/p&gt;

&lt;p&gt;Moreover, contributing to open source software is a great way to give back to the community and make a positive impact on the world. Open source software has the potential to solve important problems and provide free, accessible solutions for people all over the globe. At LTV, we love giving back to the community and positively impacting the world.&lt;/p&gt;

&lt;p&gt;If you are interested in contributing to open source software, there are many resources available to help you get started, including online tutorials, community forums, and mentorship programs. By taking advantage of these resources and working with other developers, you can gain valuable experience and make a difference in the world of technology.&lt;/p&gt;




&lt;p&gt;Interested in working with us? Have a look at our careers page and reach out to us if you would like to be a part of our team!&lt;/p&gt;




&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs78ym6zhelysp1w2840d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs78ym6zhelysp1w2840d.png" alt="Image description" width="402" height="111"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>opensource</category>
    </item>
    <item>
      <title>Effective Debugging</title>
      <dc:creator>LTV Co. Engineering</dc:creator>
      <pubDate>Mon, 15 Jan 2024 18:07:33 +0000</pubDate>
      <link>https://dev.to/ltvengineering/effective-debugging-2iia</link>
      <guid>https://dev.to/ltvengineering/effective-debugging-2iia</guid>
      <description>&lt;h1&gt;
  
  
  In this post
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;Understand the problem&lt;/li&gt;
&lt;li&gt;Reproduce the error&lt;/li&gt;
&lt;li&gt;Isolate the code&lt;/li&gt;
&lt;li&gt;Write some tests&lt;/li&gt;
&lt;li&gt;Debugging tools&lt;/li&gt;
&lt;li&gt;Final thoughts&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Let’s be honest, bugs (and debugging) are a painful, time-consuming and often frustrating process. However, it is part of our lives as developers, and also one of the best ways to learn and improve.&lt;/p&gt;

&lt;p&gt;Sometimes I get asked by other developers for help on how to track and fix a bug and, while we do some pair programming, I try to show them the process I usually follow when debugging.&lt;/p&gt;

&lt;p&gt;It’s important to understand the different strategies and tools we can use while debugging to make this a more streamlined and efficient process.&lt;/p&gt;




&lt;h1&gt;
  
  
  Understand the problem &lt;a&gt;
&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;It might sound quite obvious and even trite, but you will be surprised at how often developers try to skip this part and jump right into the issue. Before you start trying to fix something, you need to make sure you understand exactly what you’re dealing with, and can achieve that by reading and studying the errors.&lt;/p&gt;

&lt;p&gt;Reading error messages is usually the first thing to do; they can give you really good hints or even point out the place where the bug is happening. Errors can be in any form, but ideally, they would be descriptive enough to be useful during debugging.&lt;/p&gt;

&lt;p&gt;Unfortunately, that’s not always the case. I remember once I was doing a college project consisting of building a linux distro from scratch, the process was tedious, and we needed to follow a file with tons of pages to do the setup. At some point during the process, the app would just throw an “Error 2” that was not documented anywhere (not even on the web), and you had to restart the whole process from the beginning.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;make: &lt;span class="k"&gt;***&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;install&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; Error 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Whenever you face something like that, ideally there will be a stacktrace attached to the error. Unfortunately, stacktraces are not really helpful in understanding the problem, but sometimes they can point out where in the process the issue is happening, or at least lead you close to it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; node app.js

/app.js:10 &amp;lt;&lt;span class="nt"&gt;--&lt;/span&gt; Last step before issue happened
  undefinedFunction&lt;span class="o"&gt;()&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  ^

ReferenceError: undefinedFunction is not defined &amp;lt;&lt;span class="nt"&gt;--&lt;/span&gt; The error
   at thirdFunction &lt;span class="o"&gt;(&lt;/span&gt;/app.js:10:3&lt;span class="o"&gt;)&lt;/span&gt; &amp;lt;&lt;span class="nt"&gt;--&lt;/span&gt; File, line and column
   at secondFunction &lt;span class="o"&gt;(&lt;/span&gt;/app.js:6:3&lt;span class="o"&gt;)&lt;/span&gt;
   at firstFunction &lt;span class="o"&gt;(&lt;/span&gt;/app.js:2:3&lt;span class="o"&gt;)&lt;/span&gt;
   at Object.&amp;lt;anonymous&amp;gt; &lt;span class="o"&gt;(&lt;/span&gt;app.js:13:1&lt;span class="o"&gt;)&lt;/span&gt; &amp;lt;&lt;span class="nt"&gt;--&lt;/span&gt; Less helpful lines
   ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sometimes you have no messages, no codes, no stacktraces. If you understand the problem now or have nothing to work with, the next step is to reproduce the error.&lt;/p&gt;




&lt;h1&gt;
  
  
  Reproduce the error &lt;a&gt;
&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;Once you understand or at least have an idea of the problem, the next step is to try to reproduce it. &lt;/p&gt;

&lt;p&gt;To do this, you want to go to the person who reported the issue or the description (if they documented it) and see if there are specific steps they followed when they saw the error. The key here is to collect as much information as possible.&lt;/p&gt;

&lt;p&gt;Something I like to suggest to testers is to record the session so you can follow what they did step by step. It’s also good to keep developer tools like network tab and console open while debugging web applications so everything gets recorded and it’s easier to identify.&lt;/p&gt;

&lt;p&gt;It’s important to be able to reproduce the error multiple times. This will give you a better comprehension of the problem. If you’re dealing with a consistent bug or an edge case, you can decide how to approach the fix based on that.&lt;/p&gt;




&lt;h1&gt;
  
  
  Isolate the code &lt;a&gt;
&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;By this point, you should have a better idea of where the bug is coming from. Notice how we haven’t looked at the code until now. It’s easier to look at it once you understand the problem.&lt;/p&gt;

&lt;p&gt;An easy yet super useful strategy is to comment out code lines or blocks until you find what’s causing the bug. You have two options here: &lt;/p&gt;

&lt;p&gt;One, comment everything out and start uncommenting until the error happens again. This is my preferred option unless I’m super confident about where the bug is. However, depending on the code size, it can be time-consuming.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="c1"&gt;// Error stopped when running only this line&lt;/span&gt;
   &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;functionOne&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
   &lt;span class="c1"&gt;//this.functionTwo(); ----&lt;/span&gt;
   &lt;span class="c1"&gt;//this.functionThree();  | --&amp;gt; Bug can be anywhere here&lt;/span&gt;
   &lt;span class="c1"&gt;//this.functionFour(); ---&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two, if you’re feeling confident (or lucky), you can comment out the line(s) you think the bug is at and see if the error stops.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;functionOne&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
   &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;functionTwo&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
   &lt;span class="c1"&gt;//this.functionThree(); &amp;lt;-- I feel the bug can be here&lt;/span&gt;
   &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;functionFour&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;Since you already know how to reproduce the bug, you just need to start removing some lines of code and running the steps to replicate until the error stops appearing.&lt;/p&gt;




&lt;h1&gt;
  
  
  Write some tests &lt;a&gt;
&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;Last but not least, we need to make sure that the issue has been resolved and that it won’t happen again.&lt;/p&gt;

&lt;p&gt;The best way to do this is by adding the scenario to the test cases. If you want to fix it first and then add the tests or if you want to do some Test-Driven Development and write tests before the fix, is up to you.&lt;/p&gt;

&lt;p&gt;After this, you will feel more confident about the fix and you will increase the test coverage, so it is a win-win.&lt;/p&gt;




&lt;h1&gt;
  
  
  Debugging tools &lt;a&gt;
&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;No matter what your debugging process is, there are some tools you can use and combine to make your life easier. Let’s talk about some of them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Logs
&lt;/h2&gt;

&lt;p&gt;Logs are an essential part of software development. They offer detailed information about the process execution that we can use to analyze and identify the source of the issue.&lt;/p&gt;

&lt;p&gt;Logs are especially useful for reproducing errors, since you get access to all the events that happened that led to the error.&lt;/p&gt;

&lt;p&gt;It’s also important to make sure we are logging useful information. Excessive logging can make it heavy, hard to navigate and understand, and adds unnecessary noise.&lt;/p&gt;

&lt;h2&gt;
  
  
  Printing
&lt;/h2&gt;

&lt;p&gt;Depending on the language I’m working with, this is one of my preferred debugging methods. I use it with golang all the time.&lt;/p&gt;

&lt;p&gt;It’s as simple as adding some console prints in specific places in the code. I usually add some prefix to the messages so I can search them fast in the console. I use it mostly on two cases:&lt;/p&gt;

&lt;p&gt;Following the execution path, so that we know whether a specific piece of code is being called or not.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;“#######&lt;/span&gt; &lt;span class="n"&gt;I&lt;/span&gt; &lt;span class="n"&gt;am&lt;/span&gt; &lt;span class="n"&gt;on&lt;/span&gt; &lt;span class="n"&gt;method&lt;/span&gt; &lt;span class="n"&gt;X&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;Getting the value of a property at a specific moment.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;“#######&lt;/span&gt; &lt;span class="n"&gt;Value&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="n"&gt;X&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="err"&gt;”&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The downside of this method is that you need to rebuild or rerun the program if you want to change something you are printing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Debuggers
&lt;/h2&gt;

&lt;p&gt;Debuggers are a powerful tool. They allow you to go through the code line by line, giving you full control to decide when to move to the next part of the code.&lt;/p&gt;

&lt;p&gt;One of the main benefits of debuggers is that you can inspect the state of the program at any point during its execution.&lt;/p&gt;

&lt;p&gt;In a certain way, debuggers are similar to printing. You use them to know the program execution path and state. Of course, debuggers are way more powerful, and I prefer them over printing when possible.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rubberducking
&lt;/h2&gt;

&lt;p&gt;Rubber Duck Debugging (Rubberducking) is a technique that consists of explaining your code to a rubber duck or any other object. You can gain a better perspective while verbalizing your thoughts. It sounds simple and yet so effective.&lt;/p&gt;

&lt;p&gt;If you don’t feel comfortable talking to a rubber duck, or your wife is starting to think you are getting crazy, something I like to do is to explain it to another person, developer or not.&lt;/p&gt;

&lt;p&gt;I know some of you might say that sounds like pair programming, but you will see that sometimes as soon as you start explaining the issue to the other person, you realize what the problem is without them saying a word.&lt;/p&gt;

&lt;p&gt;And if it ends in being a whole conversation and a pair programming session, that is totally fine. It is another really good tool for debugging when you have tried everything without getting anywhere, and you just need a fresh pair of eyes.&lt;/p&gt;




&lt;h1&gt;
  
  
  Final thoughts &lt;a&gt;
&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;Having a streamlined process that combines different techniques, can make it easier to track bugs, find better solutions, and save you a lot of time by increasing the debugging speed.&lt;/p&gt;

&lt;p&gt;There are no techniques or tools better than others, they just fit differently depending on the problem. If you understand the problem, it would be easier to determine which tool(s) to use.&lt;/p&gt;

&lt;p&gt;It’s important to be conscious about what we log and what error messages we use while coding since that can save us time later and make the process easier.&lt;/p&gt;

&lt;p&gt;Debugging doesn’t need to be hard. The moment you start seeing it as a way to learn and improve, both the code and your skills, you will start enjoying it.&lt;/p&gt;




&lt;p&gt;Interested in working with us? Have a look at our &lt;a href="https://www.ltvco.com/careers/"&gt;careers page&lt;/a&gt; and reach out to us if you would like to be a part of our team!&lt;/p&gt;




&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--3GzqD_r0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vlmjxjyj8v33tw5wf062.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3GzqD_r0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vlmjxjyj8v33tw5wf062.png" alt="Image description" width="402" height="111"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>debugging</category>
      <category>rubberducking</category>
    </item>
    <item>
      <title>Don’t mutate state in React.js — References vs Values</title>
      <dc:creator>LTV Co. Engineering</dc:creator>
      <pubDate>Mon, 15 Jan 2024 17:28:07 +0000</pubDate>
      <link>https://dev.to/ltvengineering/dont-mutate-state-in-reactjs-references-vs-values-35cp</link>
      <guid>https://dev.to/ltvengineering/dont-mutate-state-in-reactjs-references-vs-values-35cp</guid>
      <description>&lt;h1&gt;
  
  
  In this post
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;Primitives&lt;/li&gt;
&lt;li&gt;Objects&lt;/li&gt;
&lt;li&gt;Nested State in React&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Hello! In this blog post, I am going to go over how to properly change our React.js components’ state, and why it’s important to understand JavaScript references and values. Sometimes, our states may need to contain deeply nested objects and arrays, and updating our state can sometimes be confusing and messy as a result.&lt;/p&gt;

&lt;p&gt;When we directly mutate our state in an attempt to change it, we can often leave room for unexpected side effects and bugs in our applications. But before we talk more about updating our React state, let’s go over some of the different JavaScript data types, and breakdown references and values,&lt;/p&gt;




&lt;h1&gt;
  
  
  Primitives &lt;a&gt;
&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;Primitive data types include Boolean, null , undefined , String , and Number . In JavaScript, primitive types are passed by value. This means that when we assign a variable with any of these types, that variable will be a direct container of value for the primitive data instantiation. Let’s demonstrate why this is significant.&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;let&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt;

&lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;x&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;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// =&amp;gt; 10&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;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// =&amp;gt; 5&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, we assign y the value of x so both x and y are initially equal to 5. Then we reassign y to the value of x + y . When we check the values of x and y with our console.log statements, we’ll see that y is now equal to 10, but x remains equal to 5. If primitives were passed by reference, then x would be equal to 10 like y . Let’s take a look at what this would look like for Objects!&lt;/p&gt;




&lt;h1&gt;
  
  
  Objects &lt;a&gt;
&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;Under this data type, we’ll include Array , Function , and Object . These data types are passed by** reference. **When a variable is assigned non-primitive data in JavaScript, the variable becomes a reference point to the object’s location in memory as opposed to being a direct container of value for data. Here’s a snippet to further explain the implications here:&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;let&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&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="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;

&lt;span class="nx"&gt;b&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="mi"&gt;4&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;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// =&amp;gt; [1,2,3,4]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, we assigned a an array of numbers, and we assigned b to the value of a . Because the array is a non-primitive value, both a and b point to the same array’s reference in memory. That’s why when we push a new value into b , a changes as well to reflect that push.&lt;/p&gt;




&lt;h1&gt;
  
  
  Nested State in React &lt;a&gt;
&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;Let’s say that we want to initialize some nested state for a functional component. An example can be 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="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;person&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setPerson&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;John&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;pets&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="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Fido&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;animal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dog&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;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Mr. Whiskers&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;animal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cat&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s say we want to make edits to this person state here. Here is how we SHOULD NOT update our 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="nx"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nx"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pets&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="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Polly&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;animal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;parrot&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="nx"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&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="s2"&gt;Jane&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Never do we ever want to directly mutate our state like this. Not only do these changes not trigger a rerender of our component, but they can introduce bugs in the code and UI. If we are needing to transform our state data, we should always look to make copies of our Objects before making any changes to them. For example:&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;personPetsCopy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pets&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="nx"&gt;personPetsCopy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nx"&gt;personPetsCopy&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="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Polly&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;animal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;parrot&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="nf"&gt;setPerson&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;person&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;pets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;personPetsCopy&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 also use the filter and map array methods to make copies of our arrays in state. For example, if we want to delete an object in our pets array, we can use the filter method.&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;personPetsCopy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;pet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;pet&lt;/span&gt;&lt;span class="p"&gt;.&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="s2"&gt;Fido&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;setPerson&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;person&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;pets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;personPetsCopy&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or if we want to edit one of the pets in our array, we could use the map function as well!&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;personPetsCopy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;pet&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;pet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;animal&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dog&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;pet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;doggie&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;isGoodBoy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;pet&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When mapping to make edits, also be sure to not accidentally mutate your state! A state mutation in the above example could look like:&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;personPetsCopy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;pet&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;pet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;animal&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dog&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;pet&lt;/span&gt;&lt;span class="p"&gt;.&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;doggie&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="nx"&gt;pet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isGoodBoy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;pet&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;pet&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this snippet, we are modifying the pet object in memory instead of creating a new object. As a result, this is a direct state mutation, and should be avoided.&lt;/p&gt;

&lt;p&gt;To make cloning our deeply nested objects for transformation easier, we can use the cloneDeep function that the lodash library offers.&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;personClone&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;cloneDeep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;person&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 do whatever we want to this &lt;code&gt;personClone&lt;/code&gt; without us worrying about mutating our state. And when we’re done making the changes we need, we’ll just set the clone to state as we usually would do.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;setPerson&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;personClone&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  Conclusion &lt;a&gt;
&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;Updating nested states in React can be a pain for beginners, and not doing so properly can lead to unexpected bugs. Hopefully, this article can help you write cleaner and more efficient code moving forward.&lt;/p&gt;

&lt;p&gt;If you want to learn more about the &lt;code&gt;useState&lt;/code&gt; hook in React, feel free to check out my &lt;a href="https://betterprogramming.pub/get-to-know-the-usestate-hook-in-react-js-d87797cb5a7"&gt;blog post&lt;/a&gt; detailing how to use it!&lt;/p&gt;




&lt;p&gt;Interested in working with us? Have a look at our &lt;a href="https://www.ltvco.com/careers/"&gt;careers page&lt;/a&gt; and reach out to us if you would like to be a part of our team!&lt;/p&gt;




&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Wnlhkf-Z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dzre8j8hm2psejtfqgz6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Wnlhkf-Z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dzre8j8hm2psejtfqgz6.png" alt="Image description" width="402" height="111"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>react</category>
    </item>
    <item>
      <title>When and how to write a custom React hook</title>
      <dc:creator>LTV Co. Engineering</dc:creator>
      <pubDate>Wed, 27 Sep 2023 22:27:44 +0000</pubDate>
      <link>https://dev.to/ltvengineering/when-and-how-to-write-a-custom-react-hook-4344</link>
      <guid>https://dev.to/ltvengineering/when-and-how-to-write-a-custom-react-hook-4344</guid>
      <description>&lt;h1&gt;
  
  
  In this post
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;Background: Motivating the question&lt;/li&gt;
&lt;li&gt;When to use custom hooks&lt;/li&gt;
&lt;li&gt;Extracting a custom hook&lt;/li&gt;
&lt;li&gt;Recap/TLDR&lt;/li&gt;
&lt;li&gt;Further reading&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;When you start using React, you will quickly be introduced to the idea of hooks. Perhaps, if you do not read the docs, you will not even know that you are using hooks. But chances are, in writing a react component, you will find a use case for &lt;em&gt;useState&lt;/em&gt; or &lt;em&gt;useEffect&lt;/em&gt; at the very least. &lt;/p&gt;

&lt;p&gt;This name, hooks, brings to mind the idea of lifecycle hooks that users of earlier versions of React will be familiar with, like &lt;em&gt;willComponentUpdate&lt;/em&gt;. But other than that, these mysterious functions seem to share only the prefix use, their actual functionality varying widely. &lt;/p&gt;

&lt;p&gt;Some are responsible for storing local state, some for updating it, some for accomplishing side effects, some for asynchronous activities like data fetching. If you are familiar with ember.js, you may notice that collectively, the &lt;a href="https://legacy.reactjs.org/docs/hooks-reference.html"&gt;builtin hooks&lt;/a&gt; offered by react essentially accomplish the functionality of ember’s many computed properties (among other things), with a much different interface. &lt;/p&gt;




&lt;h1&gt;
  
  
  Background: Motivating the question &lt;a&gt;
&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;As you dig around the docs, you will notice it is possible to create your own custom hooks, and indeed, that this ability seems to be heavily touted as one of the main advantages of hooks. If you are like me, you may find yourself asking: why would I want to do that? After all, at first glance, a hook seems to be no more than a function that starts with this mysterious prefix, use. &lt;/p&gt;

&lt;p&gt;Of course, there will be times when you want to encapsulate some reusable logic (the idea of helpers or utils may come to mind if you are familiar with ember), but the question remains: why encapsulate it in a hook? What benefits are conferred by using &lt;em&gt;use&lt;/em&gt;?&lt;/p&gt;




&lt;h1&gt;
  
  
  When to use custom hooks &lt;a&gt;
&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;The answer, it turns out, becomes clearer when you dig a bit deeper into the hooks docs, and in particular, when you read the &lt;a href="https://legacy.reactjs.org/docs/hooks-rules.html"&gt;rules of hooks&lt;/a&gt; section. There are, in fact, only two rules of hooks:&lt;/p&gt;

&lt;p&gt;Only call hooks at the top level (not in nested functions, loops, conditionals, etc.)&lt;br&gt;
Only call hooks from a react function component or a custom hook&lt;br&gt;
The second rule, then, gives us an idea of why we might want to write our own hooks, and in fact, gives the motivation for them: custom hooks are used to extend other hooks. In particular, they are used when the functionality that you need to reuse depends on another hook call. Since builtin hooks are used so extensively throughout a React application, this situation comes up quite often. &lt;/p&gt;

&lt;p&gt;Take, as the simplest example, the &lt;em&gt;useState&lt;/em&gt; hook. Suppose that you have several components that all need to display a particular state property. For example, a user’s name. You might use the &lt;em&gt;useState&lt;/em&gt; hook to store this value:&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="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;userName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setUserName&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;where &lt;em&gt;user&lt;/em&gt; is an application-level state object.&lt;/p&gt;

&lt;p&gt;This seems simple enough, and indeed, implementing this across multiple components would be as easy as writing the above line of code in each component. However, now suppose that the user object depends on data that is fetched asynchronously from the backend, and is not guaranteed to be populated by the time the page loads. Now, you may find yourself having to refactor your implementation to something like:&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="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;userName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setUserName&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;‘’&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nx"&gt;useEffect&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;setUserName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userName&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="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice above, you now have two separate tasks that accomplish a common goal, and you will need to reuse them across multiple components. So, encapsulation becomes attractive. And, &lt;strong&gt;because the logic that you wish to encapsulate involves react hooks, you will, by necessity, encapsulate it in a react hook, and not a plain javascript function&lt;/strong&gt;, as a result of rule 2 of hooks.&lt;/p&gt;

&lt;h3&gt;
  
  
  Point of fact:
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;React will actually allow you to break this rule without complaining, and in this simple example, it would work fine. If you use _eslint&lt;/em&gt;, and install &lt;em&gt;eslint-plugin-react-hooks&lt;/em&gt;, you will get a compiler warning or error for breaking this and the other rule, but otherwise, you would actually be able to compile and render this example just fine. An in-depth discussion of why the rules of hooks are what they are, and why you should avoid breaking them, is beyond the scope of this post, but for further reading &lt;a href="https://medium.com/@dan_abramov/this-is-a-misunderstanding-you-absolutely-can-call-hooks-from-js-functions-that-arent-94ae8f50f388"&gt;see this clarifying note from Dan Abramov&lt;/a&gt;. But, if you accept the rules of hooks proposed by the React team as law, then you will need to encapsulate this logic in a custom hook._&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h1&gt;
  
  
  Extracting a custom hook &lt;a&gt;
&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;Here is an implementation of our minimal custom hook that combines the state and effect from above:&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;function&lt;/span&gt; &lt;span class="nx"&gt;useName&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;userName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setUserName&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;‘’&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nx"&gt;useEffect&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;setUserName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userName&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="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="nx"&gt;Return&lt;/span&gt; &lt;span class="nx"&gt;userName&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;Then, in a component:&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;function&lt;/span&gt; &lt;span class="nx"&gt;SomeReactComponent&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
    &lt;span class="err"&gt;…&lt;/span&gt;
    &lt;span class="nx"&gt;Const&lt;/span&gt; &lt;span class="nx"&gt;userName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useName&lt;/span&gt;&lt;span class="p"&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;h1&gt;
  
  
  Recap/TLDR &lt;a&gt;
&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;So, there you have it, a simple heuristic and motivating example of how and when to use custom React hooks. To reiterate, &lt;strong&gt;use custom hooks when you want to encapsulate some reusable logic across different components, and the reusable logic itself involves hooks. Because hooks are so heavily ingrained in the implementation of modern React components, expect to reach for custom hooks much of the time when you need to encapsulate reusable logic.&lt;/strong&gt;&lt;/p&gt;




&lt;h1&gt;
  
  
  Further reading &lt;a&gt;
&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;At a deeper level, you could read the above note (see point of fact) and linked post, and understand that custom hooks are not magic, and are, in fact, plain javascript functions that start with the prefix use (which allows React to identify them) and contain other hooks. &lt;/p&gt;

&lt;p&gt;Furthermore, you could understand that there is technically no penalty for breaking the rules of hooks, and that they exist as helpful guidelines imposed by the React team. This knowledge will now help you understand how or when to use custom hooks, so if that is all you are after, stick to the above advice. Thanks for reading!&lt;/p&gt;




&lt;p&gt;Interested in working with us? Have a look at our &lt;a href="https://www.ltvco.com/careers/"&gt;careers page&lt;/a&gt; and reach out to us if you would like to be a part of our team!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--iVkRlQ9R--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jq2y925ouyv044vnxtp0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--iVkRlQ9R--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jq2y925ouyv044vnxtp0.png" alt="Image description" width="404" height="112"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Pair Programming: Best Practices, Tips, Benefits &amp; More</title>
      <dc:creator>LTV Co. Engineering</dc:creator>
      <pubDate>Tue, 23 May 2023 22:03:33 +0000</pubDate>
      <link>https://dev.to/ltvengineering/pair-programming-best-practices-tips-benefits-more-lfe</link>
      <guid>https://dev.to/ltvengineering/pair-programming-best-practices-tips-benefits-more-lfe</guid>
      <description>&lt;h1&gt;
  
  
  In this post
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;Motivation&lt;/li&gt;
&lt;li&gt;Our methodology&lt;/li&gt;
&lt;li&gt;Best practices&lt;/li&gt;
&lt;li&gt;Benefits&lt;/li&gt;
&lt;li&gt;Things to avoid&lt;/li&gt;
&lt;li&gt;How the DE Team reflects the LTV Core Values in the pair programming sessions&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  Motivation &lt;a&gt;
&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;This blog post will focus on the LTVco data engineering team’s pair programming practices. The data engineering team (DE) handles the transmission and transformation of data from one place to another. We would like to share our methodology for structured pair programming that this team observes and share the benefits from these sessions that we see. This team plans pair programming sessions at least twice a week. Pair programming can be helpful in the following situations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When learning a new technology or programming language to speed up the learning process. The more experienced developer can help guide the less experienced one.&lt;/li&gt;
&lt;li&gt;When working on a tight deadline to increase productivity and deliver code faster.&lt;/li&gt;
&lt;li&gt;When working on a critical or complex project with a high degree of uncertainty. Pair programming reduces the risk of errors and increases the chance of finding a solution to a problem.&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  Our methodology &lt;a&gt;
&lt;/a&gt;
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Preparation
&lt;/h2&gt;

&lt;p&gt;The first in a pair programming session is to define the pairs with a quick stand-up meeting. The pairs are matched based on the following points:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;For the pairs to work efficiently, their task needs to be well-defined.&lt;/li&gt;
&lt;li&gt;There must be a reason for them to be working together, such as working on similar tickets.&lt;/li&gt;
&lt;li&gt;We prefer to pair our Jr Engineers with Senior Engineers to facilitate knowledge transfer and training.&lt;/li&gt;
&lt;li&gt;It is important to consider if one of the pair members has more knowledge in a particular area so that they can complement each other, rather than just splitting the work between themselves and working separately.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Session
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Define what’s expected to be done in the session. Both pairs should at least discuss this.

&lt;ul&gt;
&lt;li&gt;For example, define a mini-agenda for the PP Session, define what to expect and how a result can create a bifurcation, which way is the best to go, etc.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Define the roles, who will be the navigator, and who will be the driver.

&lt;ul&gt;
&lt;li&gt;The one with the context or with more expertise about what is going to be worked on should assume the role of navigator.&lt;/li&gt;
&lt;li&gt;The navigator should be guiding the session through verbal communication.&lt;/li&gt;
&lt;li&gt;The navigator creates spaces and opportunities to encourage the analytic/creative skills of the driver and contribute to their learning instead of just providing solutions or giving instructions of what to do.&lt;/li&gt;
&lt;li&gt;The one with less context or expertise about what is going to be worked on, should assume the role of driver.&lt;/li&gt;
&lt;li&gt;The driver most of the time asks, codes and is practical.&lt;/li&gt;
&lt;li&gt;The lead is in charge of setting the session objectives, moderating the time and taking into account how much should be invested in each objective.&lt;/li&gt;
&lt;li&gt;When both pairs have similar levels of context and expertise, each one can assume a hybrid role between driver and navigator to split the job to be done, and both work at the same time.&lt;/li&gt;
&lt;li&gt;The navigator typically takes the lead of the session, but the driver can also lead.&lt;/li&gt;
&lt;li&gt;The roles might change at some point in the session based on the objectives.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;If the session is going to be 2 hours or longer, it is important to build in 10-15 minute breaks to prevent saturation..

&lt;ul&gt;
&lt;li&gt;The break time could be adjusted as needed, but it’s best to define breaks ahead of time and abide by the schedule.&lt;/li&gt;
&lt;/ul&gt;


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




&lt;h1&gt;
  
  
  Best practices &lt;a&gt;
&lt;/a&gt;
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Constant communication
&lt;/h2&gt;

&lt;p&gt;You should actively communicate with your partner at all times. The goal of a pair programming session is not to code alone, so be present and participate with your partner.&lt;/p&gt;

&lt;h2&gt;
  
  
  Role switching (when possible)
&lt;/h2&gt;

&lt;p&gt;To ensure that both programmers working in a pair are equally committed and effective, the driver and navigator should swap roles regularly. Otherwise, the navigator may quickly get bored and stop concentrating on their task, while the driver would run the risk of burnout. Frequent role-switching also makes both software developers feel equally responsible for the quality of the code they create together.&lt;/p&gt;

&lt;h1&gt;
  
  
  Benefits &lt;a&gt;
&lt;/a&gt;
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Knowledge transfer
&lt;/h2&gt;

&lt;p&gt;Teaching and knowledge transfer by an expert or senior engineer on a particular project or area can help participant(s) to go deeper into the subject matter through pair programming. This also creates the opportunity to learn not only about code but also about the workflow of the other person, the other person’s workflows, tricks, best practices for solving tasks and how to address problems.&lt;/p&gt;

&lt;h2&gt;
  
  
  Forge bonds
&lt;/h2&gt;

&lt;p&gt;Take a moment to talk about your day, your weekend and how everything is going. Encouraging pairs to have a relaxed and enjoyable time together will lead to happier employees.&lt;/p&gt;

&lt;h2&gt;
  
  
  Time management
&lt;/h2&gt;

&lt;p&gt;A task could be solved in less time thanks to the help of the pair. Also, the more experience the team gains, the higher productivity will be.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lose the fear of the unknown
&lt;/h2&gt;

&lt;p&gt;One of the biggest benefits is losing the fear of the unknown. Feeling supported raises confidence and removes anxiety. This helps a lot when training new team members.&lt;/p&gt;

&lt;h2&gt;
  
  
  Code quality improvement
&lt;/h2&gt;

&lt;p&gt;Pair programming decreases the likelihood of writing sloppy code. With two people working together as one, the output is usually more well-thought-out and organized. This is reflected as higher-quality code that is easier to maintain.&lt;/p&gt;




&lt;h1&gt;
  
  
  Things to avoid &lt;a&gt;
&lt;/a&gt;
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Overcontrol
&lt;/h2&gt;

&lt;p&gt;Overcontrol often happens when one developer is more experienced (or better versed) and tries to impose his/her point-of-view, dictate code, and strictly control the workflow. This leads to one of the pair members doing all the work and the other one just observing without participating. Overcontrol might undermine (or even eliminate) the aforementioned benefits of pair programming.&lt;/p&gt;

&lt;h2&gt;
  
  
  Distractions
&lt;/h2&gt;

&lt;p&gt;Distractions like phone notifications, messages or deliveries are always a risk, especially for remote workers. If not properly managed, the pairs may lose focus on some occasions. Be present and respectful with your partner, but also wise about how you allocate your time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Extremely long sessions
&lt;/h2&gt;

&lt;p&gt;Don’t do super long sessions that can last for hours. Take breaks and schedule time for other activities that are not programming.&lt;/p&gt;




&lt;h1&gt;
  
  
  How the DE Team reflects the LTV Core Values in the pair programming sessions &lt;a&gt;
&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SU1ikSN_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/66duqwbd14521q3exze0.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SU1ikSN_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/66duqwbd14521q3exze0.jpg" alt="LTVs Core Values" width="800" height="1236"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Try, fail, learn, repeat
&lt;/h2&gt;

&lt;p&gt;It’s rare for anything to work perfectly on the first try. In the DE team, we are used to motivating ourselves to keep pushing and trying again. Paired programming means there’s an extra set of eyes on every problem, making the troubleshooting process much easier. Working as a team, a pair can iterate, troubleshoot and adjust easily until they finally achieve success. Troubleshooting in pair programming sessions leads to two or more people learning at the same time how to face and solve a new problem. This knowledge is later shared with all the team members.&lt;/p&gt;

&lt;h2&gt;
  
  
  Teach each other to fish
&lt;/h2&gt;

&lt;p&gt;This is one of the core values and benefits of pair programming. By just promoting pair programming we enforce this core value. Besides this, we always try to focus on knowledge transfer in each of our sessions to make the most out of them.&lt;/p&gt;

&lt;h2&gt;
  
  
  No job is above or beneath you
&lt;/h2&gt;

&lt;p&gt;No matter how complex a task could be, or how little knowledge you might have about it, instead of assigning you something easier, we encourage you to face the challenge with the support of someone that can help you along the process.&lt;/p&gt;

&lt;h2&gt;
  
  
  Question everything, respectfully
&lt;/h2&gt;

&lt;p&gt;There are no wrong or bad questions. In the pair programming sessions anyone can ask anything respectfully, and the team works to create an environment where nobody feels threatened or fearful about not knowing something. If it is necessary, a member of other pairs or even someone from another team is welcome to join the session just to eliminate any doubt.&lt;/p&gt;

&lt;h2&gt;
  
  
  Be all in
&lt;/h2&gt;

&lt;p&gt;This is a value that is always present in every one of the team members. But especially in pair programming sessions we are fully committed to making the most of the opportunity due to all the benefits and how useful they are. It is always fun and motivating to work side by side with one of your co-workers!&lt;/p&gt;




&lt;p&gt;Interested in working with us? Have a look at our &lt;a href="https://www.ltvco.com/careers/"&gt;careers page&lt;/a&gt; and reach out to us if you would like to be a part of our team!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kRcSvzob--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q3zdckaud2u1rrma7oeo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kRcSvzob--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q3zdckaud2u1rrma7oeo.png" alt="Author" width="403" height="112"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>pairprogramming</category>
      <category>bestpractices</category>
      <category>programming</category>
    </item>
    <item>
      <title>How to Upgrade a Legacy API Integration</title>
      <dc:creator>LTV Co. Engineering</dc:creator>
      <pubDate>Tue, 17 Jan 2023 14:22:42 +0000</pubDate>
      <link>https://dev.to/ltvengineering/how-to-upgrade-a-legacy-api-integration-178m</link>
      <guid>https://dev.to/ltvengineering/how-to-upgrade-a-legacy-api-integration-178m</guid>
      <description>&lt;h2&gt;
  
  
  In this post
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Write tests for your legacy API integration&lt;/li&gt;
&lt;li&gt;Document request/response mappings between your legacy and modern API integrations&lt;/li&gt;
&lt;li&gt;Implement the modern API integration&lt;/li&gt;
&lt;li&gt;Enable the modern API integration&lt;/li&gt;
&lt;li&gt;Monitor the modern API integration&lt;/li&gt;
&lt;li&gt;Remove your legacy API integration&lt;/li&gt;
&lt;li&gt;Final thoughts&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;A software application typically has a lot of dependencies. These dependencies need to be upgraded in order to keep up with the latest features and security patches. This is often difficult to do in a large software application that is constantly changing, so some of these dependencies may end up becoming legacy. One of the most common types of dependencies is an API integration where the software application makes a request to an external service and the external service returns a response. This means that there’s a good chance one of your API integrations will become legacy at some point.&lt;/p&gt;

&lt;p&gt;But how exactly do you upgrade a legacy API integration? In this article, I provide a general guideline to help you along the process. This guideline is structured as a series of steps, starting with the following:&lt;/p&gt;




&lt;h2&gt;
  
  
  Write tests for your legacy API integration &lt;a&gt;
&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Before beginning the actual upgrade, make sure that your application has automated tests for your legacy API integration. These tests should simulate the API flow by stubbing API calls to send a mock request object and return a mock response object.&lt;/p&gt;

&lt;p&gt;If you don’t have any existing tests for your legacy API integration, take the time to write some. Likewise, if your tests make actual API calls, take the time to convert them to use mock data. This ensures that your existing legacy API integration is working as expected and gives you a nice fallback point in case an issue arises in the upgrade process. It also makes the rest of the upgrade process easier since you’ll be writing similar tests for your modern API integration in a future step. Once the tests are complete, we can move on to the second step.&lt;/p&gt;




&lt;h2&gt;
  
  
  Document request/response mappings between your legacy and modern API integrations &lt;a&gt;
&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;When upgrading from a legacy to a modern API integration, the request and response structures for the two integrations will likely appear very different. In particular, certain field names may have been renamed or removed entirely so it’s best to document these changes before proceeding with the actual upgrade. This is where you want to leverage the online documentation for both your legacy and modern API integrations.&lt;/p&gt;

&lt;p&gt;I like to use a spreadsheet that consists of two sheets with the following structure:&lt;/p&gt;

&lt;p&gt;One sheet is named “Request Mappings” and consists of three columns for “Legacy API Field Name,” “Modern API Field Name” and “Notes.” An example of a full request payload is also documented towards the bottom of the sheet.&lt;br&gt;
A second sheet is named “Response Mappings” and consists of the same three columns for “Legacy API Field Name,” “Modern API Field Name” and “Notes.” An example of a successful response and another example of an error response are documented towards the bottom of the sheet.&lt;br&gt;
This approach makes it easy for others to provide feedback because it organizes the changes by each individual data field while still showing the complete picture. Once you’ve documented all of the changes, we can proceed to the third step.&lt;/p&gt;


&lt;h2&gt;
  
  
  Implement the modern API integration &lt;a&gt;
&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Now it’s finally time to implement the logic for your modern API integration! The actual implementation details are specific to your integration but I like to organize them in the following manner:&lt;br&gt;
&lt;/p&gt;

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

  USE_LEGACY_API = true

  def call_api

    if USE_LEGACY_API

      call_legacy_api

    else

      call_modern_api

    end

  end

  private



  def call_legacy_api

    # implementation details for legacy api go here …

  end

  def call_modern_api

    # implementation details for modern api go here …

  end

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

&lt;/div&gt;



&lt;p&gt;I’ve done a few things here:&lt;/p&gt;

&lt;p&gt;I’ve put the implementation details for the legacy and modern APIs into two separate private methods.&lt;br&gt;
I have a single public method that clients can invoke to trigger a call to the API service.&lt;br&gt;
There is a USE_LEGACY_API boolean constant that determines whether to invoke the legacy or the modern API integration. Currently, it is set to true so we invoke the legacy API integration.&lt;br&gt;
The USE_LEGACY_API boolean constant lets us switch back and forth between the legacy and modern API integrations. Furthermore, it also makes it easier to write tests for your modern API integration. If you wrote tests for your legacy API integration back in step 1 of this guide, then you can use the same approach to write tests for your modern API integration in this step.&lt;/p&gt;

&lt;p&gt;The key takeaway from this step is that we want to implement all of the business logic and tests for the modern API integration but we do not want any clients to invoke it yet. That’s why USE_LEGACY_API is set to true. Now we’re ready to move on to the fourth step.&lt;/p&gt;


&lt;h2&gt;
  
  
  Enable the modern API integration &lt;a&gt;
&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Now we’re ready to enable the modern API Integration. This can simply be done by changing the USE_LEGACY_API constant from true to false like so:&lt;br&gt;
&lt;/p&gt;

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

  USE_LEGACY_API = false

  def call_api

    if USE_LEGACY_API

      call_legacy_api

    else

      call_modern_api

    end

  end

  private



  def call_legacy_api

    # implementation details for legacy api go here …

  end

  def call_modern_api

    # implementation details for modern api go here …

  end

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

&lt;/div&gt;



&lt;p&gt;After this, you’ll likely want to test the modern API integration in a staging environment. Once that looks good, you can deploy the change to a production environment and move on to the next step.&lt;/p&gt;




&lt;h2&gt;
  
  
  Monitor the modern API integration &lt;a&gt;
&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Now that your modern API Integration is out in production, you’ll want to monitor it to make sure no issues arise. If you do encounter any problems, then it’s best to fix them as soon as possible. If there are too many problems, you also have the option of reverting back to using the legacy API integration by switching the USE_LEGACY_API from false back to true.&lt;/p&gt;

&lt;p&gt;If the modern API integration looks like it works successfully, then we can move on to the final step.&lt;/p&gt;




&lt;h2&gt;
  
  
  Remove your legacy API integration &lt;a&gt;
&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Once your modern API integration has been running in production without encountering any issues, it’s time to remove your legacy API integration. This includes removing the legacy implementation, corresponding tests and the actual legacy library itself from your application. The final implementation should look similar to the following:&lt;br&gt;
&lt;/p&gt;

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

  def call_api

    call_modern_api

  end

  private

  def call_modern_api

     # implementation details for modern api go here …

  end

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

&lt;/div&gt;



&lt;p&gt;After all of the legacy pieces are removed, you have finally completed the upgrade process!&lt;/p&gt;




&lt;h2&gt;
  
  
  Final thoughts &lt;a&gt;
&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Congratulations! Upgrading a legacy API integration is a difficult task so I hope this guide helped you succeed. Even if that wasn’t the case, I hope I was able to put you on the right path.&lt;/p&gt;




&lt;p&gt;Interested in working with us? Have a look at our careers page and reach out to us if you would like to be a part of our team!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F61ehz44mqi9rftcn8mjt.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%2F61ehz44mqi9rftcn8mjt.png" alt="Image description" width="486" height="112"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>devmeme</category>
      <category>watercooler</category>
    </item>
    <item>
      <title>Why We Should Use Height &amp; Width Attributes on the HTML img Tag</title>
      <dc:creator>LTV Co. Engineering</dc:creator>
      <pubDate>Fri, 18 Nov 2022 21:20:54 +0000</pubDate>
      <link>https://dev.to/ltvengineering/why-we-should-use-height-width-attributes-on-the-html-img-tag-1cll</link>
      <guid>https://dev.to/ltvengineering/why-we-should-use-height-width-attributes-on-the-html-img-tag-1cll</guid>
      <description>&lt;h2&gt;
  
  
  In this post
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Things to keep in mind&lt;/li&gt;
&lt;li&gt;Context&lt;/li&gt;
&lt;li&gt;Solution&lt;/li&gt;
&lt;li&gt;Complex scenarios&lt;/li&gt;
&lt;li&gt;Final thoughts&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Things to keep in mind &lt;a&gt;
&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Before diving into the topic of this article, it is important to clarify two things: 1) Using inline CSS in HTML is considered bad practice (&lt;a href="https://dev.to/alim1496/avoid-using-inline-css-styles-5b6p"&gt;dev.to, 2021&lt;/a&gt;), and 2) inline CSS is when you use the style attribute on a specific element (&lt;a href="https://www.w3schools.com/html/html_css.asp"&gt;w3schools.com&lt;/a&gt;). Using other attributes like width and height, even if they modify the element visually, are not considered inline CSS.&lt;/p&gt;




&lt;h2&gt;
  
  
  Context &lt;a&gt;
&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Every single asset included on a page needs to be downloaded from the server to the browser. This process works in an asynchronous way, meaning that the page is rendered part by part. Because of this, if we have a very heavy asset like a high-quality image, we don’t need to wait until that image is rendered to start using the page.&lt;/p&gt;

&lt;p&gt;This process can produce a weird “jumping” effect if you combine a slow internet connection and images without using the width and height properties. This happens because the page gets new content that increases its total height, and, depending on where this new content goes, it will have to push down the already existing content.&lt;/p&gt;

&lt;p&gt;This is what the final page should look like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kPa0_wRk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tk4u2m94jpntn5ow8ixf.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kPa0_wRk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tk4u2m94jpntn5ow8ixf.jpg" alt="Image description" width="880" height="495"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But, considering how the rendering process works, this is how the page may ultimately render if we consider varying end-user internet speeds and asset sizes:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--UotCAXo8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ecgmqp8i0488exezfum5.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--UotCAXo8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ecgmqp8i0488exezfum5.jpg" alt="Image description" width="880" height="495"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What happened in the example above is that the image was loaded after the rest of the content was in place. In other words, because of the new image, the part that goes at the bottom was “pushed” down on the page.&lt;/p&gt;




&lt;h2&gt;
  
  
  Solution &lt;a&gt;
&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;The width and height attributes fix this issue by reserving the space that the image is going to require once it’s rendered. In this example, the image has 400px of both width and height, so if we use those values on those attributes (w3schools.com), we can tell the browser the space that this content is going to require before even downloading the file itself.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--dxR1nrqY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lfig3ikd8etqs4brzmun.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dxR1nrqY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lfig3ikd8etqs4brzmun.jpg" alt="Image description" width="880" height="495"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the code, it would originally have been something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;img src="orange-cat.jpg" alt="orange cat"&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Reserving the space required for the image, we would now have something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;img src="orange-cat.jpg" alt="orange cat" width="400" height="400"&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this implementation, the rendering of the image won’t push down the content below it because the space for this image is already there waiting for the asset. It is also important to mention that it is not necessary to specify the unit because the values of these properties are always in pixels.&lt;/p&gt;




&lt;h2&gt;
  
  
  Complex scenarios &lt;a&gt;
&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;he solution described above won’t cover scenarios with responsive images. To address this, it’s important to remember that CSS is going to override the width and height attribute of an image. With that in mind, we can add media queries for the resolutions that are not covered by the default case of the width and height attributes.&lt;/p&gt;

&lt;p&gt;As a result, for a mobile-first approach, this would be the HTML:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;img class="img-cat" src="img/orange-cat.jpg" alt="" width="300" height="300"&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And this would be the CSS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@media (min-width: 768px) {

   .img-cat {

   width: 500px;

   height: 500px;

   }

}

@media (min-width: 992px) {

   .img-cat {

   width: 900px;

   height: 900px;

   }

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

&lt;/div&gt;



&lt;p&gt;Note: It’s very common to use width: 100% and height: auto to create responsive images, but in this case we are illustrating a scenario that prevents the “jumping” effect on the browser when the image isn’t ready yet and we need to use specific values on some resolutions.&lt;/p&gt;




&lt;h2&gt;
  
  
  Final thoughts &lt;a&gt;
&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Using the properties width and height of the img tag is a good practice to follow and should be part of your general HTML coding practice. However, this is not a completely flawless solution that covers all possible scenarios when working with images. If you need to have responsive images, then you are going to need to include some CSS with media queries for the non-default scenarios of the image.&lt;/p&gt;

&lt;p&gt;If you happen to have the same image but with different resolutions and sizes, you could use the picture tag along with nested source and img tags This way, using CSS would be unnecessary for changing the width and height properties (&lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/picture"&gt;mdn&lt;/a&gt;). This is a completely different approach for handling images that we can cover in another article, so stay tuned!&lt;/p&gt;




&lt;p&gt;Interested in working with us? Have a look at our &lt;a href="https://www.ltvco.com/careers/"&gt;careers page&lt;/a&gt; and reach out to us if you would like to be a part of our team!&lt;/p&gt;




&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--n4-5yjl---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xzsq9t29h7vaogblfwhx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--n4-5yjl---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xzsq9t29h7vaogblfwhx.png" alt="Image description" width="486" height="112"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>css</category>
      <category>html</category>
      <category>programming</category>
    </item>
    <item>
      <title>Sass variables vs CSS custom properties</title>
      <dc:creator>LTV Co. Engineering</dc:creator>
      <pubDate>Tue, 30 Aug 2022 17:58:43 +0000</pubDate>
      <link>https://dev.to/ltvengineering/sass-variables-vs-css-custom-properties-4gfl</link>
      <guid>https://dev.to/ltvengineering/sass-variables-vs-css-custom-properties-4gfl</guid>
      <description>&lt;h2&gt;
  
  
  In this post
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Context&lt;/li&gt;
&lt;li&gt;The real difference&lt;/li&gt;
&lt;li&gt;Agnostic approach&lt;/li&gt;
&lt;li&gt;Final thoughts&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Context &lt;a&gt;
&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;In the frontend world, it’s common to talk about CSS preprocessors to get some extra tools and features that are not available with regular CSS. While there are several preprocessor options, according to &lt;a href="https://soshace.com/sass-vs-less-which-css-preprocessor-to-choose-in-2019/"&gt;recent GitHub statistics&lt;/a&gt; Sass is the most popular.&lt;/p&gt;

&lt;p&gt;As a preprocessor, Sass has many features beyond the ability to use variables like in a programming language. But, the goal of this article is to specifically compare Sass variables with regular CSS variables. Is there any difference at all? Is one better than the other? Or at least, is there a technical difference between these two options?&lt;/p&gt;




&lt;h2&gt;
  
  
  The real difference &lt;a&gt;
&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Even though Sass is more flexible in some things than regular CSS, there is something that needs to be pointed out about the use of variables: For the DOM and the CSSOM, the CSS custom properties exist, but Sass variables don’t.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--w4aimPdh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4a4ts8m7fm6rv359qwj9.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--w4aimPdh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4a4ts8m7fm6rv359qwj9.jpeg" alt="Image description" width="880" height="386"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That means it is possible to change the value of a CSS custom property with JavaScript and that is going to affect every single property using that value. But with Sass variables, this is not possible at all because the Sass variables are compiled into plain values for CSS properties where they were placed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NhXx-_dj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pv71qmy27pwncm8n673n.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NhXx-_dj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pv71qmy27pwncm8n673n.jpeg" alt="Image description" width="880" height="377"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The final product with Sass is not going to include any reference to the variables. In the example, $mainColor is not available on the CSS after the compilation. Sass variables are not converted into CSS custom properties, they are just converted into the value of the property where it was placed. As a result, to update the value of these properties it would be necessary to use JavaScript to add an extra class with the new values, or directly override the value of that element, which might not be ideal for maintainability.&lt;/p&gt;




&lt;h2&gt;
  
  
  Agnostic approach &lt;a&gt;
&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Using Sass is not an impediment to using CSS custom properties. The compiled process of Sass won’t mess around with the CSS native functionalities like the custom properties. So, it is possible to use Sass with CSS custom properties. In fact, this would be the recommended route to follow since it would allow a smooth JavaScript-CSS interaction.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4MuJ6ZV0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6930kioohhce9v9tmtju.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4MuJ6ZV0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6930kioohhce9v9tmtju.jpeg" alt="Image description" width="880" height="349"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The only downside to this approach is it does not work with discontinued or outdated browser versions that don’t support CSS custom properties.&lt;/p&gt;




&lt;h2&gt;
  
  
  Final thoughts &lt;a&gt;
&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;A CSS preprocessor will give you more tools to work with than plain CSS. This is a fact, but to revisit the questions asked at the beginning of this article, it is safe to say that: Style-wise, both options are the same. The technical difference is that CSS custom properties will be visible for the DOM, Sass variables stop existing after the compiling process.&lt;/p&gt;

&lt;p&gt;Therefore, if you plan to manipulate your styles with JavaScript which is very common in instances such as applying a light/dark switch option, you should try using CSS custom properties. It has worked out very well for us.&lt;/p&gt;




&lt;p&gt;Interested in working with us? Have a look at our &lt;a href="https://www.ltvco.com/careers/"&gt;careers page&lt;/a&gt; and reach out to us if you would like to be a part of our team!&lt;/p&gt;




&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--3BBmzQVh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b5x0s1eejqy91ssdlbdc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3BBmzQVh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b5x0s1eejqy91ssdlbdc.png" alt="Image description" width="486" height="112"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>css</category>
      <category>sass</category>
    </item>
    <item>
      <title>Integrating CI/CD into our AWS Lambda functions</title>
      <dc:creator>LTV Co. Engineering</dc:creator>
      <pubDate>Tue, 05 Jul 2022 21:04:09 +0000</pubDate>
      <link>https://dev.to/ltvengineering/integrating-cicd-into-our-aws-lambda-functions-461o</link>
      <guid>https://dev.to/ltvengineering/integrating-cicd-into-our-aws-lambda-functions-461o</guid>
      <description>&lt;h2&gt;
  
  
  In this post
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Picking the right tools&lt;/li&gt;
&lt;li&gt;Gathering everything in one place&lt;/li&gt;
&lt;li&gt;Setting up the project&lt;/li&gt;
&lt;li&gt;Shiny new features&lt;/li&gt;
&lt;li&gt;A bumpy road&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;At the Lifetime Value Company (LTV), we love to experiment and try new things. We are also constantly optimizing existing processes through a continuous loop of Try, Fail, Learn, Repeat—a Core Value at LTV.&lt;/p&gt;

&lt;p&gt;The primary responsibility of our Customer Support Operations (CSOps) team is to create and maintain software that assists Customer Support (CS) representatives with their day-to-day work, making it more manageable, efficient, and robust so we can give the best experience to our increasing customer base.&lt;/p&gt;

&lt;p&gt;As a result, the team creates and maintains proprietary tools and leverages third-party vendors, like Zendesk, Amazon Web Services (AWS) Connect and AWS Lambda. With AWS Connect, we leverage a comprehensive call center solution that our agents use to help customers. Using Lambda, we provide the underlying solutions to deliver data and real time information.&lt;/p&gt;

&lt;p&gt;We needed to scale our CS team due to our rapid growth and the volume of inquiries received by our CS team was increasing quickly over time. To assist the situation, we needed to introduce new solutions to automate some of the work done by our CS team in order to reduce their workload. In this context, we experimented with tools like AWS Connect and Lambda in an internal innovation hackathon to determine if they could help alleviate our scaling challenges.&lt;/p&gt;

&lt;p&gt;With this, we achieved a Minimum Viable Product (MVP) that solved the team’s needs at the time. But as the code and the team continued to grow, the maintenance of our functions also became more complex in the following ways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Specific functions were hard to find within our growing collection&lt;/li&gt;
&lt;li&gt;We lacked version control&lt;/li&gt;
&lt;li&gt;It was difficult to code and deploy our changes&lt;/li&gt;
&lt;li&gt;We lacked an adequate testing process&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We set the objective to enhance our Lambda functions and make the development process easier. Specifically, we were looking to centralize our source code so that developers could easily access it in a version-controlled environment, and roll out a deployment process that mirrored what we currently use for our main services. Together, this would give us a continuous integration/deployment (CI/CD) pipeline.&lt;/p&gt;




&lt;h2&gt;
  
  
  Picking the right tools &lt;a&gt;
&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;We decided to implement &lt;a href="https://www.serverless.com/"&gt;Serverless&lt;/a&gt; to hold our functions and publish them to Lambda, along with &lt;a href="https://concourse-ci.org/"&gt;Concourse&lt;/a&gt; CI to handle the deployments. We’ve used these tools in other projects, so we had good references to help with the implementation.&lt;/p&gt;




&lt;h2&gt;
  
  
  Gathering everything in one place &lt;a&gt;
&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;After discussing a proposal for the infrastructure we aimed to implement, we gathered our project needs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;We obtained a list of all the functions authored and maintained by the CSOps team.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We obtained a list of all the call center flows that use of these functions.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We created dedicated Github repositories to store and version-control each function.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We defined a workflow based on good practices, having development comfort and security while doing a change in mind.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We installed the tools.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Based on other similar projects, we implemented the following workflow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a new branch from the main branch, our production branch.&lt;/li&gt;
&lt;li&gt;Work and create atomic working commits.&lt;/li&gt;
&lt;li&gt;Open a PR against the dev branch.&lt;/li&gt;
&lt;li&gt;Ask for reviews.&lt;/li&gt;
&lt;li&gt;Cherry-pick and push to upstream dev branch when we have enough approvals.&lt;/li&gt;
&lt;li&gt;This triggers a deploy to a dev AWS account.&lt;/li&gt;
&lt;li&gt;Create a new Interactive Voice Response (IVR) basic phone flow in the dev Connect account to test the function if it doesn’t exist already.&lt;/li&gt;
&lt;li&gt;With the basic IVR phone flow, we can test it by making phone calls to the contact flow phone number.&lt;/li&gt;
&lt;li&gt;Once it works in dev, and is approved by the Quality Assurance (QA) team, we cherry-pick commits into main and push.&lt;/li&gt;
&lt;li&gt;Triggers a deployment to the AWS prod account.&lt;/li&gt;
&lt;li&gt;We QA/Test. If the function is new, we do a 10% and incremental traffic deviation to the new function. If the function already exists, we QA and monitor.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Setting up the project &lt;a&gt;
&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;The first step was to read and follow Serverless’ official documentation. Then, set up each function, one by one, using the following process:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Scaffold the project with the commands&lt;/li&gt;
&lt;li&gt;Write the config files&lt;/li&gt;
&lt;li&gt;Adapt the current Lambdas source code&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Along the way, we determined which variables were best handled as environment variables, as they could have sensitive information or could be different while testing locally.&lt;/p&gt;

&lt;p&gt;We also established which environments we would need: local, staging and production. Once we got help from the DevOps team to set up the environments and their variables, …, we could start testing our functions against our development environments. It took some time to adapt the functions again to work well with Connect, but with some help we were able to integrate everything and test our first function in a sandbox environment.&lt;/p&gt;

&lt;p&gt;After we made sure the data was correct, we could start replacing the old functions. Starting with low-risk flows, we only drove some production traffic to the new Lambda functions to detect possible issues. Fortunately, the integration process ran smoothly, and we were able to set all requests to the new Lambda functions.&lt;/p&gt;




&lt;h2&gt;
  
  
  Shiny new features &lt;a&gt;
&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;We also thought we shouldn’t be limited to the primary function, so we also added unplanned features that we like to call “developer ergonomics.” These would help the team in the development process, with the defined workflow mentioned above as an example.&lt;/p&gt;

&lt;p&gt;We wanted to improve developer ergonomics as much as possible. For instance, adding our linter/formatting tools following the company standards. Having a Serverless project allows us to easily install prettier/eslint and automate this important part of having a standard code format. Now any developer that codes in the new Lambda function can adhere to the same standards. These rules are also easy to implement when creating a new Lambda function.&lt;/p&gt;

&lt;p&gt;We also want to develop with confidence. For example, adding unit tests to the workflow to make sure we could keep a statement of the basic functionality without changing the desired outcomes. We can also be aware of what inputs the lambda functions expect.&lt;/p&gt;

&lt;p&gt;A third and essential feature added was the concept of environments. Before, we just had the production environment to make changes. Now we can develop in local, dev and production, each with its own set of environment variables in place and with its valid data set.&lt;/p&gt;




&lt;h2&gt;
  
  
  A bumpy road &lt;a&gt;
&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;As always, not everything is as easy as it seems. There were also challenges, delays and issues. For instance, adapting the functions to test them with Connect was a slow process because we had to create and modify sandbox flows and ask for help to make calls to test the toll free test phone number. Along the way, we also realized that we were using deprecated libraries as the &lt;a href="https://github.com/request/request"&gt;simple rest client&lt;/a&gt; used. The more robust Axios replaced this. Also, the code was hard to read and maintain because it used the abuse of callback functions that were partially migrated to promises with the async/await syntactic sugar. We say “partially” because AWS Connect &lt;a href="https://docs.aws.amazon.com/connect/latest/adminguide/connect-lambda-functions.html#verify-function"&gt;needs a callback&lt;/a&gt; to be executed when integrating it with the lambda functions.&lt;/p&gt;




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

&lt;p&gt;Although it took longer than anticipated, we successfully implemented a Continuous Integration/Continuous Deployment (CI/CD) process for our Lambdas. Through Github, Serverless and Concourse, we managed to have all our code and functions in their respective repositories. We developed enough configuration to deploy it to our AWS Lambda’s instances with just a “push”. We also got to add improvements to the existing code, such as removing deprecated libraries, adding unit testing and configuring a safe testing environment. Some features that we would also like to implement are migrating the functions to use Typescript, which again adds confidence to the code that we are developing.&lt;/p&gt;

&lt;p&gt;It still has room for improvements so it is far from finished, but it is a good first step towards improving our team’s needs and wellbeing. We learned a lot in the process, not only technical knowledge but also professional skills and abilities. We needed to organize our resources, collaborate with other teams and people, do research and improve our critical thinking. Following LTV’s core values, we were all in to work on this project with realistic expectations. Though we had to try, fail, learn and repeat, we did our best to deliver something valuable and we are excited to start working on our next project!&lt;/p&gt;




&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zqjMxEsh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/prv1cs0vaee99rsulanj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zqjMxEsh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/prv1cs0vaee99rsulanj.png" alt="Image description" width="486" height="112"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>coding</category>
      <category>lambda</category>
      <category>cicd</category>
    </item>
    <item>
      <title>Is It Necessary to Use Semicolons in JavaScript?</title>
      <dc:creator>LTV Co. Engineering</dc:creator>
      <pubDate>Tue, 12 Apr 2022 15:10:19 +0000</pubDate>
      <link>https://dev.to/ltvengineering/is-it-necessary-to-use-semicolons-in-javascript-57gk</link>
      <guid>https://dev.to/ltvengineering/is-it-necessary-to-use-semicolons-in-javascript-57gk</guid>
      <description>&lt;h2&gt;
  
  
  Table of Content
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;How JavaScript works&lt;/li&gt;
&lt;li&gt;When to use semicolons&lt;/li&gt;
&lt;li&gt;Final thoughts&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Let’s start with two basic but very important ideas: 1) JavaScript is a flexible language, and 2) some semicolons in JavaScript are more needed than others. JavaScript sometimes gives us so much freedom that some practices end up being “optional”, and an example of this is the use—or lack of use—of certain semicolons.&lt;/p&gt;

&lt;p&gt;To simplify the idea further, normally a missing semicolon won’t break your JavaScript code as it would in another programming language such as Java or the C family, but there’s a catch: Sometimes you can and will break your javascript code for a missing semicolon in the right (or wrong, maybe?) conditions.&lt;/p&gt;




&lt;h2&gt;
  
  
  How JavaScript works &lt;a&gt;
&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Before diving into the fun part, a.k.a “how to break your code with the correct missing semicolon,” let’s take a moment to try to better understand how JavaScript as a programming language works in the background.&lt;/p&gt;

&lt;h3&gt;
  
  
  Compiled vs Interpreted
&lt;/h3&gt;

&lt;p&gt;There are two types of programming languages: compiled and interpreted. Compiled languages need a compiler to turn written code into machine code that will be executed later. Some classic examples of this are languages such as C, C++, and Haskell. On the other side, interpreted languages such as Python or PHP (&lt;a href="https://www.freecodecamp.org/news/compiled-versus-interpreted-languages/"&gt;freecodecamp.org, 2020&lt;/a&gt;) are interpreted at runtime. Then we have JavaScript…a language that we cannot definitively classify as neither compiled nor interpreted.&lt;/p&gt;

&lt;p&gt;JavaScript defies classification because at a very technical level it is compiled before being interpreted by the browser line by line. This can be tricky to understand and agree on; some classify JavaScript as an interpreted language. For example, &lt;a href="https://web.stanford.edu/class/cs98si/slides/overview.html"&gt;this article from Stanford University&lt;/a&gt; explicitly states that “JavaScript is an interpreted language, not a compiled language,” and even the same article from freecodecamp.org referenced above classifies JavaScript as an interpreted language. Let’s not forget, however, that the code that is being interpreted by the browser was first compiled by the engine behind it. If we want to verify this information, we can reference the official V8 blog which states the following:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“With Ignition (the interpreter inside V8), V8 compiles JavaScript functions to a concise bytecode, which is between 50% to 25% the size of the equivalent baseline machine code. This bytecode is then executed by a high-performance interpreter which yields execution speeds on real-world websites close to those of code generated by V8’s existing baseline compiler.” (&lt;a href="https://v8.dev/blog/ignition-interpreter"&gt;V8 official blog, 2016&lt;/a&gt;).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;V8 is Google’s JavaScript engine on some browsers like Google Chrome (&lt;a href="https://v8.dev/docs"&gt;V8.dev&lt;/a&gt;), but if we still have some second thoughts on this whole compiled versus interpreted process, we can take a look at this illustration:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--IGFi8WHY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iqtbx6yus1pzk3yi33mt.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--IGFi8WHY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iqtbx6yus1pzk3yi33mt.jpeg" alt="Image description" width="880" height="474"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally, as we can see in the illustration, during the compile-time also happens something called “parsing”, a process that is in charge of “analyzing and converting a program into an internal format that a runtime environment can actually run” (&lt;a href="https://developer.mozilla.org/en-US/docs/Glossary/Parse"&gt;MDN Docs, 2021&lt;/a&gt;), or in other words, this is the translation from the thing we have, into the thing we need to make it work in the browser. Knowing about the step of parsing during the compilation is necessary for you to understand the exact part of the execution that deals with the missing semicolons.&lt;/p&gt;

&lt;h3&gt;
  
  
  Automatic Semicolon Insertion (ASI)
&lt;/h3&gt;

&lt;p&gt;Now that we know about the relationship between the compiling process, the parsing, and the interpretation of the code in the browser, we are ready to talk about something that happens during the parsing step called Automatic Semicolon Insertion (ASI).&lt;/p&gt;

&lt;p&gt;This process inserts semicolons in some statements in the JavaScript code when we don’t do it ourselves. To be more precise these are the statements that will be updated by the ASI (&lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar"&gt;MDN Docs, 2021&lt;/a&gt;):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Empty statement&lt;/li&gt;
&lt;li&gt;Variable statement&lt;/li&gt;
&lt;li&gt;Import &amp;amp; export&lt;/li&gt;
&lt;li&gt;Expression statements&lt;/li&gt;
&lt;li&gt;Debugger&lt;/li&gt;
&lt;li&gt;Continue, break, throw &amp;amp; return&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To clarify this idea a little bit more we can take a look at the next illustration with a few simple lines where we can see the before and after the ASI in our code:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--YLbVsjD9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jwaxfdwt36y1kxg83n6a.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--YLbVsjD9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jwaxfdwt36y1kxg83n6a.jpeg" alt="Image description" width="880" height="495"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--k7NegOzZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pa29x0t993ojdfk5ufnp.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--k7NegOzZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pa29x0t993ojdfk5ufnp.jpeg" alt="Image description" width="880" height="495"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There are three explicit rules in the JavaScript architecture for the Automatic Semicolon Insertion (&lt;a href="https://tc39.es/ecma262/#sec-rules-of-automatic-semicolon-insertion"&gt;ECMAScript, 2021&lt;/a&gt;) that we can keep in mind:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;When there is a line terminator that is not allowed.&lt;/li&gt;
&lt;li&gt;When the parser cannot parse the next line.&lt;/li&gt;
&lt;li&gt;When we have ++, –, continue, break, return, yield, yield* and module.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Again, as we can see on the documentation (&lt;a href="https://tc39.es/ecma262/#sec-rules-of-automatic-semicolon-insertion"&gt;ECMAScript, 2021&lt;/a&gt;) this is a simple way to represent and understand when the ASI works and when it does not:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SAmHn_DL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fhbx8svum8v336cfrg1o.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SAmHn_DL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fhbx8svum8v336cfrg1o.jpeg" alt="Image description" width="880" height="495"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But, if you’re still not sure about how true this is, you can reproduce it yourself on the browser’s console like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--j4ilamax--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ls9saffnz0bugzu1j6ov.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--j4ilamax--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ls9saffnz0bugzu1j6ov.jpeg" alt="Image description" width="880" height="418"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Only the first one didn’t work because of the missing semicolon that the ASI couldn’t add, but the same code with a line terminator (the code on the new line) did work because the ASI was able to fix it.&lt;/p&gt;




&lt;h2&gt;
  
  
  When to use semicolons &lt;a&gt;
&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Now that we know that JavaScript automatically adds semicolons to certain statements with a few restrictions and rules, we can—as a best practice—use semicolons after finishing statements such as variable declaration with var, let, or const, when calling a function, using ++ or –, and when using return, break or continue.&lt;/p&gt;

&lt;p&gt;Let’s wrap up the “semicolons in JavaScript” topic with some clear examples of when your code will break for a missing semicolon.&lt;/p&gt;

&lt;p&gt;Example 1:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--TYcjSoej--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/64rvkur7ku6lmtqmd3a8.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TYcjSoej--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/64rvkur7ku6lmtqmd3a8.jpeg" alt="Image description" width="880" height="352"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this case, the missing semicolon on the declaration of variable c breaks the following toString function because its value is recognized as a non declared function. We can fix this error with a semicolon in the declaration of the last variable. (&lt;a href="https://flaviocopes.com/javascript-automatic-semicolon-insertion/#:~:text=The%20JavaScript%20parser%20will%20automatically,a%20%7D%20%2C%20closing%20the%20current%20block"&gt;Flavio Copes, 2018&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--oJrYtSu5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hp9j4lzzng0xxuz1lox4.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--oJrYtSu5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hp9j4lzzng0xxuz1lox4.jpeg" alt="Image description" width="880" height="474"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Example 2:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cVJ71yRp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sn3yhkm5xzfom14pnl02.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cVJ71yRp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sn3yhkm5xzfom14pnl02.jpeg" alt="Image description" width="880" height="350"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this case, the error is with the variable c, and that’s because, for JavaScript, the last piece of code is in the same line, it looks like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--tHGHjccb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l8xfbq8bztqghpykv7um.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--tHGHjccb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l8xfbq8bztqghpykv7um.jpeg" alt="Image description" width="880" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With that being said, we’re trying to use a variable that doesn’t exist yet, and again, the way to fix this behavior is with the almighty semicolon.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--CgN_uGP9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3960t29zohzhz0v32dw6.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--CgN_uGP9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3960t29zohzhz0v32dw6.jpeg" alt="Image description" width="880" height="449"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Final thoughts &lt;a&gt;
&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;JavaScript is a very flexible language, but that doesn’t mean that we only have to put forth the minimum effort to make it work. As a best practice, we should use standard conventions within our projects, and in these particular cases, that convention should include using semicolons because even if you don’t add them, the language needs them anyway and will try—but not always succeed—to fix them with ASI.&lt;/p&gt;

&lt;p&gt;It is important to keep in mind two more things: First, it’s possible to have errors if you don’t use semicolons in your JavaScript file and try to minify or uglify it. Second, semicolons will not significantly affect the performance and size of your file (&lt;a href="https://www.youtube.com/watch?v=B4Skfqr7Dbs"&gt;Fullstack Academy, 2017&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Your code will not always break due to a missing semicolon, but contrary to popular belief, JavaScript is relying on them in the background. As developers, it is our responsibility to understand the behind-scenes process of the tool we’re using.&lt;/p&gt;




&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--rry5Wydz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yxnphlke2h5lk8avfq46.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rry5Wydz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yxnphlke2h5lk8avfq46.png" alt="Image description" width="486" height="112"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
    </item>
    <item>
      <title>Implementing an Error Factory in Go</title>
      <dc:creator>LTV Co. Engineering</dc:creator>
      <pubDate>Fri, 11 Mar 2022 21:39:43 +0000</pubDate>
      <link>https://dev.to/ltvengineering/implementing-an-error-factory-in-go-3kf3</link>
      <guid>https://dev.to/ltvengineering/implementing-an-error-factory-in-go-3kf3</guid>
      <description>&lt;h2&gt;
  
  
  Table of Content
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Handling errors in Golang&lt;/li&gt;
&lt;li&gt;Annotating errors with context information&lt;/li&gt;
&lt;li&gt;Implementing the error factory&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Errors are a key element of Golang. By understanding errors and handling them properly, you can create robust applications with the context needed to troubleshoot failures. This article will guide you through our journey creating the errwrap package, which contains a factory for standardizing error messages and improving context information using the Golang error wrapping mechanism.&lt;/p&gt;




&lt;h2&gt;
  
  
  Handling errors in Golang &lt;a&gt;
&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Golang does not provide exceptions or the conventional try/catch mechanism to handle errors. Instead, the language treats &lt;a href="https://go.dev/blog/errors-are-values"&gt;errors as values&lt;/a&gt; by exposing a built-in &lt;a href="https://pkg.go.dev/builtin#error"&gt;error&lt;/a&gt; interface to abstract this concept.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;type error interface {

    Error() string

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

&lt;/div&gt;



&lt;p&gt;That means any type that implements an &lt;code&gt;Error() string&lt;/code&gt; function can be used to represent an error condition. By convention the errors are the last return value of the functions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;type ParseError struct {

    Value           interface{}

    DestinationType string

}

func (e *ParseError) Error() string {

    return fmt.Sprintf("failed to parse '%v' as %s",

                         e.Value,

                         e.DestinationType)

}

func ParseBool(str string) (bool, error) {

    switch str {

        case "True", "true", "T", "t", "1":

            return true, nil

        case "False", "false", "F", "f", "0":

            return false, nil

        default:

            return false, &amp;amp;ParseError{Value: str, DestinationType: "bool"}

    }

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

&lt;/div&gt;



&lt;p&gt;However, instead of creating custom error types, most of the time it is enough to use the built-in &lt;a href="https://pkg.go.dev/errors#New"&gt;errors.New()&lt;/a&gt; and &lt;a href="https://pkg.go.dev/fmt#Errorf"&gt;fmt.Errorf()&lt;/a&gt; functions provided by the language standard library.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;return false, errors.New("failed to parse value as bool")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;return false, fmt.Errorf("failed to parse '%s' as bool", str)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Anyone who calls the &lt;code&gt;ParseBool()&lt;/code&gt; function will need to make sure the error is not &lt;code&gt;nil&lt;/code&gt;, keeping the happy path as left indented as possible. The most common action for errors is to annotate them with context information and escalate them until they reach a level in the function call hierarchy where they can be handled properly. For example by logging it, terminating the application with a non-zero exit code, or returning a HTTP response with a 4xx or 5xx status code.&lt;/p&gt;




&lt;h2&gt;
  
  
  Annotating errors with context information &lt;a&gt;
&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Before &lt;a href="https://go.dev/doc/go1.13#error_wrapping"&gt;Go 1.13&lt;/a&gt; was released, the way to add context to errors using the standard library was to create a new error, with a message that includes the context information and the previous error message.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dryRun, err := ParseBool(value)
if err != nil {
    return fmt.Errorf("invalid value for --dry-run flag: %v", err)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we call the previous function with a value that cannot be parsed as a boolean, for example &lt;code&gt;foo&lt;/code&gt;, then we get an error that says &lt;code&gt;invalid value for --dry-run flag: failed to parse 'foo' as bool&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The main downside to wrapping errors this way is that the original error information is lost. If we need to extract specific information about the error, or if we need to check for a specific error type, we can’t do it after it is wrapped.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;func main() {
    args, err := ParseArguments(os.Args\[1:\])
    if err != nil {
        // This type assertion is not possible, because after
        // wrapping the error its type is no longer *ParseError.
        perr, ok := err.(*ParseError)
        if ok {
        // do something with perr
        }

        log.Fatalf("Failed to parse command line arguments: %v", err)
    }
}  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This issue can be fixed by using the package &lt;a href="https://github.com/pkg/errors"&gt;https://github.com/pkg/errors&lt;/a&gt; created by Dave Cheney. It introduces a new way to wrap errors while also being able to retrieve the original error.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dryRun, err := ParseBool(value)
if err != nil {
    return errors.Wrap(err, "invalid value for --dry-run flag")
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;func main() {

    args, err := ParseArguments(os.Args\[1:\])

    if err != nil {
        perr, ok := errors.Cause(err).(*ParseError)   
        if ok {
           // do something with perr
        }

        log.Fatalf("Failed to parse command line arguments: %v", err)

    }

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

&lt;/div&gt;



&lt;p&gt;This package was widely used by the community until Go 1.13 introduced a built-in error wrapping mechanism to the standard library. It adds support to a new verb %w in the existing &lt;code&gt;fmt.Errorf()&lt;/code&gt; function to create wrapped errors. It also adds three new functions to the errors package to inspect the wrapped error (&lt;code&gt;errors.Unwrap, errors.Is, errors.As&lt;/code&gt;) .&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dryRun, err := ParseBool(value)

if err != nil {

   return fmt.Errorf("invalid value for --dry-run flag: %w", err)

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

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;func main() {

    args, err := ParseArguments(os.Args\[1:\])

    if err != nil {

        var perr *ParseError
        if errors.As(err, &amp;amp;perr) {
        // do something with perr
        }

        log.Fatalf("Failed to parse command line arguments: %v", err)

    }

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

&lt;/div&gt;






&lt;h2&gt;
  
  
  Implementing the error factory &lt;a&gt;
&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;When Go 1.13 was released, LTVCo updated our applications that were using &lt;a href="https://github.com/pkg/errors"&gt;Github pkg errors&lt;/a&gt; to start using the new functions in the “errors” package of the standard library. When doing this we noticed that much of the error handling logic in our codebase was duplicated and not standardized. We saw this as an opportunity to extract that logic to a common place, and that was how our “errwrap” package was born.&lt;/p&gt;

&lt;p&gt;One of the standards we have is that error messages must be prepended with the name of the package that creates or wraps the error. We considered this when designing the errwrap package and created a factory object. The goal is that every package has its own error factory configured with the package name, and uses that factory for all error handling performed in the package.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Factory creates and wraps errors.

type Factory struct {

    err      error

    prefix   string

    wrapping bool

}

// NewFactory creates a new error factory with a given prefix.

// The prefix will be prepended to all errors returned by the factory.

func NewFactory(prefix string) *Factory {

    return &amp;amp;Factory{prefix: fmt.Sprintf("%s: ", prefix)}

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

&lt;/div&gt;



&lt;p&gt;The first two methods exposed by the factory are &lt;code&gt;Error()&lt;/code&gt; and &lt;code&gt;Errorf()&lt;/code&gt;, which can be used to create errors using a raw error message or a format specifier.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Error behaves like errors.New() but prepends the factory prefix to the error message.

func (f *Factory) Error(text string) error {

    return errors.New(f.prefix + text)

}

// Errorf behaves like fmt.Errorf() but prepends the factory prefix to the error message.

func (f *Factory) Errorf(format string, a ...interface{}) error {

    return fmt.Errorf(f.prefix+format, a...)

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

&lt;/div&gt;



&lt;p&gt;When we started using the error factory we noticed that the error messages were not standardized. Some of them started with “failed to …” and some others started with “unable to …”, so we decided to use only “failed to …” to standardize the error messages. We added two helpers to the factory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// FailedTo returns an error with a message "failed to &amp;lt;action&amp;gt;".

func (f *Factory) FailedTo(action string) error {

    return f.Errorf("failed to %s", action)

}

// FailedTof behaves like Errorf but prepends "failed to".

func (f *Factory) FailedTof(format string, a ...interface{}) error {

    return f.Errorf("failed to "+format, a...)

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

&lt;/div&gt;



&lt;p&gt;We also noticed some common validation errors and added helpers for them too.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Nil returns an error with a message "nil &amp;lt;something&amp;gt;".

func (f *Factory) Nil(something string) error {

    return f.Errorf("nil %s", something)

}

// Empty returns an error with a message "empty &amp;lt;something&amp;gt;".

func (f *Factory) Empty(something string) error {

    return f.Errorf("empty %s", something)

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

&lt;/div&gt;



&lt;p&gt;At this point the factory has the methods and helpers for creating errors but is missing one important feature: being able to wrap them. To do this we used the builder pattern by introducing a &lt;code&gt;Wrap()&lt;/code&gt; method that receives an error and returns a derived factory which wraps the given error in all future errors created.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Wrap returns a derived Factory that wraps the given errors in all errors created.

func (f *Factory) Wrap(err error) *Factory {

    return &amp;amp;Factory{

        err:      err,

        prefix:   f.prefix,

        wrapping: true,

    }

}

// Error behaves like errors.New() but prepends the factory prefix to the error message.

func (f *Factory) Error(text string) error {

    return f.wrap(errors.New(f.prefix + text))

}

// Errorf behaves like fmt.Errorf() but prepends the factory prefix to the error message.

func (f *Factory) Errorf(format string, a ...interface{}) error {

    return f.wrap(fmt.Errorf(f.prefix+format, a...))

}

func (f *Factory) wrap(err error) error {

    if !f.wrapping {

        return err

    }

    if f.err == nil {

        return nil

    }

    return &amp;amp;wrapError{inner: f.err, outer: err}

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

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;wrapError&lt;/code&gt; is an error type which contains the error being wrapped and the context information used to wrap the error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package errwrap

import "fmt"

type wrapError struct {

    inner error

    outer error

}

func (w *wrapError) Error() string {

    return fmt.Sprintf("%v: %v", w.outer, w.inner)

}

func (w *wrapError) Unwrap() error {

    return w.inner

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

&lt;/div&gt;



&lt;p&gt;Now the error factory is complete and ready to be used.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package main

var errors = errwrap.NewFactory("main")

func main() {

    if err := run("foo", "bar"); err != nil {

        log.Println(err)

        return

    }

    log.Println("Done")

}

func run(dryRun string, verbose string) error {

    _, err := strconv.ParseBool(dryRun)

    if err != nil {

        return errors.Wrap(err).FailedTo("parse --dry-run flag")

    }

    _, err = strconv.ParseBool(verbose)

    if err != nil {

        return errors.Wrap(err).FailedTo("parse --verbose flag")

    }

    // execute application logic

    return nil

}

// output:

// main: failed to parse --dry-run flag: strconv.ParseBool: parsing "foo": invalid syntax  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By using error wrapping mechanism we were able to identify which of the flags failed to be parsed. All the code and examples used in this article are available in the following &lt;a href="https://go.dev/play/p/wRzKZWbNNVz"&gt;Go Playground&lt;/a&gt;. The errwrap package helped us to standardize our error messages between applications and improve the context information in them. In a future blog post we will discuss how to adapt this error factory to wrap multiple errors, and the use cases of that feature.&lt;/p&gt;




&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--WONshoQd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4xgow9cy6eafxxpjkc8j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WONshoQd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4xgow9cy6eafxxpjkc8j.png" alt="Image description" width="486" height="112"&gt;&lt;/a&gt; &lt;/p&gt;

</description>
      <category>go</category>
    </item>
  </channel>
</rss>
