<?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: Kevin Kimani</title>
    <description>The latest articles on DEV Community by Kevin Kimani (@kimanikevin254).</description>
    <link>https://dev.to/kimanikevin254</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%2F803047%2F2c29ab2d-915d-48ad-9bc7-2cb8914bdb5d.png</url>
      <title>DEV Community: Kevin Kimani</title>
      <link>https://dev.to/kimanikevin254</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/kimanikevin254"/>
    <language>en</language>
    <item>
      <title>Next-Level Observability with OpenTelemetry</title>
      <dc:creator>Kevin Kimani</dc:creator>
      <pubDate>Fri, 10 Apr 2026 15:35:40 +0000</pubDate>
      <link>https://dev.to/kimanikevin254/next-level-observability-with-opentelemetry-52be</link>
      <guid>https://dev.to/kimanikevin254/next-level-observability-with-opentelemetry-52be</guid>
      <description>&lt;p&gt;When something goes wrong in my applications, logging is almost always the first tool I reach for. I'll throw a few log statements at the start and end of a function, sprinkle some into the exception handlers, and I'll have a basic picture of what's happening. For simple services running on a single instance, that's usually enough; I can scroll through the log file, spot the error, and trace it back to its cause.&lt;/p&gt;

&lt;p&gt;But as my systems have grown, that same approach doesn't work. Logs pile up from multiple sources, executions start interleaving, and the error I'm staring at no longer tells me enough. I can see &lt;em&gt;that&lt;/em&gt; something failed, but I can't trace &lt;em&gt;why&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;In this tutorial, I'll walk you through how I moved beyond basic logging by instrumenting a &lt;a href="https://kotlinlang.org/docs/server-overview.html" rel="noopener noreferrer"&gt;Kotlin&lt;/a&gt; and &lt;a href="https://spring.io/projects/spring-boot" rel="noopener noreferrer"&gt;Spring Boot&lt;/a&gt; backend service with &lt;a href="https://opentelemetry.io/" rel="noopener noreferrer"&gt;OpenTelemetry&lt;/a&gt;. You'll learn how OpenTelemetry's tracing model gives you the execution context that logs alone can't provide. By the end of this guide, you'll have a working instrumented service and a clear mental model for building more observable backend systems.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Why I Needed Next-Level Observability&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Modern backend systems are rarely linear. One operation might fan out to several downstream services, retry on failure, or execute concurrently across multiple instances and threads. All of these patterns create failure modes that are genuinely hard to explain after the fact.&lt;/p&gt;

&lt;p&gt;I ran into this personally when a background job processing hundreds of records across overlapping executions started throwing errors. My logs showed the errors, but they couldn't tell me which execution each error belonged to, or whether the other concurrent executions succeeded or failed in the same way.&lt;/p&gt;

&lt;p&gt;The gap between &lt;em&gt;seeing&lt;/em&gt; an error and &lt;em&gt;understanding&lt;/em&gt; what led to it is the problem. I'd have the error message and a timestamp, but no way to connect either to the broader execution context. In a system running multiple concurrent job executions, log lines from different runs freely interleave, and thread names get recycled by the thread pool. Without a way to uniquely identify each execution, every line in my log file was an isolated fact with no reliable way to group it with others from the same run.&lt;/p&gt;

&lt;p&gt;Observability gave me a structured view of what my system did and in what order. It does this through traces, records of complete operations that carry unique identifiers. I can filter my logs by those trace identifiers and see the entire history of a specific execution, clearly. Metrics add another dimension by revealing patterns over time that no single log entry can show. Together, they transformed my debugging from guesswork into a structured investigation.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;What OpenTelemetry Provides&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;OpenTelemetry is an open-source observability framework that defines a unified model for collecting three types of signals from your applications:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://opentelemetry.io/docs/concepts/signals/traces/" rel="noopener noreferrer"&gt;&lt;strong&gt;Traces&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;:&lt;/strong&gt; represent the full lifecycle of a request or an operation as it moves through your system. A trace is made up of &lt;a href="https://opentelemetry.io/docs/concepts/signals/traces/#spans" rel="noopener noreferrer"&gt;spans&lt;/a&gt;, where each span represents a unit of work within the operation, such as an HTTP call or a background task. Each span contains a trace ID and a span ID as part of its context, where the trace ID ties back the span to its parent operation (trace) and the span ID uniquely identifies the single specific step within the operation.
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://opentelemetry.io/docs/concepts/signals/metrics/" rel="noopener noreferrer"&gt;&lt;strong&gt;Metrics&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;:&lt;/strong&gt; capture aggregated measurements over time, such as how long an operation takes and the error rates. This helps to give you a statistical view of the overall system health.
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://opentelemetry.io/docs/concepts/signals/logs/" rel="noopener noreferrer"&gt;&lt;strong&gt;Logs&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;:&lt;/strong&gt; represent discrete events that happened at a specific point in time. When correlated with trace context, logs stop being isolated entries in a file and become anchored events within a specific execution, which makes it easy to understand exactly what happened and why.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The OpenTelemetry ecosystem has three main &lt;a href="https://opentelemetry.io/docs/concepts/components/" rel="noopener noreferrer"&gt;components&lt;/a&gt;: instrumentation, the &lt;a href="https://opentelemetry.io/docs/collector/" rel="noopener noreferrer"&gt;Collector&lt;/a&gt;, and exporters. Instrumentation is how you integrate OpenTelemetry into your application, using language-specific SDKs to create spans, record metrics, and propagate context. The Collector is an optional middleware component that receives, processes, and exports telemetry data to one or more backends. Exporters are the plugins that actually send your data to a specific destination, like &lt;a href="https://prometheus.io/" rel="noopener noreferrer"&gt;Prometheus&lt;/a&gt; or &lt;a href="https://jaegertracing.io/" rel="noopener noreferrer"&gt;Jaeger&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;What made me commit to OpenTelemetry as a long-term strategy is its vendor neutrality. Before it existed, instrumentation was tightly coupled to specific vendors, and switching meant rewriting instrumentation code throughout your entire codebase. OpenTelemetry fixed that by separating instrumentation from destination; I can instrument my service once using the standard API, and then swap exporters as my infrastructure evolves.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Setting Up Next-Level Observability with OpenTelemetry&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;If you want to follow along, you'll need the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An IDE, such as &lt;a href="https://www.jetbrains.com/idea/" rel="noopener noreferrer"&gt;IntelliJ IDEA&lt;/a&gt;.
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.oracle.com/africa/java/technologies/downloads/" rel="noopener noreferrer"&gt;JDK 17 or later&lt;/a&gt; and &lt;a href="https://git-scm.com/book/en/v2/Getting-Started-Installing-Git" rel="noopener noreferrer"&gt;Git CLI&lt;/a&gt; installed on your local machine.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is a rough architecture diagram of what we'll build:&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%2Fzfmh8zudc9zfdx38l8vm.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%2Fzfmh8zudc9zfdx38l8vm.png" alt="Rough architecture diagram" width="800" height="325"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The application consists of a Spring Boot Service running in a single Java Virtual Machine (JVM). The Task Scheduler triggers the &lt;code&gt;OrderSummaryJob&lt;/code&gt; at regular intervals. The job reads orders from an embedded H2 database via Spring Data JPA, processes them, and writes summaries back to the database. The OpenTelemetry Java Agent sits within the JVM, automatically instrumenting the job and injecting trace context into the Mapped Diagnostic Context (MDC). This context flows through the log output, allowing you to correlate all logs from a single execution when multiple executions run concurrently.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Setting Up the Starter Template&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;To keep things focused on observability, I've prepared a Kotlin and Spring Boot application with a scheduled job already in place:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone &lt;span class="nt"&gt;--single-branch&lt;/span&gt; &lt;span class="nt"&gt;-b&lt;/span&gt; starter-template https://github.com/kimanikevin254/jetbrains-otel-order-summary.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open the project in your code editor.&lt;/p&gt;

