<?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>Forem: Aryan Mehrotra</title>
    <description>The latest articles on Forem by Aryan Mehrotra (@aryanmehrotra).</description>
    <link>https://forem.com/aryanmehrotra</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%2F1199823%2F4489a969-3d9c-477e-86f6-8bfc629c43e4.png</url>
      <title>Forem: Aryan Mehrotra</title>
      <link>https://forem.com/aryanmehrotra</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/aryanmehrotra"/>
    <language>en</language>
    <item>
      <title>The Microservices Backlash: Over-Engineering or Misunderstood Architecture?</title>
      <dc:creator>Aryan Mehrotra</dc:creator>
      <pubDate>Tue, 29 Apr 2025 22:49:45 +0000</pubDate>
      <link>https://forem.com/aryanmehrotra/the-microservices-backlash-over-engineering-or-misunderstood-architecture-51bm</link>
      <guid>https://forem.com/aryanmehrotra/the-microservices-backlash-over-engineering-or-misunderstood-architecture-51bm</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Microservices architecture has been one of the most debated topics in software engineering over the past decade. While many organizations have successfully adopted this pattern, there's growing skepticism about whether microservices are often an over-engineered solution to problems that could be solved with simpler architectures. This article explores why microservices generate so much criticism, examines valid concerns about over-engineering, and presents alternative approaches like clean three-layer architecture that might offer better solutions for many projects - with a powerful ally that simplifies it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;  &lt;em&gt;Skip to the end to meet the ally... but if you do, you'll miss:&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;em&gt;Why your Kubernetes cluster gives you nightmares&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;em&gt;How foreign keys became the villains of our story&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;em&gt;The secret monolith-master race manifesto&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;em&gt;Why 90% of microservices are just distributed monoliths in disguise&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why People Hate Microservices
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Complexity Overhead
&lt;/h3&gt;

&lt;p&gt;Microservices introduce significant operational complexity that many teams aren't prepared to handle. Suddenly, you need to manage:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Service discovery&lt;/li&gt;
&lt;li&gt;Distributed tracing&lt;/li&gt;
&lt;li&gt;Circuit breakers&lt;/li&gt;
&lt;li&gt;API gateways&lt;/li&gt;
&lt;li&gt;Cross-service transactions&lt;/li&gt;
&lt;li&gt;Eventual consistency patterns&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For small to medium-sized applications, this complexity often outweighs the benefits.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"We spent 3 months setting up observability before writing business logic"&lt;/em&gt; – Anonymous Engineer&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Infrastructure Costs
&lt;/h3&gt;

&lt;p&gt;The criticism about Kubernetes costs is valid for many cases. Running multiple services in production requires:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Container orchestration&lt;/li&gt;
&lt;li&gt;More sophisticated monitoring&lt;/li&gt;
&lt;li&gt;Additional network infrastructure&lt;/li&gt;
&lt;li&gt;Potentially more expensive hosting solutions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While you can run microservices on a single EC2 instance, this often defeats the purpose of having independent scalability.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Development Experience Degradation
&lt;/h3&gt;

&lt;p&gt;Developers frequently complain about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Needing to run multiple services locally&lt;/li&gt;
&lt;li&gt;Difficulty in debugging distributed systems&lt;/li&gt;
&lt;li&gt;More complicated CI/CD pipelines&lt;/li&gt;
&lt;li&gt;Context switching between multiple codebases&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. Premature Scaling
&lt;/h3&gt;

&lt;p&gt;Many teams adopt microservices because "we might need to scale," not because they actually need to scale. This premature optimization leads to unnecessary complexity.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Over-Engineering Problem
&lt;/h2&gt;

&lt;p&gt;Microservices have become a victim of their own hype cycle. Many teams implement them because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Resume-driven development&lt;/strong&gt; ("FAANG uses them!")&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Architecture theater&lt;/strong&gt; (Impressive-looking diagrams)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Premature optimization&lt;/strong&gt; ("We might need to scale someday")&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Reality Check&lt;/strong&gt;:&lt;br&gt;&lt;br&gt;
Less than 5% of applications truly benefit from microservices initially.&lt;br&gt;
Rarely do teams honestly assess whether their problem actually requires a distributed systems approach. The truth is that most applications never reach the scale where monoliths become problematic, and when they do, careful modularization within a monolith can often solve the scaling issues.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;Modular Monoliths: The Balanced Approach&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Your observation about structuring code for potential future separation is insightful. This approach—often called the "modular monolith" pattern—provides many benefits:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Single codebase&lt;/strong&gt;: One repository with clear internal boundaries&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Simplified deployment&lt;/strong&gt;: One binary/Docker image to manage&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Easier testing&lt;/strong&gt;: No need for complex integration test setups&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Future flexibility&lt;/strong&gt;: Well-structured code can be split later if truly needed&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In Go, this could look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/project
├── main.go          # Single entry point
├── order/           # Fully self-contained
│   │   ├── handler/
│   │   ├── service/
│   │   └── store/
│   ├── main.go      # Optional microservice entry point
│   └── Dockerfile   # Optional microservice Dockerfile
│-── catalogue/      # Independent domain
│-─  customer/       # Clear boundaries
└── Dockerfile       # Single deployment
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Key Architectural Decisions
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. Domain-Centric Organization
&lt;/h4&gt;

&lt;p&gt;This structure organizes code by business domains (order, catalogue, customer) rather than by technical layers (controllers, services, repositories). Each domain contains its own complete vertical slice of the architecture.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Benefits:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Better alignment with business capabilities&lt;/li&gt;
&lt;li&gt;Reduced cross-domain coupling&lt;/li&gt;
&lt;li&gt;Easier to extract into microservices later if needed&lt;/li&gt;
&lt;li&gt;More cohesive code organization&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  2. Self-Contained Modules
&lt;/h4&gt;

