<?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: Sankararaman K</title>
    <description>The latest articles on DEV Community by Sankararaman K (@sankararaman).</description>
    <link>https://dev.to/sankararaman</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%2F1935105%2F615dbdd4-f672-4b0a-8486-d17dca3ccb92.jpg</url>
      <title>DEV Community: Sankararaman K</title>
      <link>https://dev.to/sankararaman</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sankararaman"/>
    <language>en</language>
    <item>
      <title>Streamlining Exception Handling in Spring Boot</title>
      <dc:creator>Sankararaman K</dc:creator>
      <pubDate>Thu, 20 Feb 2025 08:48:15 +0000</pubDate>
      <link>https://dev.to/sankararaman/streamlining-exception-handling-in-spring-boot-bn3</link>
      <guid>https://dev.to/sankararaman/streamlining-exception-handling-in-spring-boot-bn3</guid>
      <description>&lt;p&gt;Have you ever found yourself wrestling with a tangled web of &lt;code&gt;try-catch&lt;/code&gt; blocks scattered across your Controller, Service, and Repository layers?  It's a common problem, and while seemingly innocuous, it can lead to maintenance headaches, violate Single Responsibility Principle (SRP), and introduce redundant code. Let's explore a cleaner, more efficient approach to exception handling in Java.&lt;/p&gt;

&lt;p&gt;Consider this typical, yet problematic, example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@RestController&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AuthController&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@PostMapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/login"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;ResponseEntity&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;loginUser&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@RequestBody&lt;/span&gt; &lt;span class="nc"&gt;LoginRequest&lt;/span&gt; &lt;span class="n"&gt;loginRequest&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;authService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;loginUser&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;loginRequest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getEmail&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;loginRequest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getPassword&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;ResponseEntity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ok&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"User logged in successfully"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;TimeoutException&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;ResponseEntity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;HttpStatus&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;GATEWAY_TIMEOUT&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Timeout Occurred"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;@Service&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AuthService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;loginUser&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;thirdPartyApiClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;validateUser&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getId&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;TimeoutException&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Timeout calling 3rd party API: "&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// What else can we do?&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The Problem
&lt;/h3&gt;

&lt;p&gt;While this code functions, it presents several challenges:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Maintenance Nightmare:&lt;/strong&gt; Tracking &lt;code&gt;try-catch&lt;/code&gt; blocks across multiple layers becomes a burden.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SRP Violation:&lt;/strong&gt; The Service layer, focused on business logic, is now handling infrastructure concerns (exceptions).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Code Redundancy:&lt;/strong&gt; Similar &lt;code&gt;try-catch&lt;/code&gt; blocks are likely repeated throughout the application.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  A Better Approach: Centralized Exception Handling
&lt;/h3&gt;

&lt;p&gt;One solution is to consolidate exception handling in a single layer, typically the Controller. This can be done by removing &lt;code&gt;try-catch&lt;/code&gt; block inside the service layer as shown in the snippet below. This simplifies the Service layer.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Service&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AuthService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;loginUser&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;thirdPartyApiClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;validateUser&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getId&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, the Controller catches exceptions. However, this still mixes exception handling with request processing, further violating SRP and leading to repetitive code in each controller method.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Power of &lt;code&gt;@ControllerAdvice&lt;/code&gt; and &lt;code&gt;@ExceptionHandler&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Enter &lt;code&gt;@ControllerAdvice&lt;/code&gt; and &lt;code&gt;@ExceptionHandler&lt;/code&gt;. These annotations provide a clean, centralized way to manage exceptions. Consider the following code snippet.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@ControllerAdvice&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;GlobalExceptionHandler&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@ExceptionHandler&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;TimeoutException&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;ResponseEntity&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;handleTimeoutException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;TimeoutException&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;ResponseEntity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;HttpStatus&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;GATEWAY_TIMEOUT&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"External service timed out"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;@ControllerAdvice&lt;/code&gt; allows you to define a class that handles exceptions globally. &lt;code&gt;@ExceptionHandler&lt;/code&gt; specifies which exceptions a particular method should handle.  This approach offers several advantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Clean Separation of Concerns:&lt;/strong&gt; Controllers focus on handling requests, Services on business logic, and GlobalExceptionHandler on exceptions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reduced Boilerplate:&lt;/strong&gt; No more redundant &lt;code&gt;try-catch&lt;/code&gt; blocks in Controllers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Centralized Management:&lt;/strong&gt; Exception handling logic resides in one place, making it easier to maintain and modify.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  When &lt;strong&gt;&lt;em&gt;Not&lt;/em&gt;&lt;/strong&gt; to Use Centralized Exception Handling
&lt;/h3&gt;