&lt;p&gt;The most important file in this project is the &lt;code&gt;src/main/kotlin/com/example/order_summary/service/OrderSummaryJob.kt&lt;/code&gt;, which defines the scheduled job. The job reads orders created in the last 24 hours from an &lt;a href="https://www.h2database.com/html/main.html" rel="noopener noreferrer"&gt;H2 database&lt;/a&gt; via Spring Data repositories, processes them one by one, and writes summaries back to the DB. The job runs every five minutes using Spring's &lt;code&gt;@Scheduled&lt;/code&gt; annotation. The summaries generated by this job can later be consumed by other parts of a larger system, such as dashboards, analytic pipelines, or downstream services that need a periodic snapshot of order volume and revenue.&lt;/p&gt;

&lt;p&gt;The logging approach is straightforward and very common. You log when the job starts, log each order being processed, log if an exception occurs, and log when the job finishes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Service&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OrderSummaryJob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
   &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;orderRepository&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;OrderRepository&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;orderSummaryRepository&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;OrderSummaryRepository&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;logger&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;LoggerFactory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getLogger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;OrderSummaryJob&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;java&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

   &lt;span class="nd"&gt;@Scheduled&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fixedDelay&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;300000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// 5mins in ms&lt;/span&gt;
   &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;generateSummary&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Starting order summary job..."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

       &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;periodEnd&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;LocalDateTime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
       &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;periodStart&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;periodEnd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;minusHours&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

       &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;orders&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;orderRepository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findByCreatedAtAfter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;periodStart&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="n"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isEmpty&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
           &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"No orders found in the last 24 hours. Skipping summary generation."&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="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Found ${orders.size} orders to process"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

       &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;processedCount&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
       &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;totalAmount&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;BigDecimal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ZERO&lt;/span&gt;

       &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
           &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
               &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Processing order ${order.id} for customer ${order.customerId}..."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

               &lt;span class="c1"&gt;// Simulate processing work&lt;/span&gt;
               &lt;span class="nc"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

               &lt;span class="c1"&gt;// Simulate occasional failures&lt;/span&gt;
               &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;BigDecimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"400"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                   &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nc"&gt;RuntimeException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Order amount exceeds threshold: ${order.amount}"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
               &lt;span class="p"&gt;}&lt;/span&gt;

               &lt;span class="n"&gt;totalAmount&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;totalAmount&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
               &lt;span class="n"&gt;processedCount&lt;/span&gt;&lt;span class="p"&gt;++&lt;/span&gt;
           &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
               &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Failed to process order ${order.id}: ${e.message}"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
               &lt;span class="c1"&gt;// Continue processing other orders&lt;/span&gt;
           &lt;span class="p"&gt;}&lt;/span&gt;
       &lt;span class="p"&gt;}&lt;/span&gt;

       &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;summary&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;OrderSummary&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
           &lt;span class="n"&gt;totalOrders&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
           &lt;span class="n"&gt;totalAmount&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;totalAmount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
           &lt;span class="n"&gt;periodStart&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;periodStart&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
           &lt;span class="n"&gt;periodEnd&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;periodEnd&lt;/span&gt;
       &lt;span class="p"&gt;)&lt;/span&gt;

       &lt;span class="n"&gt;orderSummaryRepository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;summary&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
       &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Order summary job completed. Total: ${orders.size} orders, Amount $totalAmount"&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;To see it in action, run the following command in your terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./gradlew bootRun
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the application starts, you can see the logs. Execute the command &lt;code&gt;tail -f logs/order-summary.log&lt;/code&gt; in a separate terminal to stream the logs from the configured log file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2026-02-24T15:49:47.304+03:00  INFO 605417 --- [order-summary] [scheduling-1] c.e.o.service.OrderSummaryJob            : Found 12 orders to process
2026-02-24T15:49:47.305+03:00  INFO 605417 --- [order-summary] [scheduling-1] c.e.o.service.OrderSummaryJob            : Processing order 1 for customer CUST-10001...
2026-02-24T15:49:49.306+03:00  INFO 605417 --- [order-summary] [scheduling-1] c.e.o.service.OrderSummaryJob            : Processing order 3 for customer CUST-10003...
2026-02-24T15:49:51.307+03:00  INFO 605417 --- [order-summary] [scheduling-1] c.e.o.service.OrderSummaryJob            : Processing order 7 for customer CUST-10007...
2026-02-24T15:49:53.308+03:00  INFO 605417 --- [order-summary] [scheduling-1] c.e.o.service.OrderSummaryJob            : Processing order 8 for customer CUST-10008...
2026-02-24T15:49:55.308+03:00  INFO 605417 --- [order-summary] [scheduling-1] c.e.o.service.OrderSummaryJob            : Processing order 9 for customer CUST-10009...
2026-02-24T15:49:57.310+03:00 ERROR 605417 --- [order-summary] [scheduling-1] c.e.o.service.OrderSummaryJob            : Failed to process order 9: Order amount exceeds threshold: 458.23
...

2026-02-24T15:50:11.322+03:00 ERROR 605417 --- [order-summary] [scheduling-1] c.e.o.service.OrderSummaryJob            : Failed to process order 19: Order amount exceeds threshold: 427.98
2026-02-24T15:50:11.340+03:00  INFO 605417 --- [order-summary] [scheduling-1] c.e.o.service.OrderSummaryJob            : Order summary job completed. Total: 12 orders, Amount 1680.31
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The logs show clean, linear execution. Each step follows the previous, and errors are easy to associate with what was happening. This works well for infrequent, single-instance execution.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Introducing Complexity&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;As a project evolves, two changes might occur:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The business might demand near real-time visibility into the order metrics, which means that the job needs to run more frequently. Say, every five seconds instead of every five minutes.
&lt;/li&gt;
&lt;li&gt;The application may be deployed across multiple instances for high availability.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's start by running the job more frequently to see how this affects our current logging approach. To do this, open the &lt;code&gt;src/main/kotlin/com/example/order_summary/OrderSummaryApplication.kt&lt;/code&gt; file and add the following line of code to the main application class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@EnableAsync&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This enables async execution. Remember to add the following import statement to the same file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.springframework.scheduling.annotation.EnableAsync&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open the &lt;code&gt;src/main/kotlin/com/example/order_summary/service/OrderSummaryJob.kt&lt;/code&gt; file and replace &lt;code&gt;@Scheduled(fixedDelay = 300000) // 5mins&lt;/code&gt; with the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Async&lt;/span&gt;
&lt;span class="nd"&gt;@Scheduled&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fixedRate&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// 5secs in ms&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Changing from &lt;code&gt;fixedDelay&lt;/code&gt; to &lt;code&gt;fixedRate&lt;/code&gt; means the job starts every five seconds regardless of whether the previous execution has finished. Adding &lt;code&gt;@Async&lt;/code&gt; ensures that each execution runs on its own thread from Spring's task executor pool, preventing slow jobs from blocking the scheduler. This is a common pattern when scaling background jobs to handle higher throughput.&lt;/p&gt;