&lt;p&gt;Each domain module contains:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Handler&lt;/strong&gt;: HTTP/API delivery layer&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Service&lt;/strong&gt;: Business logic layer &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Store&lt;/strong&gt;: Data access layer &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This follows the principles where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Dependencies flow inward (handlers depend on services, services depend on stores)&lt;/li&gt;
&lt;li&gt;Outer layers can be swapped without changing inner layers&lt;/li&gt;
&lt;li&gt;Business logic remains agnostic&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  3. Flexible Deployment Options
&lt;/h4&gt;

&lt;p&gt;The structure supports multiple deployment strategies:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Monolithic Mode:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Single &lt;code&gt;main.go&lt;/code&gt; orchestrates all domains&lt;/li&gt;
&lt;li&gt;Unified configuration&lt;/li&gt;
&lt;li&gt;Single process monitoring&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Microservice Mode:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Any service can be built and deployed separately using its own &lt;code&gt;main.go&lt;/code&gt; and &lt;code&gt;Dockerfile&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Advantages Over Traditional Three-Layer
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Better Domain Isolation&lt;/strong&gt;: Clear boundaries prevent accidental coupling&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Easier Testing&lt;/strong&gt;: Each domain can be tested in isolation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Progressive Complexity&lt;/strong&gt;: Start simple, add distribution only when needed&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Team Scalability&lt;/strong&gt;: Different teams can own different domains&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  When This Works Best
&lt;/h3&gt;

&lt;p&gt;This architecture shines when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You want to avoid microservices overhead but maintain separation&lt;/li&gt;
&lt;li&gt;Your team is small-to-medium sized&lt;/li&gt;
&lt;li&gt;You might need microservices eventually but not yet&lt;/li&gt;
&lt;li&gt;Different domains have different evolution speeds&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The key insight is that &lt;strong&gt;code organization doesn't have to match deployment topology&lt;/strong&gt;. You can maintain clean separation in code while deploying as a monolith, then change deployment strategy later without massive rewrites.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Clean Three-Layer Architecture in Practice&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;1. Delivery Layer (Handler)&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Receives HTTP requests&lt;/li&gt;
&lt;li&gt;Handles:

&lt;ul&gt;
&lt;li&gt;Request validation&lt;/li&gt;
&lt;li&gt;Authentication/authorization&lt;/li&gt;
&lt;li&gt;Error formatting&lt;/li&gt;
&lt;li&gt;Response marshaling&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Should be thin - delegates business logic to service layer&lt;/li&gt;

&lt;li&gt;

&lt;em&gt;Example&lt;/em&gt;:
&lt;/li&gt;

&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;  &lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;CreateOrder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;gofr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt; &lt;span class="n"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;OrderHandler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;gofr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt; &lt;span class="n"&gt;OrderRequest&lt;/span&gt;

      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ErrorInvalidParam&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Params&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"body"&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="c"&gt;// Delegates to service layer&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CreateOrder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;2. Business Logic Layer (Service)&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Manages all domain relationships&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Database-agnostic&lt;/strong&gt; (critical for flexibility)&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Anti-pattern alert&lt;/em&gt;:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;  &lt;span class="c1"&gt;-- ❌ Avoid foreign key constraints&lt;/span&gt;
  &lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&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;customer_id&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt; &lt;span class="k"&gt;REFERENCES&lt;/span&gt; &lt;span class="n"&gt;customers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="o"&gt;#&lt;/span&gt; &lt;span class="n"&gt;Tight&lt;/span&gt; &lt;span class="n"&gt;DB&lt;/span&gt; &lt;span class="n"&gt;coupling&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why?&lt;/strong&gt; Database-level constraints like foreign keys create tight coupling that violates service boundaries - always enforce relationships in your application code, not your storage layer.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Contains domain logic&lt;/li&gt;
&lt;li&gt;Orchestrates multiple store operations&lt;/li&gt;
&lt;li&gt;Enforces business rules&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Better&lt;/em&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;  &lt;span class="c"&gt;// ✅ Service manages validation&lt;/span&gt;
  &lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;customerService&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;GetByID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;gofr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Customer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;OrderService&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;gofr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt; &lt;span class="n"&gt;OrderInput&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;exists&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;customerService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetByID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CustomerID&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&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;err&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="c"&gt;// Proceed with order creation&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;3. Store Layer (Data Access)&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Handles database operations&lt;/li&gt;
&lt;li&gt;Manages:

&lt;ul&gt;
&lt;li&gt;Database connections&lt;/li&gt;
&lt;li&gt;Query building&lt;/li&gt;
&lt;li&gt;Caching&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Practical Microservice Division: Your E-commerce Example
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Order Service&lt;/strong&gt;: Focused purely on order processing&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Catalogue Service&lt;/strong&gt;: Manages products and brands (cohesive domain)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Customer Service&lt;/strong&gt;: Handles all customer-related data&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This division follows domain boundaries rather than technical concerns. The key insight is keeping tightly coupled entities together (like brands and products) while separating domains that can evolve independently (like orders and customers).&lt;/p&gt;

&lt;h2&gt;
  
  
  When Microservices Deployment Make Sense
&lt;/h2&gt;

&lt;p&gt;Microservices Deployment become valuable when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Different components have genuinely different scaling requirements&lt;/li&gt;
&lt;li&gt;Teams need to work independently with different release cycles&lt;/li&gt;
&lt;li&gt;You have clear domain boundaries with minimal cross-domain communication&lt;/li&gt;
&lt;li&gt;You're at a scale where operational overhead is justified&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;The backlash against microservices stems from their frequent misuse as a default architecture rather than a deliberate choice for specific scaling needs. For most applications—especially early-stage products—starting with a well-structured modular monolith using clean architectural principles provides better velocity and maintainability.&lt;/p&gt;