&lt;p&gt;While centralized exception handling is often the best approach, there are situations where handling exceptions within the Service layer is appropriate.  This is crucial when the exception is directly related to your business logic. For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Retry Logic:&lt;/strong&gt; If a service call fails, you might want to retry with a different data source.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fallback Mechanisms:&lt;/strong&gt; If one service fails, you might have a backup service to use.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These scenarios represent valid use cases for &lt;code&gt;try-catch&lt;/code&gt; blocks within the Service layer.  The key is to differentiate between exceptions that are truly part of your business logic and those that are infrastructure-related.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Think carefully about why you're handling an exception. If it's not directly related to your core business logic, centralized exception handling with &lt;code&gt;@ControllerAdvice&lt;/code&gt; and &lt;code&gt;@ExceptionHandler&lt;/code&gt; is usually the best approach. It promotes cleaner code, improves maintainability, and adheres to SRP principles.  However, don't blindly apply this pattern.  Exceptions that are integral to your business logic should be handled within the Service layer.  Striking the right balance is key to robust and well-structured applications.&lt;/p&gt;

&lt;p&gt;What other types of exception handling techniques do you use? Do you think you can use this in your project? Share your experiences and tips in the comments below!&lt;/p&gt;

</description>
      <category>springboot</category>
      <category>softwareengineering</category>
      <category>cleancode</category>
      <category>java</category>
    </item>
    <item>
      <title>The Guide to Effective Logging</title>
      <dc:creator>Sankararaman K</dc:creator>
      <pubDate>Fri, 08 Nov 2024 06:37:17 +0000</pubDate>
      <link>https://dev.to/sankararaman/fundamentals-of-logging-1ab9</link>
      <guid>https://dev.to/sankararaman/fundamentals-of-logging-1ab9</guid>
      <description>&lt;p&gt;Logging is a crucial process in software development that creates a trail of logs for specific processes or logic flows. In this guide, we'll explore what logging is, why it's important, and best practices for implementing an effective logging strategy.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a log?
&lt;/h2&gt;

&lt;p&gt;A log is a record of an event that occurs within a system or application. These records are essential for debugging, monitoring, and analyzing system behavior.&lt;/p&gt;

&lt;h2&gt;
  
  
  What types of events should be logged?
&lt;/h2&gt;

&lt;p&gt;The events you should log depend on your specific use-case. Here are two primary categories of events that should be logged:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Failure logging&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Failure logging is critical for identifying and resolving issues in your system. Here are some things to consider while looging failure events:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Log a trail of events that can lead to failure&lt;/li&gt;
&lt;li&gt;Make sure these events don't create noice during successful execution&lt;/li&gt;
&lt;li&gt;For example:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[Thu Mar 13 19:04:13 2014] [error] [client 10.1.10.50] File does not exist: /var/www/favicon.ico
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Analytics logging&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Analytics logging helps you understand system usage and performance. Consider logging:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;API endpoints to identify frequently used APIs&lt;/li&gt;
&lt;li&gt;Execution duration to track API response times&lt;/li&gt;
&lt;li&gt;User actions and system events for behavioral analysis&lt;/li&gt;
&lt;li&gt;For example:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;10.1.10.50 [Thu Mar 13 19:04:13 2014] 808840 “GET /inventory/item?itemId=234” 500”
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Best Practises
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Readability&lt;/strong&gt;: Ensure logs are human-readable and easily interpretable&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Noise Reduction&lt;/strong&gt;: Avoid excessive logging that can obscure important information&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Searchability and Filterability&lt;/strong&gt;: Implement unique IDs for each request to enable easy filtering and searching of related logs&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Structured Logging&lt;/strong&gt;: Use a consistent format (e.g., JSON) for easier parsing and analysis&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security&lt;/strong&gt;: Be cautious about logging sensitive information like passwords or personal data&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance&lt;/strong&gt;: Optimize logging to minimize impact on system performance&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Retention&lt;/strong&gt;: Implement a log retention policy that balances storage costs with data availability needs&lt;/li&gt;
&lt;/ol&gt;

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

&lt;p&gt;Effective logging is essential for maintaining, debugging, and optimizing your software systems. By following these best practices and logging the right events, you can significantly improve your ability to troubleshoot issues and gain valuable insights into your application's performance.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;What other types of events do you log? What additional parameters do you consider when defining a log? Share your experiences and tips in the comments below!&lt;/em&gt;&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