&lt;p&gt;Remember to add the following import statement to the same file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.springframework.scheduling.annotation.Async&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Restart the application and observe the logs. You should see 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;2026-02-24T16:17:40.469+03:00  INFO 610799 --- [order-summary] [task-1] c.e.o.service.OrderSummaryJob            : Starting order summary job...
2026-02-24T16:17:40.596+03:00  INFO 610799 --- [order-summary] [task-1] c.e.o.service.OrderSummaryJob            : Found 12 orders to process
2026-02-24T16:17:40.597+03:00  INFO 610799 --- [order-summary] [task-1] c.e.o.service.OrderSummaryJob            : Processing order 1 for customer CUST-10001...
...
2026-02-24T16:17:47.468+03:00  INFO 610799 --- [order-summary] [task-2] c.e.o.service.OrderSummaryJob            : Processing order 3 for customer CUST-10003...
2026-02-24T16:17:48.602+03:00  INFO 610799 --- [order-summary] [task-1] c.e.o.service.OrderSummaryJob            : Processing order 9 for customer CUST-10009...
2026-02-24T16:17:49.469+03:00  INFO 610799 --- [order-summary] [task-2] c.e.o.service.OrderSummaryJob            : Processing order 7 for customer CUST-10007...
2026-02-24T16:17:50.460+03:00  INFO 610799 --- [order-summary] [task-3] c.e.o.service.OrderSummaryJob            : Starting order summary job...
2026-02-24T16:17:50.472+03:00  INFO 610799 --- [order-summary] [task-3] c.e.o.service.OrderSummaryJob            : Found 12 orders to process
2026-02-24T16:17:50.473+03:00  INFO 610799 --- [order-summary] [task-3] c.e.o.service.OrderSummaryJob            : Processing order 1 for customer CUST-10001...
...
2026-02-24T16:17:54.476+03:00  INFO 610799 --- [order-summary] [task-3] c.e.o.service.OrderSummaryJob            : Processing order 7 for customer CUST-10007...
2026-02-24T16:17:54.608+03:00  INFO 610799 --- [order-summary] [task-1] c.e.o.service.OrderSummaryJob            : Processing order 14 for customer CUST-10014...
2026-02-24T16:17:55.460+03:00  INFO 610799 --- [order-summary] [task-4] c.e.o.service.OrderSummaryJob            : Starting order summary job...
2026-02-24T16:17:55.473+03:00  INFO 610799 --- [order-summary] [task-4] c.e.o.service.OrderSummaryJob            : Found 12 orders to process
2026-02-24T16:17:55.474+03:00  INFO 610799 --- [order-summary] [task-4] c.e.o.service.OrderSummaryJob            : Processing order 1 for customer CUST-10001...
2026-02-24T16:17:55.475+03:00 ERROR 610799 --- [order-summary] [task-2] c.e.o.service.OrderSummaryJob            : Failed to process order 9: Order amount exceeds threshold: 458.23
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The logs are now completely interleaved. Executions from &lt;code&gt;task-1&lt;/code&gt;, &lt;code&gt;task-2&lt;/code&gt;, and &lt;code&gt;task-3&lt;/code&gt; are all running simultaneously, processing the orders, and logging to the same output. When an error occurs, like the failure on order 9 at 16:17:55, it's not easy to figure out which job execution the log belongs to and which orders were successfully processed before the error occurred in that specific execution.&lt;/p&gt;

&lt;p&gt;You might think searching by thread name, such as &lt;code&gt;task-1&lt;/code&gt;, would solve this, but Spring's thread pool reuses threads. After &lt;code&gt;task-1&lt;/code&gt; finishes its first execution, it picks up execution 9, then execution 17, and so on. Searching by thread name now gives you mixed logs from multiple unrelated executions. In production, where multiple application instances run behind a load balancer, thread names are no longer unique across your system.&lt;/p&gt;

&lt;p&gt;This is where plain logging breaks down. I can see that something failed. I can't explain what happened leading up to it.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;A Better Solution: Adding OpenTelemetry&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;To fix the missing execution context, I wanted each job execution to be treated as a logical unit of work, with a unique trace ID attached to it. All logs emitted during that job should include that ID. Even when multiple executions run concurrently and logs interleave, I can filter by trace ID and see exactly what happened in a single run.&lt;/p&gt;

&lt;p&gt;OpenTelemetry provides &lt;a href="https://opentelemetry.io/docs/languages/java/instrumentation/#instrumentation-categories" rel="noopener noreferrer"&gt;several ways&lt;/a&gt; to instrument applications. I'll use the &lt;a href="https://opentelemetry.io/docs/zero-code/java/agent/" rel="noopener noreferrer"&gt;Java Agent&lt;/a&gt; here, which automatically instruments your application without requiring any changes to the source code. It's genuinely the path of least resistance.&lt;/p&gt;

&lt;p&gt;Let's start by downloading the agent JAR file. Execute the following commands in the project root folder to create a directory for the agent and download 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="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; agents
curl &lt;span class="nt"&gt;-L&lt;/span&gt; https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/latest/download/opentelemetry-javaagent.jar &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;-o&lt;/span&gt; agents/opentelemetry-javaagent.jar
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Verify the download using the following command:&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="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-lh&lt;/span&gt; agents/opentelemetry-javaagent.jar
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see a file around 24MB in size.&lt;/p&gt;

&lt;p&gt;Add the &lt;code&gt;agents/&lt;/code&gt; directory to your &lt;code&gt;.gitignore&lt;/code&gt; file so that the JAR file is not committed to version control. You can use the command &lt;code&gt;echo "agents/" &amp;gt;&amp;gt; .gitignore&lt;/code&gt; or add it manually.&lt;/p&gt;

&lt;p&gt;Once you've confirmed that the agent was downloaded successfully, it's time to configure it. You need to attach it to the JVM when running the application by passing it as an argument. Open the &lt;code&gt;build.gradle.kts&lt;/code&gt; file and add the following configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="n"&gt;tasks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bootRun&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="n"&gt;jvmArgs&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;listOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
       &lt;span class="s"&gt;"-javaagent:${projectDir}/agents/opentelemetry-javaagent.jar"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="s"&gt;"-Dotel.service.name=order-summary-service"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="s"&gt;"-Dotel.traces.exporter=logging"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="s"&gt;"-Dotel.metrics.exporter=none"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="s"&gt;"-Dotel.logs.exporter=none"&lt;/span&gt;
   &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's what each argument does:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;-javaagent&lt;/code&gt; tells the JVM to load the OpenTelemetry agent before your application starts
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-Dotel.service.name&lt;/code&gt; sets the name of your service in the telemetry data
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-Dotel.traces.exporter=logging&lt;/code&gt; prints trace data to the console. No external backend is needed for this guide
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-Dotel.metrics.exporter=none&lt;/code&gt; and &lt;code&gt;-Dotel.logs.exporter=none&lt;/code&gt; disable metrics and log exporting since that is outside the scope of this guide&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Lastly, you need to update the log patterns to include trace context. The OpenTelemetry agent automatically injects &lt;code&gt;trace_id&lt;/code&gt; and &lt;code&gt;span_id&lt;/code&gt; into the logging context (Mapped Diagnostic Context). To display these values in your application logs, open the &lt;code&gt;src/main/resources/application.properties&lt;/code&gt; file and add the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;logging.pattern.console&lt;span class="o"&gt;=&lt;/span&gt;%d&lt;span class="o"&gt;{&lt;/span&gt;HH:mm:ss.SSS&lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;%thread] &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;trace_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;%mdc&lt;span class="o"&gt;{&lt;/span&gt;trace_id&lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="nv"&gt;span_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;%mdc&lt;span class="o"&gt;{&lt;/span&gt;span_id&lt;span class="o"&gt;}]&lt;/span&gt; %-5level %logger&lt;span class="o"&gt;{&lt;/span&gt;36&lt;span class="o"&gt;}&lt;/span&gt; - %msg%n
logging.pattern.file&lt;span class="o"&gt;=&lt;/span&gt;%d&lt;span class="o"&gt;{&lt;/span&gt;HH:mm:ss.SSS&lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;%thread] &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;trace_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;%mdc&lt;span class="o"&gt;{&lt;/span&gt;trace_id&lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="nv"&gt;span_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;%mdc&lt;span class="o"&gt;{&lt;/span&gt;span_id&lt;span class="o"&gt;}]&lt;/span&gt; %-5level %logger&lt;span class="o"&gt;{&lt;/span&gt;36&lt;span class="o"&gt;}&lt;/span&gt; - %msg%n
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;%mdc{trace_id}&lt;/code&gt; and &lt;code&gt;%mdc{span_id}&lt;/code&gt; directives extract values from the MDC that the agent populates automatically.&lt;/p&gt;