&lt;p&gt;The wisdom in your approach lies in recognizing that code organization and deployment strategy are separate concerns. You can structure your code for potential future distribution while maintaining the simplicity of a monolith deployment. This pragmatic approach avoids over-engineering while preserving architectural flexibility for when (and if) you truly need to scale.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Final Insight&lt;/strong&gt;:&lt;br&gt;&lt;br&gt;
&lt;em&gt;"Good architecture maximizes options, not complexity."&lt;/em&gt;&lt;br&gt;&lt;br&gt;
With GoFr, you get:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Simplicity&lt;/strong&gt;  when you need it&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Scalability&lt;/strong&gt;  when you require it&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Sanity&lt;/strong&gt;  throughout your journey&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://gofr.dev/" rel="noopener noreferrer"&gt;Explore GoFr&lt;/a&gt;  to build systems that grow with your needs, not your headaches.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Unlocking Hidden Performance Bottlenecks in Golang using GoFr: The Underrated Power of pprof</title>
      <dc:creator>Aryan Mehrotra</dc:creator>
      <pubDate>Wed, 26 Mar 2025 21:14:45 +0000</pubDate>
      <link>https://forem.com/aryanmehrotra/unlocking-hidden-performance-bottlenecks-in-golang-using-gofr-the-underrated-power-of-pprof-2dc7</link>
      <guid>https://forem.com/aryanmehrotra/unlocking-hidden-performance-bottlenecks-in-golang-using-gofr-the-underrated-power-of-pprof-2dc7</guid>
      <description>&lt;p&gt;In high-traffic production environments, unexpected performance bottlenecks can degrade user experience and threaten system reliability. While GoFr, a powerful Golang framework, offers built-in observability, some issues demand deeper debugging to pinpoint the exact lines of code causing slowdowns. This is where pprof—an underrated yet potent tool—shines, delivering real-time performance profiling and actionable insights.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Challenge of Debugging Performance Issues in Golang
&lt;/h2&gt;

&lt;p&gt;Golang services are built for speed, but at scale, even small inefficiencies can snowball into significant performance hits. Debugging these issues is tricky because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Traditional logs and traces provide historical data but can’t capture real-time bottlenecks.&lt;/li&gt;
&lt;li&gt;Problems like CPU spikes, memory leaks, and goroutine contention require live profiling to diagnose effectively.&lt;/li&gt;
&lt;li&gt;Many profiling tools demand complex setup or risk destabilizing production environments.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How GoFr &amp;amp; pprof Solve This Quickly
&lt;/h2&gt;

&lt;p&gt;GoFr simplifies observability with integrated logging, monitoring, and metrics (visualizable via tools like Grafana). For deeper debugging, it pairs seamlessly with pprof, enabling developers to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Quickly Enable Profiling&lt;/strong&gt;: With a simple config tweak in GoFr, unlock real-time CPU, memory, and goroutine profiling.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Analyze Performance in Production&lt;/strong&gt;: Diagnose high-latency endpoints without downtime, thanks to pprof’s runtime capabilities.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Optimize for Peak Traffic&lt;/strong&gt;: Spot inefficient operations—like JSON decoding, mutex contention, or costly database calls—and address them proactively.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  pprof in GoFr
&lt;/h2&gt;

&lt;p&gt;In GoFr applications, pprof profiling is built-in and accessible via the &lt;code&gt;METRICS_PORT&lt;/code&gt; (defaulting to 2121 if unspecified). This dedicated port isolates profiling endpoints from your main application, enhancing security. Access them at:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;CPU Profiling&lt;/strong&gt;: &lt;code&gt;&amp;lt;host&amp;gt;:2121/debug/pprof/profile&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Memory Profiling&lt;/strong&gt;: &lt;code&gt;&amp;lt;host&amp;gt;:2121/debug/pprof/heap&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Goroutine Analysis&lt;/strong&gt;: &lt;code&gt;&amp;lt;host&amp;gt;:2121/debug/pprof/goroutine&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Using data collected from these endpoints, developers can generate detailed CPU profiles and flamegraphs to visualize performance bottlenecks.&lt;/p&gt;

&lt;h3&gt;
  
  
  CPU Profile (Call Graph)
&lt;/h3&gt;

&lt;p&gt;A CPU call graph illustrates how functions execute and interconnect at runtime:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Nodes&lt;/strong&gt;: Represent functions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Edges&lt;/strong&gt;: Show function calls between them.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This view is ideal for understanding program flow and dependencies.&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%2F3ylsj8wepb5dukg7rwot.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%2F3ylsj8wepb5dukg7rwot.png" alt="Call Graph" width="800" height="458"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Flamegraph
&lt;/h3&gt;

&lt;p&gt;A flamegraph highlights CPU usage visually with stacked bars:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;X-axis&lt;/strong&gt;: Function execution time (wider bars mean more time spent).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Y-axis&lt;/strong&gt;: Call hierarchy (higher stacks indicate deeper calls).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It’s a fast way to spot performance hotspots and prioritize optimizations.&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%2F02d4hfcj1fu14jib0px0.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%2F02d4hfcj1fu14jib0px0.png" alt="Flame Graph" width="800" height="376"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Differences
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;CPU Call Graph&lt;/strong&gt;: Emphasizes function relationships and execution order.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flamegraph&lt;/strong&gt;: Pinpoints CPU-intensive functions and bottlenecks.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Real-World Use Case: Debugging Latency Spikes in a Golang Service
&lt;/h2&gt;

&lt;p&gt;Imagine a Go-based service hit by latency spikes during peak traffic. Standard monitoring (logs, GoFr’s metrics in Grafana) flags high API response times, but the root cause stays elusive. A common culprit? Inefficient JSON decoding, where &lt;code&gt;json.Unmarshal()&lt;/code&gt; chews up CPU via reflection. Without profiling, this is a needle in a haystack. Here’s how pprof saves the day:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Identify the Problem Using Grafana&lt;/strong&gt;: GoFr’s metrics, visualized in Grafana, show elevated response times. Uneven load distribution suggests concurrency issues.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Run Real-Time Profiling with pprof&lt;/strong&gt;: Enable pprof in GoFr with a config change. Collect CPU and memory profiles during peak load, then analyze them with &lt;code&gt;go tool pprof&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pinpoint the Bottleneck&lt;/strong&gt;: Profiling reveals &lt;code&gt;json.Unmarshal()&lt;/code&gt; as a CPU hog due to reflection-based unmarshaling—slowing down requests significantly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Apply Optimizations &amp;amp; Measure Impact&lt;/strong&gt;: Swap &lt;code&gt;encoding/json&lt;/code&gt; for &lt;code&gt;jsoniter&lt;/code&gt; (a high-performance JSON library). Cut API latency by 30%. Deploy safely with feature flags and confirm gains in Grafana.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Why This Approach Is a Game-Changer for Golang Developers
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Minimal Setup&lt;/strong&gt;: GoFr enables pprof with a single config tweak—no complex integrations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Live Debugging Without Downtime&lt;/strong&gt;: Profile production systems in real-time using pprof’s runtime capabilities.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pinpoint Slow Code Paths&lt;/strong&gt;: Uncover inefficient functions dragging down performance.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Optimize Safely&lt;/strong&gt;: Roll out fixes with confidence using controlled deployments.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Performance debugging in Golang doesn’t have to be a mystery. By combining GoFr’s observability with pprof’s profiling power, developers can expose hidden inefficiencies and tune services for peak performance at scale.&lt;/p&gt;

&lt;p&gt;Have you tackled JSON decoding bottlenecks with pprof—or found other sneaky slowdowns? Share your experiences in the comments! 🚀&lt;/p&gt;

&lt;p&gt;Support GoFr by giving a ⭐: &lt;a href="https://github.com/gofr-dev/gofr" rel="noopener noreferrer"&gt;https://github.com/gofr-dev/gofr&lt;/a&gt;&lt;br&gt;&lt;br&gt;
Check out GoFr’s profiling docs: &lt;a href="https://gofr.dev/docs/advanced-guide/debugging" rel="noopener noreferrer"&gt;https://gofr.dev/docs/advanced-guide/debugging&lt;/a&gt;&lt;br&gt;&lt;br&gt;
Explore Golang’s official diagnostics guide: &lt;a href="https://go.dev/doc/diagnostics" rel="noopener noreferrer"&gt;https://go.dev/doc/diagnostics&lt;/a&gt;&lt;/p&gt;

</description>
      <category>go</category>
      <category>programming</category>
      <category>ai</category>
      <category>performance</category>
    </item>
    <item>
      <title>I Hated gRPC until this tool started Simplifying it!</title>
      <dc:creator>Aryan Mehrotra</dc:creator>
      <pubDate>Sun, 12 Jan 2025 20:54:13 +0000</pubDate>
      <link>https://forem.com/aryanmehrotra/i-hated-grpc-until-this-tool-started-simplifying-it-27o2</link>
      <guid>https://forem.com/aryanmehrotra/i-hated-grpc-until-this-tool-started-simplifying-it-27o2</guid>
      <description>&lt;p&gt;gRPC, Google’s open-source RPC framework, has become a go-to choice for building high-performance, efficient APIs. It’s fast, reliable, and ideal for microservices. But let’s be honest — getting started with gRPC can be a real headache.&lt;/p&gt;

&lt;p&gt;From installing &lt;code&gt;protoc&lt;/code&gt; and its plugins to managing the generated code, there’s a lot to set up before you can even write your first handler. That complexity often makes developers shy away from using it, despite its advantages.&lt;/p&gt;

&lt;p&gt;Fortunately, &lt;a href="https://gofr.dev" rel="noopener noreferrer"&gt;&lt;strong&gt;GoFr&lt;/strong&gt;&lt;/a&gt; can make working with gRPC significantly easier by providing built-in support for observability, dependency management, and a simplified development process.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Challenges of Using gRPC
&lt;/h2&gt;

&lt;p&gt;While gRPC is amazing, it comes with its fair share of pain points:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Steep Setup Curve&lt;/strong&gt;
Setting up the protocol buffer compiler (&lt;code&gt;protoc&lt;/code&gt;), installing plugins, and ensuring compatibility often feels like a chore.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Manual Code Generation&lt;/strong&gt;
Defining services in &lt;code&gt;.proto&lt;/code&gt; files and generating code requires multiple commands. Any misstep can result in errors and wasted time.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Boilerplate Code&lt;/strong&gt;
Even after generating the necessary files, writing handler code from scratch and integrating dependencies can feel overwhelming.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Lack of Integrated Tools&lt;/strong&gt;
&lt;strong&gt;Observability&lt;/strong&gt;, &lt;strong&gt;database connections&lt;/strong&gt;, and &lt;strong&gt;configuration management&lt;/strong&gt; typically require separate efforts to integrate.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  How GoFr Simplifies gRPC Development
&lt;/h2&gt;

&lt;p&gt;While GoFr doesn’t replace the need for &lt;code&gt;protoc&lt;/code&gt;, it enhances the development experience by providing seamless integration with modern tools and practices.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Features of GoFr for gRPC
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Integrating Observability and Dependencies&lt;/strong&gt;: Access databases, logging, metrics, traces directly from GoFr’s context.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Generating Ready-to-Use Handlers&lt;/strong&gt;: Use the &lt;code&gt;gofr wrap grpc&lt;/code&gt; command to scaffold handler templates for your gRPC services.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Reducing Boilerplate&lt;/strong&gt;: Focus on business logic instead of repetitive setup tasks.&lt;/li&gt;
&lt;/ol&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%2Flvghx2hkcm64xmqmfsxt.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%2Flvghx2hkcm64xmqmfsxt.png" alt="GoFr's gRPC Handler" width="800" height="543"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Started with GoFr and gRPC
&lt;/h2&gt;