&lt;p&gt;Now, let's restart the application and observe the logs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;17:19:43.715 [task-1] [trace_id=da673f1ec49eba77264c5912584e7183 span_id=74c708e335a974e3] INFO  c.e.o.service.OrderSummaryJob - Starting order summary job...
17:19:43.856 [task-1] [trace_id=da673f1ec49eba77264c5912584e7183 span_id=74c708e335a974e3] INFO  c.e.o.service.OrderSummaryJob - Found 12 orders to process
17:19:43.857 [task-1] [trace_id=da673f1ec49eba77264c5912584e7183 span_id=74c708e335a974e3] INFO  c.e.o.service.OrderSummaryJob - Processing order 1 for customer CUST-10001...
17:19:45.860 [task-1] [trace_id=da673f1ec49eba77264c5912584e7183 span_id=74c708e335a974e3] INFO  c.e.o.service.OrderSummaryJob - Processing order 3 for customer CUST-10003...

...

17:19:53.704 [task-3] [trace_id=4a969bbb00634e0ee36b2fbda1399d8a span_id=0a602f1a58df2f71] INFO  c.e.o.service.OrderSummaryJob - Starting order summary job...
17:19:53.715 [task-3] [trace_id=4a969bbb00634e0ee36b2fbda1399d8a span_id=0a602f1a58df2f71] INFO  c.e.o.service.OrderSummaryJob - Found 12 orders to process
17:19:53.715 [task-3] [trace_id=4a969bbb00634e0ee36b2fbda1399d8a span_id=0a602f1a58df2f71] INFO  c.e.o.service.OrderSummaryJob - Processing order 1 for customer CUST-10001...
17:19:53.868 [task-1] [trace_id=da673f1ec49eba77264c5912584e7183 span_id=74c708e335a974e3] ERROR c.e.o.service.OrderSummaryJob - Failed to process order 9: Order amount exceeds threshold: 458.23
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All logs from the first execution share the same &lt;code&gt;trace_id&lt;/code&gt; (&lt;code&gt;da673f1ec49eba77264c5912584e7183&lt;/code&gt;), while logs from the third execution have a different &lt;code&gt;trace_id&lt;/code&gt; (&lt;code&gt;4a969bbb00634e0ee36b2fbda1399d8a&lt;/code&gt;). Even though both executions are running concurrently and their logs are interleaved, you can now filter by trace ID to isolate a single execution.&lt;/p&gt;

&lt;p&gt;For example, to see logs only from the first execution, you could search for &lt;code&gt;trace_id=da673f1ec49eba77264c5912584e7183&lt;/code&gt; in a log aggregation tool such as &lt;a href="https://aws.amazon.com/cloudwatch/" rel="noopener noreferrer"&gt;Amazon CloudWatch&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;All the code used in this tutorial is available on &lt;a href="https://github.com/kimanikevin254/jetbrains-otel-order-summary" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Where to Go From Here&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Once I had trace IDs in my logs, a few next steps were obvious.&lt;/p&gt;

&lt;p&gt;For even more powerful filtering, I could add structured fields to logs for record IDs or job phases, for example, logging &lt;code&gt;order_id&lt;/code&gt; as a dedicated field alongside the trace ID, letting me query all executions that touched a specific order.&lt;/p&gt;

&lt;p&gt;I could also export logs alongside traces to an observability backend like Jaeger or Grafana, which would let me visualize the full trace as a timeline showing how long each step took and where errors occurred. The OpenTelemetry agent supports multiple backends by simply changing the exporter configuration, so I can start with logging (as we did here) and migrate to a full observability platform later without touching my instrumentation code.&lt;/p&gt;

&lt;p&gt;The same pattern works for API handlers, other background jobs, or any async work in the system. Once OpenTelemetry is in place, every part of the application automatically benefits from trace context propagation.&lt;/p&gt;

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

&lt;p&gt;Good observability isn't just about adding more logs. It's about adding structure and context to the signals your system already emits. With OpenTelemetry, I was able to turn interleaved, confusing output into isolated, queryable execution traces.&lt;/p&gt;

&lt;p&gt;Building with observability in mind changes how I think about system design. Traces reveal where boundaries should exist. Metrics show trends that make capacity planning and SLO definition more grounded in actual production behavior. And well-instrumented code is simply more readable. When every operation is traced, you think more carefully about what constitutes a meaningful unit of work, which benefits both the tools and the people reading the code later.&lt;/p&gt;

</description>
      <category>observability</category>
      <category>opentelemetry</category>
      <category>springboot</category>
      <category>kotlin</category>
    </item>
    <item>
      <title>Defensive Programming: A Guide to Building Resilient API Clients</title>
      <dc:creator>Kevin Kimani</dc:creator>
      <pubDate>Thu, 20 Nov 2025 16:23:34 +0000</pubDate>
      <link>https://dev.to/kimanikevin254/defensive-programming-a-guide-to-building-resilient-api-clients-10hj</link>
      <guid>https://dev.to/kimanikevin254/defensive-programming-a-guide-to-building-resilient-api-clients-10hj</guid>
      <description>&lt;p&gt;Imagine this: it's payday, and my system calls a payroll application programming interface (API) to process salaries. The request times out, so my client retries it. However, the initial request actually went through, but I just didn't receive the confirmation. Suddenly, every employee is double-paid, or worse, no one gets paid at all. One small glitch on the network level just turned into a very expensive mistake that can cause serious financial and compliance issues.&lt;/p&gt;

&lt;p&gt;Thankfully, defensive programming can help. Instead of assuming that everything works as expected, defensive programming involves writing API clients that anticipate failures and protect against them. Networks are unreliable, services have downtimes, and bugs happen, but a resilient client treats these as the norm, not an exception. By designing with failure in mind, you can avoid critical errors, like duplicate charges, missed payments, or cascading retries that overwhelm a service.&lt;/p&gt;

&lt;p&gt;In this guide, I'll share techniques for building resilient API clients. I show how to implement retries safely using exponential backoff and why idempotent requests are important. I illustrate these points with examples of &lt;a href="https://embedded.gusto.com/" rel="noopener noreferrer"&gt;Gusto Embedded's&lt;/a&gt; Payroll APIs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understand Why Defensive Programming Matters for API Clients
&lt;/h2&gt;