&lt;p&gt;If you’re ready to explore how GoFr can simplify your gRPC workflow, here are the key resources to get you started:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Install and Use GoFr for gRPC&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://github.com/gofr-dev/gofr-cli" rel="noopener noreferrer"&gt;Setting up GoFr CLI&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://gofr.dev/docs/advanced-guide/grpc#g-rpc-with-gofr" rel="noopener noreferrer"&gt;gRPC with GoFr Documentation&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Official Examples&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://github.com/gofr-dev/gofr/blob/main/examples/grpc-server/main.go" rel="noopener noreferrer"&gt;gRPC Server Example in GoFr&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;gRPC is a powerful framework, but its initial setup can be daunting. &lt;a href="https://gofr.dev" rel="noopener noreferrer"&gt;GoFr&lt;/a&gt; doesn’t eliminate the need for &lt;code&gt;protoc&lt;/code&gt;, but it significantly reduces the friction by providing context-driven tools and simplifying the development process.&lt;/p&gt;

&lt;p&gt;Whether you’re new to gRPC or an experienced developer, &lt;a href="https://gofr.dev" rel="noopener noreferrer"&gt;GoFr’s&lt;/a&gt; integration of observability and dependency management makes gRPC development more approachable and efficient.&lt;/p&gt;

&lt;p&gt;Give it a try — you might just find yourself enjoying gRPC more than ever before!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Support GoFr by giving a ⭐:&lt;/strong&gt; &lt;a href="https://github.com/gofr-dev/gofr" rel="noopener noreferrer"&gt;https://github.com/gofr-dev/gofr&lt;/a&gt;&lt;/p&gt;

</description>
      <category>go</category>
      <category>programming</category>
      <category>beginners</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>The Ultimate Golang Framework for Microservices: GoFr</title>
      <dc:creator>Aryan Mehrotra</dc:creator>
      <pubDate>Wed, 24 Jul 2024 06:55:26 +0000</pubDate>
      <link>https://forem.com/aryanmehrotra/the-ultimate-golang-framework-for-microservices-gofr-ok</link>
      <guid>https://forem.com/aryanmehrotra/the-ultimate-golang-framework-for-microservices-gofr-ok</guid>
      <description>&lt;p&gt;Go is a multiparadigm, statically typed, and compiled programming language designed by Google. Many developers have embraced Go because of its garbage collection, memory safety, and structural typing system. Go web frameworks were created to ease Go web development processes without worrying about setups and focusing more on the functionalities of a project. While building small applications, frameworks may not be necessary, but for production-level software, they are crucial. Frameworks provide additional functionalities and services that can be used by other developers who want to add similar functionalities to their software rather than writing the full-fledged software by themselves.&lt;/p&gt;

&lt;p&gt;Choosing the right framework for your needs can enable faster development cycles and easier maintenance down the road. In this article we will talk about GoFr, an opinionated Golang framework for accelerated microservice development. And we will discover why it is your ultimate choice when building microservices in Go!&lt;/p&gt;

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




&lt;h2&gt;
  
  
  GoFr &amp;amp; It’s rich set of features:
&lt;/h2&gt;

&lt;p&gt;What really makes a framework good or bad is the ease of development it provides for its user along with the range of features it offers so the user can purely focus on business logic implementation. GoFr has been built to help developers write fast, scalable and efficient API’s. The framework offers a rich set of features that help developers in writing production grade microservices with ease. Let’s explore some of these features:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Efficient Configuration Management&lt;/strong&gt;
Environment variables are the best way to set configuration values for your software application as they can be defined at system-level, independently of the software. This is one of the principles of the &lt;strong&gt;Twelve-Factor App methodology&lt;/strong&gt; and enables applications to be built with portability.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;GoFr has some predefined environment variables for various purposes like changing log levels, connecting to databases, setting application name and version, setting http ports etc. The user just needs to set these in an .env file inside the configs directory of the application and GoFr automatically reads the values from that.&lt;/p&gt;