&lt;p&gt;We all know APIs don't run in perfect environments. Failures are not only possible but expected. You can see everything from transient network drops and &lt;code&gt;HTTP 500&lt;/code&gt; errors under peak load to rate-limit responses like &lt;code&gt;HTTP 429 Too Many Requests&lt;/code&gt;. Even DNS resolution failures or partial timeouts can cause requests to hang indefinitely. Even with robust infrastructure, no API can guarantee 100 percent uptime or consistency. If my API client design assumes success by default, one minor issue can break my integration and ripple through the rest of my system.&lt;/p&gt;

&lt;p&gt;In domains with high stakes like payroll, defensive programming is even more important. If retries aren't handled correctly, duplicate adjustments or repeated tax withholdings can occur, leading to inaccurate payroll results. These issues can harm trust, create compliance risks, and be costly to fix.&lt;/p&gt;

&lt;p&gt;A defensive mindset is critical to building resilient API clients. Instead of assuming every request succeeds, assume the requests may be lost, delayed, or duplicated. Design each interaction with the expectation of failure. When you plan for failure at every step, your client can keep functioning gracefully even when the API or network is unpredictable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Build Resilient API Clients Using Defensive Programming
&lt;/h2&gt;

&lt;p&gt;Resilient API clients aren't built with a single technique but through a set of practices designed to predict and contain failure.&lt;/p&gt;

&lt;h3&gt;
  
  
  Handle Failures Correctly with Retries
&lt;/h3&gt;

&lt;p&gt;Retries are the primary tool developers reach for when dealing with unreliable APIs. The idea is this: if a request fails, send it again. However, not all failures are created equal, and retrying blindly can do more harm than good.&lt;/p&gt;

&lt;h4&gt;
  
  
  Manage Transient and Permanent Failures
&lt;/h4&gt;

&lt;p&gt;Before retrying after an error, you need to decide whether you should retry or stop and fail fast. The distinction between transient and permanent failures helps guide that logic.&lt;/p&gt;

&lt;p&gt;Transient errors are faults that may resolve on their own if you try again. Examples include network timeouts, service overloads, or temporary outages in downstream systems. In HTTP, you often see status codes like &lt;a href="https://docs.gusto.com/embedded-payroll/docs/error-categories#internal_error" rel="noopener noreferrer"&gt;&lt;code&gt;500 Internal Server Error&lt;/code&gt;&lt;/a&gt;, &lt;code&gt;502 Bad Gateway&lt;/code&gt;, &lt;a href="https://docs.gusto.com/embedded-payroll/docs/error-categories#third_party_service_unavailable" rel="noopener noreferrer"&gt;&lt;code&gt;503 Service Unavailable&lt;/code&gt;&lt;/a&gt;, or even &lt;code&gt;504 Gateway Timeout&lt;/code&gt;. These are signals that the server isn't able to fulfill the request right now, but may be able to later. In these cases, retrying makes sense, provided you back off appropriately.&lt;/p&gt;

&lt;p&gt;A special case worth mentioning is &lt;a href="https://docs.gusto.com/embedded-payroll/docs/error-categories#rate_limit_exceeded" rel="noopener noreferrer"&gt;&lt;code&gt;429 Too Many Requests&lt;/code&gt;&lt;/a&gt;. This indicates that your client has hit a rate limit. While it's technically a transient error, you shouldn't retry immediately. Instead, check the &lt;code&gt;Retry-After&lt;/code&gt; header in the response (if present) and wait for the specified duration before sending another request. This ensures your client respects server limits and avoids being throttled further.&lt;/p&gt;

&lt;p&gt;Permanent errors reflect problems that can't be resolved with a retry. These include &lt;code&gt;400 Bad Request&lt;/code&gt;, &lt;code&gt;401 Unauthorized&lt;/code&gt;, &lt;a href="https://docs.gusto.com/embedded-payroll/docs/error-categories#missing_oauth_scopes" rel="noopener noreferrer"&gt;&lt;code&gt;403 Forbidden&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://docs.gusto.com/embedded-payroll/docs/error-categories#not_found" rel="noopener noreferrer"&gt;&lt;code&gt;404 Not Found&lt;/code&gt;&lt;/a&gt;, and &lt;a href="https://docs.gusto.com/embedded-payroll/docs/error-categories#duplicate_operation" rel="noopener noreferrer"&gt;&lt;code&gt;422 Unprocessable Entity&lt;/code&gt;&lt;/a&gt; due to invalid parameters. Once one of these errors is returned, retrying is futile. Instead, your client should fail fast and surface the error for intervention.&lt;/p&gt;

&lt;h4&gt;
  
  
  Prevent the Risk of Naive Retry Strategies
&lt;/h4&gt;

&lt;p&gt;Naive retry strategies can introduce new problems. If every client retries immediately after a timeout, the server can become overwhelmed by a surge of duplicate requests. Even worse, a poorly designed client can execute the same operation twice, leading to unintended side effects, like submitting the same payroll run multiple times. Error handling must go beyond simply trying again.&lt;/p&gt;

&lt;h4&gt;
  
  
  Combine Exponential Backoff with Jitter
&lt;/h4&gt;

&lt;p&gt;To avoid these pitfalls, the industry standard is to combine exponential backoff with jitter. Exponential backoff spaces out each retry by increasing the delay each time: wait one second, then two, then four, then eight, and so on. Jitter adds a random variation to these wait times, ensuring multiple clients don't retry at the same time and overwhelm the server.&lt;/p&gt;

&lt;p&gt;Here's a simple Python example showing exponential backoff with jitter when calling an API endpoint. This example uses a &lt;code&gt;GET&lt;/code&gt; request for simplicity. The same retry logic applies to &lt;code&gt;POST&lt;/code&gt;, &lt;code&gt;PUT&lt;/code&gt;, &lt;code&gt;PATCH&lt;/code&gt;, and &lt;code&gt;DELETE&lt;/code&gt; operations as well. Just make sure those operations are idempotent before retrying so that multiple attempts do not cause unintended side effects:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;random&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;make_request_with_retries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_retries&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
   &lt;span class="n"&gt;last_exception&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;

   &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;attempt&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_retries&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
       &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
           &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
               &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
               &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
                   &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;accept&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;application/json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                   &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;X-Gusto-API-Version&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2025-06-15&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                   &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;authorization&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Bearer &amp;lt;YOUR-COMPANY-API-TOKEN&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
               &lt;span class="p"&gt;},&lt;/span&gt;
               &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;
           &lt;span class="p"&gt;)&lt;/span&gt;
           &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;raise_for_status&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
           &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

       &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;exceptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RequestException&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
           &lt;span class="n"&gt;last_exception&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;

           &lt;span class="c1"&gt;# Don't retry on client errors like 400 or 401
&lt;/span&gt;           &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="mi"&gt;400&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
               &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;

           &lt;span class="c1"&gt;# Don't sleep after the last attempt
&lt;/span&gt;           &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;attempt&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;max_retries&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
               &lt;span class="n"&gt;wait_time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="n"&gt;attempt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;uniform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
               &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Retry &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;attempt&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;max_retries&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; failed: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;. Retrying in &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;wait_time&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;s...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
               &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;wait_time&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
           &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
               &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Retry &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;attempt&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;max_retries&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; failed: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;. Max retries reached.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

   &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="n"&gt;last_exception&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Max retries reached. Request failed.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Example usage:
&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;make_request_with_retries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://api.gusto-demo.com/v1/payrolls/&amp;lt;PAYROLL_UUID&amp;gt;/receipt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code attempts to &lt;a href="https://docs.gusto.com/embedded-payroll/reference/get-v1-payment-receipts-payrolls-payroll_uuid" rel="noopener noreferrer"&gt;get a single payroll receipt&lt;/a&gt; with increasing wait times between retries. Each failure triggers an exponential delay (one second, two seconds, four seconds, and so on) with a bit of randomness added (the jitter) to avoid synchronized retry attempts. If all attempts fail, it raises the last exception so that the calling code can log or handle it appropriately.&lt;/p&gt;

&lt;h3&gt;
  
  
  Handle Idempotency: Design Safe Retries
&lt;/h3&gt;

&lt;p&gt;Retries are only truly safe when they're paired with idempotency. In the context of APIs, idempotency means that a request can be executed multiple times but only produces the same outcome as the initial successful execution. It's the safeguard that prevents retries from accidentally causing duplicate side effects.&lt;/p&gt;

&lt;p&gt;In real-world systems, idempotency protects against the unpredictable behavior of networks and clients. Imagine a user submitting a payment form or signing up for an account, and their browser freezes midway. If they refresh and the client resends the same request, idempotency ensures the user isn't charged twice or created as a duplicate record (in cases where there are no unique identifiers, such as username or email).&lt;/p&gt;

&lt;p&gt;The most common way to achieve this is through a unique identifier that links all the attempts of a request to a single logical operation. The Gusto Embedded Payroll APIs support this pattern with the &lt;a href="https://docs.gusto.com/embedded-payroll/docs/idempotency" rel="noopener noreferrer"&gt;&lt;code&gt;Idempotency-Key&lt;/code&gt; header&lt;/a&gt;. When a client submits a request with an idempotency key, the server stores both the request and its result. If the client retries with the same key against the same endpoint, the server doesn't run the operation again; it simply returns the previously stored result. &lt;/p&gt;

&lt;p&gt;Version-based object management takes this a step further. For update operations, the API requires a &lt;code&gt;version&lt;/code&gt; field that helps prevent race conditions. If the resource has changed since the client's last request, the API returns a &lt;code&gt;409 Conflict&lt;/code&gt; instead of silently overwriting data. This guarantees that retries don't create conflicting state changes even under concurrent operations.&lt;/p&gt;

&lt;p&gt;This approach is clearly important in payroll systems where correctness is important. Imagine creating a payroll run for your workforce. Without an idempotency key, a retry after a timeout may be interpreted as a second payroll run, leading to employees being double-paid and the company facing compliance issues. With idempotency in place, all retries are tied back to the same logical run, so employees are paid exactly once, no matter how many times the request is retried.&lt;/p&gt;

&lt;p&gt;Here's an example of how you can send a payroll creation request with an idempotency key header to guarantee safe retries:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;uuid&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create_payroll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;company_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;idempotency_key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;payroll_data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
   &lt;span class="n"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Authorization&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Bearer &amp;lt;YOUR-COMPANY-ACCESS-TOKEN&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;accept&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;application/json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;X-Gusto-API-Version&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2025-06-15&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Content-Type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;application/json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Idempotency-Key&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;idempotency_key&lt;/span&gt;  &lt;span class="c1"&gt;# unique key for this operation,
&lt;/span&gt;   &lt;span class="p"&gt;}&lt;/span&gt;

   &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://api.gusto-demo.com/v1/companies/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;company_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/payrolls&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

   &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
       &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;payroll_data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;
   &lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;raise_for_status&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;# Example usage
&lt;/span&gt;&lt;span class="n"&gt;idempotency_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;uuid4&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="n"&gt;payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;off_cycle&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;off_cycle_reason&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Bonus&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;start_date&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2025-11-11&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;end_date&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2025-11-18&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;create_payroll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;company_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;123&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;idempotency_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;idempotency_key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;payroll_data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code sends a &lt;a href="https://docs.gusto.com/embedded-payroll/reference/post-v1-companies-company_id-payrolls" rel="noopener noreferrer"&gt;create payroll&lt;/a&gt; request to Gusto while using an idempotency key to ensure safe retries. It generates a unique key with &lt;code&gt;uuid.uuid4()&lt;/code&gt; and passes it in the &lt;code&gt;Idempotency-Key&lt;/code&gt; header so the API can recognize repeat attempts as the same operation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Implement Resilient API Client Patterns
&lt;/h3&gt;

&lt;p&gt;Once you understand retries and idempotency, the next step is to apply them consistently. Resilient API clients aren't just a collection of one-off fixes; they're built around a set of design patterns that treat reliability as a core concern. These patterns assume that every request can fail, and they put safeguards in place so those failures never compromise correctness.&lt;/p&gt;

&lt;p&gt;Building resilience also means thinking beyond a single API call. In distributed systems, dependencies can go down, networks can degrade, and partial failures can ripple across services. Robust clients use techniques, such as fallback services (&lt;em&gt;eg&lt;/em&gt; using cached data or a secondary endpoint when the primary is unavailable), graceful degradation (serving limited functionality instead of breaking completely), and circuit breakers to prevent cascading failures. Together with retries, timeouts, and idempotency, these techniques form the foundation of reliability in APIs.&lt;/p&gt;

&lt;p&gt;Here are the key patterns that guide the design of reliable API clients:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Pattern&lt;/th&gt;
&lt;th&gt;Why It Matters&lt;/th&gt;
&lt;th&gt;Example in Practice&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Treat every request as if it can fail.&lt;/td&gt;
&lt;td&gt;Networks and servers are inherently unreliable. Coding as if success is guaranteed leads to brittle integrations.&lt;/td&gt;
&lt;td&gt;Always implement timeouts, retries, and error handling logic.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ensure critical operations are idempotent.&lt;/td&gt;
&lt;td&gt;Without idempotency, retries can trigger duplicate side effects, like double payments.&lt;/td&gt;
&lt;td&gt;Use an &lt;code&gt;Idempotency-Key&lt;/code&gt; (or equivalent identifier) to safely retry operations. For example, Gusto supports this through the &lt;code&gt;Idempotency-Key&lt;/code&gt; header.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Monitor and log retry behavior.&lt;/td&gt;
&lt;td&gt;Silent retries hide systemic issues. Visibility is needed for debugging and capacity planning.&lt;/td&gt;
&lt;td&gt;Record retry attempts and their outcomes in your client logs.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Back off intelligently.&lt;/td&gt;
&lt;td&gt;Immediate retries amplify the load and risk further failure. Exponential backoff with jitter smooths traffic spikes.&lt;/td&gt;
&lt;td&gt;Retry requests with increasing wait times and randomized delays.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fail fast on permanent errors.&lt;/td&gt;
&lt;td&gt;Retrying invalid requests wastes resources and delays recovery.&lt;/td&gt;
&lt;td&gt;Stop retries when the API returns &lt;code&gt;4xx&lt;/code&gt; client errors like &lt;code&gt;401 Unauthorized&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;When applied together, these patterns transform an integration from fragile to dependable. Instead of breaking down under real-world conditions, the client absorbs failures, retries safely, and communicates clearly when something is wrong.&lt;/p&gt;

&lt;h3&gt;
  
  
  Optimistic Version Control
&lt;/h3&gt;

&lt;p&gt;Another method of ensuring data integrity is utilizing optimistic version control. Object-based versions—essentially snapshots of a given resource—are used to process concurrent updates correctly, ensuring data integrity in a multi-user environment. It is a form of optimistic concurrency control, where the system 'assumes' that conflicts are rare and only checks for them at the time of an update.&lt;/p&gt;

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