&lt;p&gt;Here is the full list of environment variables supported by GoFr:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Seamless Database Interactions&lt;/strong&gt;
Managing database connections and interactions can become hectic, especially when working with multiple databases. GoFr handles database connections seamlessly using configuration variables. Not only does it manage the connections, but it also provides direct access to database objects using the GoFr context within handlers. This approach simplifies working with multiple databases. GoFr currently supports all SQL Dialects, &lt;strong&gt;Redis, MongoDB, Cassandra and ClickHouse&lt;/strong&gt; databases.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Example of using MySQL and Redis DB inside the handler.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;func DBHandler(c *gofr.Context) (interface{}, error) {
 var value int

// querying a SQL db
err := c.SQL.QueryRowContext(c, "select 2+2").Scan(&amp;amp;value)
 if err != nil {
  return nil, datasource.ErrorDB{Err: err, Message: "error from sql db"}
 }

// retrieving value from Redis
 _, err = c.Redis.Get(c, "test").Result()
 if err != nil &amp;amp;&amp;amp; !errors.Is(err, redis.Nil) {
  return nil, datasource.ErrorDB{Err: err, Message: "error from redis db"}
 }

 return value, nil
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Implementing Publisher-Subscriber architecture with ease:&lt;/strong&gt;
GoFr simplifies Pub/Sub by offering built-in support for popular clients like Kafka, Google Pub/Sub, and MQTT. This eliminates the need for manual configuration or library management, allowing you to focus on your event-driven architecture. Publishing and subscribing to events are streamlined using the GoFr context. Publishing events can be done inside the handler using the context, and to subscribe to an event, you just need to use GoFr’s Subscribe handler. This approach promotes clean code and reduces boilerplate compared to implementing the Pub/Sub pattern from scratch.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Example of using Publisher and Subscriber in a GoFr application:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

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

import (
 "encoding/json"

 "gofr.dev/pkg/gofr"
)

func main() {
 app := gofr.New()

 app.POST("/publish-product", product)

// subscribing to products topic
 app.Subscribe("products", func(c *gofr.Context) error {
  var productInfo struct {
   ProductId string `json:"productId"`
   Price     string `json:"price"`
  }

  err := c.Bind(&amp;amp;productInfo)
  if err != nil {
   c.Logger.Error(err)

   return nil
  }

  c.Logger.Info("Received product ", productInfo)

  return nil
 })

 app.Run()
}

func product(ctx *gofr.Context) (interface{}, error) {
 type productInfo struct {
  ProductId string `json:"productId"`
  Price     string `json:"price"`
 }

 var data productInfo

// binding the request data to productInfo struct
 err := ctx.Bind(&amp;amp;data)
 if err != nil {
  return nil, err
 }

 msg, _ := json.Marshal(data)

// publishing message to producst topic using gofr context
 err = ctx.GetPublisher().Publish(ctx, "products", msg)
 if err != nil {
  return nil, err
 }

 return "Published", nil
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Out of the Box Observability:&lt;/strong&gt;
Effective monitoring is crucial for maintaining high-performing microservices. GoFr takes the burden off your shoulders by providing built-in observability features. This eliminates the need for manual configuration of tracing, metrics, and logging libraries.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Detailed Logging:&lt;/strong&gt; GoFr offers structured logging with various log levels (INFO, DEBUG, WARN, ERROR, FATAL) to capture application events at different granularities. This empowers you to analyze application flow, identify potential issues, and streamline debugging.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Actionable Metrics:&lt;/strong&gt; GoFr automatically collects and exposes application metrics, allowing you to monitor key performance indicators. With metrics readily available, you can quickly identify bottlenecks and optimize application performance.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Distributed Tracing:&lt;/strong&gt; GoFr integrates with popular tracing backends like Zipkin and Jaeger. Distributed tracing allows you to visualize the entire request lifecycle across your microservices, making it easier to pinpoint the root cause of issues within complex systems.&lt;/p&gt;

&lt;p&gt;These observability features help users gain detailed insights into the application’s flow and performance, identify and resolve bottlenecks, and ensure smooth operation.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Effortless Interservice HTTP Communication:&lt;/strong&gt;
In a microservices architecture, efficient and reliable communication between services is crucial. GoFr simplifies this process by providing a dedicated mechanism to initialize and manage interservice HTTP communication. You can easily register downstream services at the application level using the AddHTTPService method.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Configurational Options for HTTP Services:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;GoFr offers a variety of configuration options to enhance interservice communication:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Authentication:&lt;/strong&gt; Supports APIKeyConfig, BasicAuthConfig, and OAuthConfig for secure authentication.&lt;/li&gt;
&lt;li&gt;Default Headers: Allows setting default headers for all downstream HTTP service requests.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Circuit Breaker:&lt;/strong&gt; Enhance service resilience with built-in circuit breaker functionality. GoFr allows you to configure thresholds and intervals to gracefully handle failures and prevent cascading outages.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Health Checks:&lt;/strong&gt; Proactively monitor the health of your downstream services using GoFr’s health check configuration. Define a health endpoint for each service, and GoFr will automatically verify their availability, allowing for early detection of potential issues.
These features ensure that interservice communication is secure, reliable, and easily manageable.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Example of connecting to a HTTP Service and sending a GET request:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;func main() {
 a := gofr.New()

 a.AddHTTPService("cat-facts", "https://catfact.ninja",
  &amp;amp;service.CircuitBreakerConfig{
   Threshold: 4,
   Interval:  1 * time.Second,
  },
  &amp;amp;service.HealthConfig{
   HealthEndpoint: "breeds",
  },
 )

a.GET("/fact", Handler)

 a.Run()
}

func Handler(c *gofr.Context) (any, error) {
 var data = struct {
  Fact   string `json:"fact"`
  Length int    `json:"length"`
 }{}

 var catFacts = c.GetHTTPService("cat-facts")

 resp, err := catFacts.Get(c, "fact", map[string]interface{}{
  "max_length": 20,
 })
 if err != nil {
  return nil, err
 }

 b, _ := io.ReadAll(resp.Body)
 err = json.Unmarshal(b, &amp;amp;data)
 if err != nil {
  return nil, err
 }

 return data, nil
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Flexible Middleware Support for Enhanced Control:&lt;/strong&gt;
Middleware allows you intercepting and manipulating HTTP requests and responses flowing through your application’s router. Middlewares can perform tasks such as authentication, authorization, caching etc. before or after the request reaches your application’s handler.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;GoFr empowers developers with middleware support, allowing for request/response manipulation and custom logic injection. This provides a powerful mechanism to implement cross-cutting concerns like authentication, authorization, and caching in a modular and reusable way. Middleware functions are registered using the UseMiddleware method on your GoFr application instance. Additionally, GoFr includes built-in CORS **(Cross-Origin Resource Sharing) **middleware to handle CORS-related headers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example of adding a custom middleware to GoFr application:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import (
    "net/http"

    gofrHTTP "gofr.dev/pkg/gofr/http"
)

// Define your custom middleware function
func customMiddleware() gofrHTTP.Middleware {
    return func(inner http.Handler) http.Handler {
        return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
            // Your custom logic here
            // For example, logging, authentication, etc.

            // Call the next handler in the chain
            inner.ServeHTTP(w, r)
        })
    }
}

func main() {
    // Create a new instance of your GoFr application
    app := gofr.New()

    // Add your custom middleware to the application
    app.UseMiddleware(customMiddleware())

    // Define your application routes and handlers
    // ...

    // Run your GoFr application
    app.Run()
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Integrated Authentication Mechanisms:&lt;/strong&gt;
Securing your microservices with robust authentication is crucial. GoFr streamlines this process by providing built-in support for various industry-standard authentication mechanisms. This empowers you to choose the approach that best suits your application’s needs without writing complex authentication logic from scratch.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Basic Auth:&lt;/strong&gt; Basic auth is the simplest way to authenticate your APIs. It’s built on HTTP protocol authentication scheme. It involves sending the prefix Basic trailed by the Base64-encoded : within the standard Authorization header. GoFr offers two ways to implement basic authentication i.e. using pre-defined credentials as well as defining a custom validation function.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;API Keys Auth:&lt;/strong&gt; API Key Authentication is an HTTP authentication scheme where a unique API key is included in the request header for validation against a store of authorized keys. GoFr offers two ways to implement API Keys authentication i.e. Framework Default Validation as well as defining a Custom Validation Function.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;OAuth 2.0:&lt;/strong&gt; OAuth 2.0 is the industry-standard protocol for authorization. It focuses on client developer simplicity while providing specific authorization flows for web applications, desktop applications, mobile phones, and living room devices. It involves sending the prefix Bearer trailed by the encoded token within the standard Authorization header. GoFr supports authenticating tokens encoded by algorithm RS256/384/512.&lt;br&gt;
Refer to the GoFr’s Authentication Documentation to see the examples of how to use these auth mechanisms and know more about it.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Automatic Swagger UI Rendering:&lt;/strong&gt;
Providing clear and interactive API documentation is essential for user adoption and efficient development workflows. API specifications can be written in YAML or JSON. The format is easy to learn and readable to both humans and machines. The complete OpenAPI Specification can be found on the official Swagger website.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;GoFr supports automatic rendering of OpenAPI (also known as Swagger) documentation. This feature allows you to easily provide interactive API documentation for your users. To allow GoFr to render your OpenAPI documentation, simply place your openapi.json file inside the static directory of your project. GoFr will automatically render the Swagger documentation at the /.well-known/swagger endpoint.&lt;/p&gt;

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

&lt;p&gt;Throughout this article, we’ve explored the rich features of GoFr, an opinionated Golang framework specifically designed to accelerate microservice development. We’ve seen how GoFr simplifies common tasks like configuration management, database interactions, Pub/Sub integration, automatic observability, interservice communication, middleware usage, and authentication. Additionally, GoFr offers built-in support for data migrations, web sockets, cron jobs, and remote log level changes, further streamlining your development process.&lt;/p&gt;

&lt;p&gt;We benchmarked GoFr against other popular Go frameworks such as Gin, Chi, Echo, and Fiber, and found that GoFr performed optimally, even with its extensive feature set. This means you can leverage all its powerful functionalities without compromising on performance.&lt;/p&gt;

&lt;p&gt;We encourage you to explore GoFr for yourself. The framework’s comprehensive documentation, tutorials, and active community are valuable resources to guide you on your journey. With GoFr, you can focus on building robust, scalable, and efficiently managed microservices, freeing you to dedicate more time to your application’s core functionalities.&lt;/p&gt;

&lt;p&gt;Get started with GoFr today!&lt;/p&gt;

&lt;p&gt;Star the repo if you like it! @ &lt;a href="https://github.com/gofr-dev/gofr" rel="noopener noreferrer"&gt;https://github.com/gofr-dev/gofr&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here are some helpful resources:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;GoFr Website: &lt;a href="https://gofr.dev" rel="noopener noreferrer"&gt;https://gofr.dev&lt;/a&gt;&lt;br&gt;
GoFr GitHub Repository: &lt;a href="https://github.com/gofr-dev/gofr" rel="noopener noreferrer"&gt;https://github.com/gofr-dev/gofr&lt;/a&gt;&lt;br&gt;
GoFr Discord Server: &lt;a href="https://discord.gg/zyJkVhps" rel="noopener noreferrer"&gt;https://discord.gg/zyJkVhps&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>programming</category>
      <category>go</category>
      <category>backend</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Runtime Log Level Change using Golang &amp; GoFr</title>
      <dc:creator>Aryan Mehrotra</dc:creator>
      <pubDate>Mon, 22 Jul 2024 07:48:20 +0000</pubDate>
      <link>https://forem.com/aryanmehrotra/remote-runtime-log-level-change-using-golang-gofr-54d8</link>
      <guid>https://forem.com/aryanmehrotra/remote-runtime-log-level-change-using-golang-gofr-54d8</guid>
      <description>&lt;p&gt;In this article, I will be sharing how you can change the log level of your application without restarting your application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Log levels are usually considered to be in order of importance: turn on "unimportant" levels in development (notice, debug and the like), but enable only the "most important" levels (warn, error, etc.) in production, where resources like CPU time and disk space are precious.&lt;/p&gt;

&lt;p&gt;But what if your application is running at &lt;code&gt;ERROR&lt;/code&gt; level and you start facing many issues, but you cannot figure it out from ERROR level logs, changing the log level by redeploying the application will take a lot of time and resources.&lt;/p&gt;

&lt;p&gt;Moreover, running your application at either INFO or DEBUG level in production will generate a large number of logs which can overwhelm the logging system, leading to increased I/O operations and resource consumption.&lt;/p&gt;

&lt;p&gt;To rescue us from these issues, &lt;a href="https://blog.stackademic.com/the-ultimate-golang-framework-for-microservices-gofr-eb4071cded30" rel="noopener noreferrer"&gt;GoFr - The Ultimate Golang Framework &lt;/a&gt;provides a secure way to change the log level without restarting your application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Changing Log Level
&lt;/h2&gt;

&lt;p&gt;To change the log level any GoFr application requires the following configuration:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;REMOTE_LOG_URL=&amp;lt;URL to user remote log level endpoint&amp;gt; (e.g., https://log-service.com/log-levels?id=1)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;GoFr fetches the endpoint provided every 15 seconds by default to get the latest log level, this interval can be increased or decreased by adding the following configuration.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;REMOTE_LOG_FETCH_INTERVAL=&amp;lt;Interval in seconds&amp;gt; (default: 15)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Log Level Service
&lt;/h2&gt;

&lt;p&gt;GoFr requires the response from the URL in the following format with two mandatory fields:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "data": {
       "serviceName": "test-service",
       "logLevel": "DEBUG"
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Let's create the log-level service which will provide the log-level to our application.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I will be using GoFr to create the service, refer the &lt;a href="https://gofr.dev/docs" rel="noopener noreferrer"&gt;documentation&lt;/a&gt; to know more.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We will use MySQL as the database, to add MySQL add the following &lt;a href="https://gofr.dev/docs/quick-start/configuration" rel="noopener noreferrer"&gt;configs&lt;/a&gt; in .env file in the configs directory.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DB_HOST=localhost
DB_USER=root
DB_PASSWORD=password
DB_NAME=log-level
DB_PORT=2001
DB_DIALECT=mysql
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;To run the MySQL docker container run the following command&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker run --name gofr-logger -e MYSQL_ROOT_PASSWORD=password -e MYSQL_DATABASE=log-level -p 2001:3306 -d mysql:8.0.30
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Lets add the main.go file with &lt;a href="https://gofr.dev/docs/advanced-guide/handling-data-migrations" rel="noopener noreferrer"&gt;migrations&lt;/a&gt; to create table and we will use &lt;a href="https://gofr.dev/docs/quick-start/add-rest-handlers" rel="noopener noreferrer"&gt;AddRESTHandler&lt;/a&gt; feature to register the route.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;main.go&lt;/strong&gt;&lt;/p&gt;

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

import (
 "gofr.dev/pkg/gofr"
 "gofr.dev/pkg/gofr/migration"
)

const createTable = `CREATE TABLE level (
    id INT PRIMARY KEY,
    service_name VARCHAR(255) NOT NULL,
    log_level VARCHAR(50) NOT NULL
);
`

func createTableLevel() migration.Migrate {
 return migration.Migrate{
  UP: func(d migration.Datasource) error {
   _, err := d.SQL.Exec(createTable)
   if err != nil {
    return err
   }

   return nil
  },
 }
}

type Level struct {
 ID          int    `json:"id"`
 ServiceName string `json:"serviceName"`
 LogLevel    string `json:"logLevel"`
}

func (u *Level) RestPath() string {
 return "level"
}

func main() {
 app := gofr.New()

 app.Migrate(map[int64]migration.Migrate{1: createTableLevel()})

 err := app.AddRESTHandlers(&amp;amp;Level{})
 if err != nil {
  app.Logger().Fatalf("Failed to register routes for level struct: %v", err)
 }

 app.Run()
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;After running the Log Service we will see the following logs:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F47bwq4whmfe74m3upepo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F47bwq4whmfe74m3upepo.png" alt="LOGS FOR LOG-LEVEL CHANGE SERVICE STARTUP"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We have all the REST routes registered.&lt;/p&gt;

&lt;p&gt;To Create a service send the following request:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl --location 'localhost:8000/level' \
--header 'Content-Type: application/json' \
--data '{
    "id":1,
    "logLevel":"INFO",
    "serviceName":"gofr-app"
}'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;To Update the log level send the following request:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl --location --request PUT 'localhost:8000/level/1' \
--header 'Content-Type: application/json' \
--data '{
    "id":1,
    "logLevel":"DEBUG",
    "serviceName":"gofr-app"
}'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;To Get the log level send the following request:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl --location 'localhost:8000/level/1'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The same URL will be used in the configs of our application whose log-level has to be changed remotely.&lt;/p&gt;

&lt;h2&gt;
  
  
  CONCLUSION
&lt;/h2&gt;

&lt;p&gt;By using GoFr remote Log Level change feature, you will get benefits such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Effortless Adjustments:&lt;br&gt;
Modify the log level anytime without restarting the application. This is especially helpful during troubleshooting.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Enhanced Visibility:&lt;br&gt;
Easily switch to a more detailed log level (e.g., DEBUG) to gain deeper insights into specific issues, and then switch back to a less detailed level (e.g., INFO) for regular operation.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Improved Performance:&lt;br&gt;
Generating a large number of logs can overwhelm the logging system, leading to increased I/O operations and resource consumption, changing to Warn or Error Level reduces the number of logs, and enhancing performance, and &lt;strong&gt;REDUCING CLOUD COST&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Support GoFr by giving a ⭐star:&lt;/strong&gt; &lt;a href="https://github.com/gofr-dev/gofr" rel="noopener noreferrer"&gt;https://github.com/gofr-dev/gofr&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Moreover, you have access to the &lt;strong&gt;free public endpoint to export and view your application's traces&lt;/strong&gt; @ tracer.gofr.dev. &lt;br&gt;
To enable it, add the following config in your .env file&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TRACE_EXPORTER=gofr
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Other Benefits:&lt;/strong&gt;&lt;br&gt;
If you contribute towards GOFR either in development or writing articles. You can get free &lt;strong&gt;swags(T-shirts, Stickers)&lt;/strong&gt; by filling out the form presented on their GitHub &lt;strong&gt;&lt;a href="https://github.com/gofr-dev/gofr/blob/development/README.md" rel="noopener noreferrer"&gt;Readme&lt;/a&gt;&lt;/strong&gt; (at the bottom).&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>go</category>
      <category>backend</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Released! GoFr - An Opinionated Go Framework</title>
      <dc:creator>Aryan Mehrotra</dc:creator>
      <pubDate>Thu, 09 Nov 2023 20:30:40 +0000</pubDate>
      <link>https://forem.com/aryanmehrotra/released-gofr-an-opinionated-go-framework-3142</link>
      <guid>https://forem.com/aryanmehrotra/released-gofr-an-opinionated-go-framework-3142</guid>
      <description>&lt;p&gt;🚀 Hey🌟 &lt;br&gt;
We've been on an incredible journey with GoFr, our opinionated microservice development framework and we have recently opensource it and released the version v1.0.0.&lt;/p&gt;

&lt;p&gt;Our story with GoFr started out of necessity to tackle those cross-cutting concerns inherent in microservice development. Over the years, this framework has evolved and been used in different ways, ultimately becoming what it is today.&lt;/p&gt;

&lt;p&gt;You can star, fork, contribute, and use GoFr in your personal or commercial projects.&lt;/p&gt;

&lt;p&gt;Do visit and share your thoughts! 💬&lt;br&gt;
Github : &lt;a href="https://github.com/gofr-dev/gofr"&gt;https://github.com/gofr-dev/gofr&lt;/a&gt;&lt;br&gt;
Website : &lt;a href="https://gofr.dev"&gt;https://gofr.dev&lt;/a&gt;&lt;/p&gt;

</description>
      <category>go</category>
      <category>database</category>
      <category>opensource</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