&lt;p&gt;Building resilient API clients means embracing the reality that things fail: networks drop, servers timeout, and dependencies falter. You need to anticipate these failures—handle retries with exponential backoff and make requests idempotent so developers can ensure their integrations behave predictably, even under stress.&lt;/p&gt;

</description>
      <category>defensiveprogramming</category>
      <category>api</category>
      <category>apiclients</category>
      <category>programming</category>
    </item>
    <item>
      <title>JS Solutions for CodeWars Katas: Part 2</title>
      <dc:creator>Kevin Kimani</dc:creator>
      <pubDate>Tue, 24 May 2022 06:05:33 +0000</pubDate>
      <link>https://dev.to/kimanikevin254/js-solutions-for-codewars-katas-part-2-30bm</link>
      <guid>https://dev.to/kimanikevin254/js-solutions-for-codewars-katas-part-2-30bm</guid>
      <description>&lt;p&gt;1.Write an algorithm that takes an array and moves all of the zeros to the end, preserving the order of the other elements.&lt;/p&gt;

&lt;p&gt;moveZeros([false,1,0,1,2,0,1,3,"a"]) // returns[false,1,1,2,1,3,"a",0,0]&lt;/p&gt;

&lt;p&gt;My solution:&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;moveZeros&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;arr&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;arr&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;num&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;num&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;arr&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;num&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;num&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Long version:&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="nf"&gt;moveZeros&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;)&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;zerosArr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;arr&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;num&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;num&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;nonZerosArr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;arr&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;num&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;num&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="mi"&gt;0&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;nonZerosArr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;zerosArr&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;2.Write a function that accepts an array of 10 integers (between 0 and 9), that returns a string of those numbers in the form of a phone number.&lt;/p&gt;

&lt;p&gt;Example&lt;br&gt;
createPhoneNumber([1, 2, 3, 4, 5, 6, 7, 8, 9, 0]) // =&amp;gt; returns "(123) 456-7890"&lt;br&gt;
The returned format must be correct in order to complete this challenge.&lt;br&gt;
Don't forget the space after the closing parentheses!&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;createPhoneNumber&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;numbers&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
   &lt;span class="s2"&gt;`(&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;) &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&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="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;-&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>javascript</category>
      <category>challenge</category>
      <category>programming</category>
      <category>webdev</category>
    </item>
    <item>
      <title>JS Solutions for CodeWars Katas</title>
      <dc:creator>Kevin Kimani</dc:creator>
      <pubDate>Sun, 22 May 2022 14:42:02 +0000</pubDate>
      <link>https://dev.to/kimanikevin254/js-solutions-for-codewars-katas-5532</link>
      <guid>https://dev.to/kimanikevin254/js-solutions-for-codewars-katas-5532</guid>
      <description>&lt;p&gt;In this article I will be documenting the solutions for codewars challenge questions that I am able to solve:&lt;/p&gt;

&lt;p&gt;1.Your task is to sum the differences between consecutive pairs in the array in descending order.&lt;/p&gt;

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

&lt;p&gt;[2, 1, 10]  -&amp;gt;  9&lt;br&gt;
In descending order: [10, 2, 1]&lt;/p&gt;

&lt;p&gt;Sum: (10 - 2) + (2 - 1) = 8 + 1 = 9&lt;/p&gt;

&lt;p&gt;If the array is empty or the array has only one element the result should be 0 ( Nothing in Haskell ).&lt;/p&gt;

&lt;p&gt;My solution:&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="nf"&gt;sumOfDifferences&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;&lt;span class="k"&gt;return&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="p"&gt;});&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;diff&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
  &lt;span class="k"&gt;for&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;i&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="nx"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="nx"&gt;diff&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;diff&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;diff&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;2.A square of squares&lt;br&gt;
You like building blocks. You especially like building blocks that are squares. And what you even like more, is to arrange them into a square of square building blocks!&lt;/p&gt;

&lt;p&gt;However, sometimes, you can't arrange them into a square. Instead, you end up with an ordinary rectangle! Those blasted things! If you just had a way to know, whether you're currently working in vain… Wait! That's it! You just have to check if your number of building blocks is a perfect square.&lt;/p&gt;

&lt;p&gt;Task&lt;br&gt;
Given an integral number, determine if it's a square number:&lt;/p&gt;

&lt;p&gt;In mathematics, a square number or perfect square is an integer that is the square of an integer; in other words, it is the product of some integer with itself.&lt;/p&gt;

&lt;p&gt;The tests will always use some integral number, so don't worry about that in dynamic typed languages.&lt;/p&gt;

&lt;p&gt;Examples&lt;br&gt;
-1  =&amp;gt;  false&lt;br&gt;
 0  =&amp;gt;  true&lt;br&gt;
 3  =&amp;gt;  false&lt;br&gt;
 4  =&amp;gt;  true&lt;br&gt;
25  =&amp;gt;  true&lt;br&gt;
26  =&amp;gt;  false&lt;/p&gt;

&lt;p&gt;My solution:&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;var&lt;/span&gt; &lt;span class="nx"&gt;isSquare&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&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;n&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&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;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sqrt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)){&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&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;Refactored solution:&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;var&lt;/span&gt; &lt;span class="nx"&gt;isSquare&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sqrt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;3.Implement a function that adds two numbers together and returns their sum in binary. The conversion can be done before, or after the addition.&lt;/p&gt;

&lt;p&gt;The binary number returned should be a string.&lt;/p&gt;

&lt;p&gt;Examples:(Input1, Input2 --&amp;gt; Output (explanation)))&lt;/p&gt;

&lt;p&gt;1, 1 --&amp;gt; "10" (1 + 1 = 2 in decimal or 10 in binary)&lt;br&gt;
5, 9 --&amp;gt; "1110" (5 + 9 = 14 in decimal or 1110 in binary)&lt;/p&gt;

&lt;p&gt;My solution:&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="nf"&gt;addBinary&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toString&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;4.Given an array of integers, find the one that appears an odd number of times.&lt;/p&gt;

&lt;p&gt;There will always be only one integer that appears an odd number of times.&lt;/p&gt;

&lt;p&gt;Examples&lt;br&gt;
[7] should return 7, because it occurs 1 time (which is odd).&lt;br&gt;
[0] should return 0, because it occurs 1 time (which is odd).&lt;br&gt;
[1,1,2] should return 2, because it occurs 1 time (which is odd).&lt;br&gt;
[0,1,0,1,0] should return 0, because it occurs 3 times (which is odd).&lt;br&gt;
[1,2,2,3,3,3,4,3,3,3,2,2,1] should return 4, because it appears 1 time (which is odd).&lt;/p&gt;

&lt;p&gt;My solution:&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="nf"&gt;findOdd&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="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;

  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;element&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;A&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;property&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;property&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;parseInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;property&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;5.Make a program that filters a list of strings and returns a list with only your friends name in it.&lt;/p&gt;

&lt;p&gt;If a name has exactly 4 letters in it, you can be sure that it has to be a friend of yours! Otherwise, you can be sure he's not...&lt;/p&gt;

&lt;p&gt;Ex: Input = ["Ryan", "Kieran", "Jason", "Yous"], Output = ["Ryan", "Yous"]&lt;/p&gt;

&lt;p&gt;i.e.&lt;/p&gt;

&lt;p&gt;friend ["Ryan", "Kieran", "Mark"] &lt;code&gt;shouldBe&lt;/code&gt; ["Ryan", "Mark"]&lt;br&gt;
Note: keep the original order of the names in the output.&lt;/p&gt;

&lt;p&gt;My solution:&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;friend&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;friends&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;friends&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;friend&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;friend&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>challenge</category>
    </item>
    <item>
      <title>How to Rotate a String in JavaScript</title>
      <dc:creator>Kevin Kimani</dc:creator>
      <pubDate>Sun, 22 May 2022 09:10:59 +0000</pubDate>
      <link>https://dev.to/kimanikevin254/rotate-a-string-in-javascript-2and</link>
      <guid>https://dev.to/kimanikevin254/rotate-a-string-in-javascript-2and</guid>
      <description>&lt;p&gt;Recently, I applied a job in a certain company that was hiring a React developer. I sent my CV, did a coding assessment and passed. After this I was invited for an in-person interview where I was required to write code on paper.&lt;/p&gt;

&lt;p&gt;The coding problem was: &lt;strong&gt;write code in the programming language of your choice that rotates a given string a specified number of times&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;At first I freaked out as I had not tackled such a problem before, keep in mind that I am not a guru. I took the pen and paper and started writing code.&lt;/p&gt;

&lt;p&gt;After struggling for a few minutes, I was able to write code for positive number rotation but I didn't know that they also required the code to also handle negative number rotation and my time was up. &lt;/p&gt;

&lt;p&gt;Anyway, I was able to solve the negative rotation part in my mind on my way home and I want to share it here in case you ever encounter such a problem.&lt;/p&gt;

&lt;p&gt;Here's is the JS code to rotate a string(handles both left and right rotation):&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;rotate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;n&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;txtArr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 

  &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="k"&gt;for&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;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&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;firstel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;txtArr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="nx"&gt;txtArr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;shift&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="nx"&gt;txtArr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;firstel&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;else&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;n&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="k"&gt;for&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;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;--&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;lastel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;txtArr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;txtArr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="nx"&gt;txtArr&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;txtArr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unshift&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lastel&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;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;txtArr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;rotate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hello&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Code explanation:
&lt;/h3&gt;

&lt;p&gt;I will explain the code with the steps involved:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Convert the text into an array using the &lt;code&gt;text.split()&lt;/code&gt; method.&lt;/li&gt;
&lt;li&gt;Use an &lt;code&gt;if&lt;/code&gt; statement to check whether &lt;code&gt;n&lt;/code&gt; is positive, &lt;code&gt;n&amp;gt;0&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;If &lt;code&gt;n&lt;/code&gt; is positive:&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;use a &lt;code&gt;for&lt;/code&gt; loop to loop through the &lt;code&gt;textArr&lt;/code&gt; &lt;code&gt;n&lt;/code&gt; times.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;get the first element in the array using &lt;code&gt;txtArr[0]&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Remove the first array element using &lt;code&gt;txtArr.shift()&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Add the first array element to the end of the aaray using &lt;code&gt;txtArr.push(firstel)&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;4.If &lt;code&gt;n&lt;/code&gt; is negative:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;use a &lt;code&gt;for&lt;/code&gt; loop to loop through the &lt;code&gt;textArr&lt;/code&gt; &lt;code&gt;n&lt;/code&gt; times.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;get the last element in the array using &lt;code&gt;txtArr[txtArr.length - 1]&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Remove the last array element using &lt;code&gt;txtArr.pop()&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Add the last array element to the beginning of the aaray using &lt;code&gt;txtArr.unshift(lastel)&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;5.If &lt;code&gt;n&lt;/code&gt; is equal to 0, return it as it is&lt;/p&gt;

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

&lt;p&gt;That's all for this article. Hope you learn a thing or two. See you in the next one :)&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>beginners</category>
      <category>interview</category>
      <category>programming</category>
    </item>
    <item>
      <title>HTML For Beginners: Cool Stuff You Can Do With HTML Only</title>
      <dc:creator>Kevin Kimani</dc:creator>
      <pubDate>Wed, 02 Mar 2022 07:34:47 +0000</pubDate>
      <link>https://dev.to/kimanikevin254/html-for-beginners-cool-stuff-you-can-do-with-html-only-3lgm</link>
      <guid>https://dev.to/kimanikevin254/html-for-beginners-cool-stuff-you-can-do-with-html-only-3lgm</guid>
      <description>&lt;p&gt;Hey there web developer. Hope you doing good. In this short article we will take a look at a few cool things that you can actually achieve with HTML only. I'll try to keep this article short and brief. Lets jump right into it!&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Creating an Accordion with HTML only.
&lt;/h3&gt;

&lt;p&gt;Yap! This is possible. An accordion is mostly used in FAQ section of a website. Let's take a look at simple code snippet we can use to create this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;details&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;I am an accordion&lt;span class="nt"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;I am the accordion body. Lorem ipsum dolor sit amet consectetur adipisicing elit. Reiciendis fugiat quia provident cum laudantium nobis minus magni a ex officia! Ab ex nemo tenetur nihil?&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/details&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Progress Bar with HTML only.
&lt;/h3&gt;

&lt;p&gt;This is mostly used by developers in their portfolios to show their their level of expertise in a certain field as a percentage. Below is a code snippet for achieving this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"progressBar"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Web Dev: &lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;progress&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"progressBar"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"95"&lt;/span&gt; &lt;span class="na"&gt;max=&lt;/span&gt;&lt;span class="s"&gt;"100"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/progress&amp;gt;&amp;lt;span&amp;gt;&lt;/span&gt; 95% &lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Autocomplete with HTML only.
&lt;/h3&gt;

&lt;p&gt;Autocomplete is a feature in which an application predicts the rest of a word a user is typing. Let's see how we can achieve this. As you type in the provided input field, you will see a list of the options defined in the &lt;code&gt;datalist&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;list=&lt;/span&gt;&lt;span class="s"&gt;"programmingLanguages"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;datalist&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"programmingLanguages"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;option&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"JavaScript"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;option&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"Python"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;option&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"PHP"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/datalist&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Color Picker with HTML only.
&lt;/h3&gt;

&lt;p&gt;This is self explanatory. It is used to pick a color 😂. After picking a color, it gives you the option of picking a colors &lt;code&gt;rgb&lt;/code&gt;, &lt;code&gt;hex&lt;/code&gt; or &lt;code&gt;hsl&lt;/code&gt; value. To set a default color that is not black you just need to specify the &lt;code&gt;value&lt;/code&gt; attribute. Let's see how we can achieve this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"colorPicker"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Select a color: &lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"color"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"colorPicker"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"colorPicker"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"#ff0000"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  5. Simple Calculator with HTML only.
&lt;/h3&gt;

&lt;p&gt;This has some JavaScript but its pretty basic and beginner friendly. And of course I wanted to include it in this list 😁. All the JavaScript in this code snippet does is just convert the value entered by the user from a &lt;code&gt;string&lt;/code&gt; to an &lt;code&gt;integer&lt;/code&gt; Let's take a look at how we can do it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;oninput=&lt;/span&gt;&lt;span class="s"&gt;"result.value=parseInt(a.value)+parseInt(b.value)"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"number"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"b"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"b"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"10"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt; +
      &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"number"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"a"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"a"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"10"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt; =
      &lt;span class="nt"&gt;&amp;lt;output&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"result"&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"a b"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;20&lt;span class="nt"&gt;&amp;lt;/output&amp;gt;&lt;/span&gt;
 &lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;And that is all for this article my friends. Hope you enjoyed it and learn a few things. See you in the next one. Peace out!✌️&lt;/p&gt;

</description>
      <category>html</category>
      <category>webdev</category>
      <category>beginners</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
