<?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: gvison</title>
    <description>The latest articles on DEV Community by gvison (@zhufuyi).</description>
    <link>https://dev.to/zhufuyi</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%2F990748%2F083e441e-2096-4a50-b79c-ac3a7b0bab8f.jpeg</url>
      <title>DEV Community: gvison</title>
      <link>https://dev.to/zhufuyi</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/zhufuyi"/>
    <language>en</language>
    <item>
      <title>Go in Action: Building a Production-Grade Dynamic Reverse Proxy on Top of Gin</title>
      <dc:creator>gvison</dc:creator>
      <pubDate>Thu, 20 Nov 2025 08:44:15 +0000</pubDate>
      <link>https://dev.to/zhufuyi/go-in-action-building-a-production-grade-dynamic-reverse-proxy-on-top-of-gin-3job</link>
      <guid>https://dev.to/zhufuyi/go-in-action-building-a-production-grade-dynamic-reverse-proxy-on-top-of-gin-3job</guid>
      <description>&lt;h3&gt;
  
  
  Foreword
&lt;/h3&gt;

&lt;p&gt;As backend developers, we are certainly familiar with Nginx. It is the absolute dominator of reverse proxies and load balancing. However, have you encountered this scenario: your business is in a rapid iteration phase, backend service nodes change frequently, or you need to perform canary releases. Every time you adjust the Upstream servers, you have to modify &lt;code&gt;nginx.conf&lt;/code&gt; and then carefully execute &lt;code&gt;nginx -s reload&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Although Nginx has powerful performance, its configuration management can feel slightly "heavy" in certain dynamic scenarios (while Nginx Plus supports dynamic APIs, that is a paid feature; Lua scripts can also achieve this, but maintenance costs are high).&lt;/p&gt;

&lt;p&gt;If you are a Go developer and are currently using the Gin framework, you can completely "embed" reverse proxy capabilities into your business code. Today, I am introducing a production-grade reverse proxy library based on Gin —— &lt;strong&gt;Gin Reverse Proxy&lt;/strong&gt;. It not only replaces some Nginx functions but, more importantly: &lt;strong&gt;it supports dynamic management of routes and nodes via API without restarting the service.&lt;/strong&gt;&lt;/p&gt;



&lt;h3&gt;
  
  
  Why Implement Reverse Proxy in Code?
&lt;/h3&gt;

&lt;p&gt;Usually, we consider reverse proxies an operations matter. But in microservices or cloud-native environments, enabling the gateway layer with programmable capabilities is essential.&lt;/p&gt;

&lt;p&gt;This library &lt;code&gt;github.com/go-dev-frame/sponge/pkg/gin/proxy&lt;/code&gt; is actually built on the Go standard library &lt;code&gt;net/http/httputil&lt;/code&gt;, but it adds a very practical layer of encapsulation:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Dynamic Awareness&lt;/strong&gt;: Bring backend machines online or offline at any time via HTTP API.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Health Checks&lt;/strong&gt;: Similar to Nginx's &lt;code&gt;health_check&lt;/code&gt;, automatically removing bad nodes and reviving them after recovery.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Load Balancing Strategies&lt;/strong&gt;: Built-in Round Robin, Least Connections, and IP Hash.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This means you can write a simple Go program that handles some business logic while also distributing traffic like a gateway, and it is extremely flexible.&lt;/p&gt;



&lt;h3&gt;
  
  
  Quick Start: Build Your Gateway
&lt;/h3&gt;

&lt;p&gt;Assume we want to start a gateway locally to distribute traffic to two backend service clusters (e.g., "Transaction Service" and "User Service").&lt;/p&gt;

&lt;h4&gt;
  
  
  1. Basic Code Implementation
&lt;/h4&gt;

&lt;p&gt;With just a few lines of code, your Gin service can transform into a reverse proxy:&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
    &lt;span class="s"&gt;"github.com/go-dev-frame/sponge/pkg/gin/proxy"&lt;/span&gt;
    &lt;span class="s"&gt;"github.com/gin-gonic/gin"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;gin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Default&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c"&gt;// Initialize proxy middleware; default management interface is mounted at /endpoints&lt;/span&gt;
    &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;proxy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// Configure routing rules&lt;/span&gt;
    &lt;span class="n"&gt;setupProxyRoutes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// Your Gin can still handle normal routes&lt;/span&gt;
    &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GET&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/ping"&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;c&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;gin&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;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;gin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;H&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"message"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"I am the gateway itself"&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Gateway started, listening on :8080"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;":8080"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;setupProxyRoutes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;proxy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Proxy&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// Rule 1: Dispatch requests starting with /proxy/ to cluster A&lt;/span&gt;
    &lt;span class="c"&gt;// Defaults to Round Robin strategy, health check interval of 5 seconds&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;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Pass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/proxy/"&lt;/span&gt;&lt;span class="p"&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;"http://localhost:8081"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
        &lt;span class="s"&gt;"http://localhost:8082"&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="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="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// Rule 2: Dispatch requests starting with /personal/ to cluster B&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;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Pass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/personal/"&lt;/span&gt;&lt;span class="p"&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;"http://localhost:8083"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
        &lt;span class="s"&gt;"http://localhost:8084"&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="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="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&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;Looking at this, you will find it very similar to Nginx's &lt;code&gt;proxy_pass&lt;/code&gt; logic, but it is compiled into the binary file.&lt;/p&gt;



&lt;h4&gt;
  
  
  2. Advanced Configuration: More Than Just Forwarding
&lt;/h4&gt;

&lt;p&gt;Production environments often require finer control. For example, for services requiring Session persistence, we need the IP Hash strategy; for critical services, we need custom health check timings.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;proxy.New&lt;/code&gt; and &lt;code&gt;p.Pass&lt;/code&gt; both support Option pattern configuration, which is very "Go Style":&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;// Fine-grained configuration when registering routes&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;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Pass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/proxy/"&lt;/span&gt;&lt;span class="p"&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;"http://localhost:8081"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"http://localhost:8082"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="n"&gt;proxy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Config&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// Use IP Hash algorithm to ensure requests from the same user hit the same machine&lt;/span&gt;
    &lt;span class="n"&gt;proxy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithPassBalancer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;proxy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BalancerIPHash&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="c"&gt;// Custom health check: once every 5 seconds, timeout 3 seconds&lt;/span&gt;
    &lt;span class="n"&gt;proxy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithPassHealthCheck&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Second&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Second&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="c"&gt;// You can even add middleware (e.g., authentication) to this proxy route individually&lt;/span&gt;
    &lt;span class="n"&gt;proxy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithPassMiddlewares&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AuthMiddleware&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This step is very powerful. In Nginx, configuring authentication is usually troublesome (requiring modules like auth_request), whereas in Go, this is just a standard Gin Middleware.&lt;/p&gt;



&lt;h3&gt;
  
  
  Killer Feature: Runtime Dynamic Management
&lt;/h3&gt;

&lt;p&gt;This is the most attractive part of this library.&lt;/p&gt;

&lt;p&gt;Previously, if &lt;code&gt;localhost:8081&lt;/code&gt; went down, or you needed to scale out to include a new machine &lt;code&gt;8085&lt;/code&gt;, you usually had to modify configuration and restart the gateway. But here, after the proxy service starts, it automatically exposes management APIs (default under &lt;code&gt;/endpoints&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;You can command your gateway directly via HTTP requests.&lt;/p&gt;

&lt;h4&gt;
  
  
  Scenario 1: Service Scaling
&lt;/h4&gt;

&lt;p&gt;Traffic spikes during a sale, and you temporarily start a new machine &lt;code&gt;http://localhost:8085&lt;/code&gt;. You want the gateway to distribute traffic to it immediately.&lt;/p&gt;

&lt;p&gt;Send a POST request directly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://localhost:8080/endpoints/add &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
           "prefixPath": "/proxy/",
           "targets": ["http://localhost:8085"]
         }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Takes effect instantly.&lt;/strong&gt; The new node automatically joins the load balancing pool and begins accepting health checks.&lt;/p&gt;



&lt;h4&gt;
  
  
  Scenario 2: Node Offline / Canary Release
&lt;/h4&gt;

&lt;p&gt;If you find &lt;code&gt;8085&lt;/code&gt; has a high error rate or needs an upgrade, you need to take it offline gracefully.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://localhost:8080/endpoints/remove &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
           "prefixPath": "/proxy/",
           "targets": ["http://localhost:8085"]
         }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;h4&gt;
  
  
  Scenario 3: Monitoring Dashboard
&lt;/h4&gt;

&lt;p&gt;If you want to know the current health status of all backend nodes, directly call the &lt;code&gt;list&lt;/code&gt; interface:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl http://localhost:8080/endpoints/list?prefixPath&lt;span class="o"&gt;=&lt;/span&gt;/proxy/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The returned result is clear:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"prefixPath"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/proxy/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"targets"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"target"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http://localhost:8081"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"healthy"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"target"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http://localhost:8082"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"healthy"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; 
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;h3&gt;
  
  
  Summary and Suggestions
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;When should you use it?&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Go Tech Stack Teams&lt;/strong&gt;: If your team primarily uses Go, maintaining a Go-based gateway is much easier than maintaining Nginx configuration files.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;High Customization Logic&lt;/strong&gt;: For example, if you need to read a blocklist from Redis before forwarding, or perform complex signature verification on the request body, writing middleware in Go is much more comfortable than writing Nginx Lua scripts.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Small/Medium Dynamic Environments&lt;/strong&gt;: For lightweight deployments outside of k8s, or development/test environments, dynamically adjusting routing via API is very convenient.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;When should you still use Nginx?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Static resource serving (CDN level).&lt;/li&gt;
&lt;li&gt;  Extremely massive concurrency (Millions of QPS), where Nginx's C-based optimizations remain the ceiling.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Overall, &lt;strong&gt;Gin Reverse Proxy&lt;/strong&gt; offers a middle ground between "hard coding" and "pure operations tools." It returns control of load balancing and reverse proxying to developers, allowing the network layer to be as flexible and versatile as business logic.&lt;/p&gt;

&lt;p&gt;If you are fed up with frequently reloading Nginx, try this solution in your next project.&lt;/p&gt;








&lt;p&gt;&lt;code&gt;proxy&lt;/code&gt; is a built-in library of Sponge. Sponge is a powerful and easy-to-use Go development framework that integrates &lt;strong&gt;code generation&lt;/strong&gt;, &lt;strong&gt;Web framework (Gin)&lt;/strong&gt;, and &lt;strong&gt;microservice framework (gRPC)&lt;/strong&gt;, covering the full lifecycle from project generation, development, and testing to API documentation and deployment. Sponge aims to improve backend service development efficiency and code quality, eliminating tedious repetitive work and focusing on the implementation of core business logic.&lt;/p&gt;

&lt;p&gt;Sponge's core philosophy is &lt;strong&gt;"Definitions as Code"&lt;/strong&gt;. By parsing SQL, Protobuf, and JSON configuration files, it generates modular service code. Developers can flexibly combine these modules to quickly build various backend systems such as RESTful APIs, gRPC, HTTP+gRPC, gRPC Gateway, or microservice clusters via a &lt;strong&gt;low-code&lt;/strong&gt; approach.&lt;/p&gt;

&lt;p&gt;Sponge Github Address: &lt;a href="https://github.com/go-dev-frame/sponge" rel="noopener noreferrer"&gt;https://github.com/go-dev-frame/sponge&lt;/a&gt;&lt;/p&gt;

</description>
      <category>go</category>
      <category>proxy</category>
      <category>nginx</category>
      <category>gin</category>
    </item>
    <item>
      <title>No More Complex Scripts! PerfTest Distributed Load Testing Uses a Single YAML to Orchestrate Massive Cluster Tests Gracefully</title>
      <dc:creator>gvison</dc:creator>
      <pubDate>Tue, 14 Oct 2025 11:00:49 +0000</pubDate>
      <link>https://dev.to/zhufuyi/no-more-complex-scripts-perftest-distributed-load-testing-uses-a-single-yaml-to-orchestrate-2o48</link>
      <guid>https://dev.to/zhufuyi/no-more-complex-scripts-perftest-distributed-load-testing-uses-a-single-yaml-to-orchestrate-2o48</guid>
      <description>&lt;h3&gt;
  
  
  Preface
&lt;/h3&gt;

&lt;p&gt;In the previous article, we detailed the single-machine stress testing capabilities of &lt;code&gt;perftest&lt;/code&gt;, showcasing how it achieves high-performance testing for HTTP/1.1, HTTP/2, HTTP/3, and WebSocket with a minimalist command-line interface. However, when dealing with large-scale business systems, distributed service deployments, and complex network links, the capabilities of a single machine are clearly insufficient to simulate real-world production environments.&lt;/p&gt;

&lt;p&gt;Fortunately, &lt;code&gt;perftest&lt;/code&gt; goes beyond a single machine. It also supports &lt;strong&gt;distributed cluster stress testing&lt;/strong&gt;. Through a &lt;strong&gt;Collector + Agent&lt;/strong&gt; architecture, you can easily launch tests from multiple machines simultaneously, enabling performance assessments at the scale of millions or even tens of millions of concurrent users.&lt;/p&gt;



&lt;h3&gt;
  
  
  Why Choose Distributed Cluster Stress Testing?
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1. Replicate Real-World Traffic Scenarios&lt;/strong&gt;&lt;br&gt;
Single-machine testing cannot simulate user access behavior from different geographical regions, network environments, and latency conditions. Distributed cluster testing allows requests to be sent from multiple geographical nodes at the same time, more closely resembling a real production environment.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Break Through Performance Bottlenecks&lt;/strong&gt;&lt;br&gt;
When a single machine's CPU, memory, or network bandwidth reaches its limit, the test results are no longer accurate. &lt;code&gt;perftest&lt;/code&gt; avoids a single point of failure by distributing requests across multiple machines.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Validate the System's Horizontal Scaling Capabilities&lt;/strong&gt;&lt;br&gt;
When your application runs in Kubernetes, a Service Mesh, or a microservices cluster, distributed stress testing can help you verify your system's load balancing strategies and elastic scaling effectiveness under high concurrency scenarios.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Provide More Comprehensive Data Observation&lt;/strong&gt;&lt;br&gt;
Real-time monitoring in cluster mode not only allows you to see overall QPS and latency curves but also to break down the performance distribution of each Agent node, precisely locating performance bottlenecks.&lt;/p&gt;


&lt;h3&gt;
  
  
  Architecture Design: Collector and Agent
&lt;/h3&gt;

&lt;p&gt;The distributed stress testing system of &lt;code&gt;perftest&lt;/code&gt; adopts a minimalist and stable &lt;strong&gt;Master-Agent (Collector-Agent) architecture&lt;/strong&gt;, as shown in the diagram below:&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%2Fs4patmci935ir2bkh18o.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%2Fs4patmci935ir2bkh18o.png" alt=" " width="800" height="428"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Collector (Master Node)&lt;/strong&gt;&lt;br&gt;
Responsible for creating test sessions, scheduling all Agents, aggregating performance metrics, and displaying overall data in real-time on a Web UI.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Agent (Execution Node)&lt;/strong&gt;&lt;br&gt;
Actually executes the stress testing tasks and periodically pushes performance metrics to the Collector. The Agent features mechanisms like automatic registration, hot-reloading of configurations, and automatic reconnection to ensure stable operation in large-scale distributed scenarios.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can think of it as a "commander" (Collector) directing a stress testing "army" composed of multiple "soldiers" (Agents)—with a single command, all nodes open fire simultaneously.&lt;/p&gt;


&lt;h3&gt;
  
  
  How It Works: From Registration to Aggregation
&lt;/h3&gt;

&lt;p&gt;The entire stress testing process is very clear:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Start the Collector:&lt;/strong&gt; The Collector service starts and provides a web management interface.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Create a Test Session:&lt;/strong&gt; In the web interface, specify the desired number of agent nodes to participate in the test, then start a new session.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Start the Agents:&lt;/strong&gt; After each agent starts, it reads its configuration file and automatically registers with the Collector.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Start the Test:&lt;/strong&gt; Once the preset number of agents have completed registration, the Collector notifies all agents to start the stress test simultaneously.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Aggregate Results:&lt;/strong&gt; Agents push performance data (throughput, latency, etc.) to the Collector in real-time, which the Collector displays on a live dashboard.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Test End and Report Export:&lt;/strong&gt; After the test is finished, the Collector automatically generates a complete report in Markdown format, which can be downloaded and saved with one click.&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Tip:&lt;/strong&gt; The Agent actively listens to its &lt;code&gt;agent.yml&lt;/code&gt; configuration file. Any changes will be automatically hot-reloaded without restarting the agent process, making it very convenient to adjust test parameters.&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h3&gt;
  
  
  Quick Start: A Simple Cluster Example
&lt;/h3&gt;

&lt;p&gt;Here is a basic cluster example with 1 Collector and 3 Agents:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Role&lt;/th&gt;
&lt;th&gt;IP Address&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Collector&lt;/td&gt;
&lt;td&gt;192.168.1.20&lt;/td&gt;
&lt;td&gt;Management Node&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Agent 1&lt;/td&gt;
&lt;td&gt;192.168.1.101&lt;/td&gt;
&lt;td&gt;Execution Node&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Agent 2&lt;/td&gt;
&lt;td&gt;192.168.1.102&lt;/td&gt;
&lt;td&gt;Execution Node&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Agent 3&lt;/td&gt;
&lt;td&gt;192.168.1.103&lt;/td&gt;
&lt;td&gt;Execution Node&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;h4&gt;
  
  
  Step 1. Start the Collector
&lt;/h4&gt;

&lt;p&gt;On machine 1 (&lt;code&gt;192.168.1.20&lt;/code&gt;), start the Collector service:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;sponge perftest collector
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Access &lt;code&gt;http://192.168.1.20:8888&lt;/code&gt; in your browser, create a new test session, and set the number of Agents to 3.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 2. Start the Agents
&lt;/h4&gt;

&lt;p&gt;Example &lt;code&gt;agent.yml&lt;/code&gt; configuration file for each Agent:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# 1. Protocol Configuration (supports: http | http2 | http3)&lt;/span&gt;
&lt;span class="na"&gt;protocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;http&lt;/span&gt;

&lt;span class="c1"&gt;# 2. Target API Configuration&lt;/span&gt;
&lt;span class="na"&gt;testURL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http://localhost:8080/get"&lt;/span&gt;
&lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;GET"&lt;/span&gt;        &lt;span class="c1"&gt;# Supported methods: GET | POST | PUT | PATCH | DELETE&lt;/span&gt;
&lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;             &lt;span class="c1"&gt;# Supported data types: JSON, Form-data, Text. e.g.: "{\"key\": \"value\"}"&lt;/span&gt;
&lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Authorization:&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Bearer&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;lt;token&amp;gt;"&lt;/span&gt;
  &lt;span class="c1"&gt;#- "Content-Type: application/json"&lt;/span&gt;

&lt;span class="c1"&gt;# 3. Stress Test Strategy (choose one: fixed duration or fixed number of requests)&lt;/span&gt;
&lt;span class="na"&gt;duration&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;10s&lt;/span&gt;        &lt;span class="c1"&gt;# e.g.: 10s, 1m, 2h&lt;/span&gt;
&lt;span class="c1"&gt;# total: 500000      # Total number of requests&lt;/span&gt;

&lt;span class="c1"&gt;# 4. Service Discovery, ensure the collector and agent services can communicate&lt;/span&gt;
&lt;span class="na"&gt;collectorHost&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http://192.168.1.20:8888"&lt;/span&gt;      &lt;span class="c1"&gt;# Address of the Collector service&lt;/span&gt;
&lt;span class="na"&gt;agentHost&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http://&amp;lt;agent-host-ip&amp;gt;:6601"&lt;/span&gt;       &lt;span class="c1"&gt;# The accessible IP and port of the current agent&lt;/span&gt;
&lt;span class="na"&gt;agentPushInterval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;1s&lt;/span&gt;                          &lt;span class="c1"&gt;# Metric push frequency&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Important Note:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Please replace &lt;code&gt;&amp;lt;agent-host-ip&amp;gt;&lt;/code&gt; in &lt;code&gt;agentHost&lt;/code&gt; with the actual IP address of each agent machine.&lt;/li&gt;
&lt;li&gt;For the same test session, the &lt;code&gt;testURL&lt;/code&gt; and &lt;code&gt;method&lt;/code&gt; in all agent configuration files must be identical.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;Start the agent processes on machines 2, 3, and 4 respectively:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;sponge perftest agent &lt;span class="nt"&gt;-c&lt;/span&gt; agent.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once all 3 Agents have successfully registered, the Collector will automatically synchronize and start the stress test, displaying real-time graphs as shown below:&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%2Fctp9fhnk4752rr8a6cbj.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%2Fctp9fhnk4752rr8a6cbj.png" alt=" " width="800" height="1263"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After the test is complete, you can also click &lt;strong&gt;"Download Test Report"&lt;/strong&gt; to get a detailed Markdown report, including all statistical metrics and chart data, for subsequent analysis or performance regression comparisons.&lt;/p&gt;



&lt;h3&gt;
  
  
  Automated Deployment in Kubernetes Scenarios
&lt;/h3&gt;

&lt;p&gt;For large-scale testing, managing nodes manually is impractical. &lt;code&gt;perftest&lt;/code&gt; can be easily deployed on Kubernetes, allowing you to scale your number of agents effortlessly.&lt;/p&gt;

&lt;p&gt;A complete YAML deployment manifest and specific operational examples are provided. Please see the documentation &lt;a href="https://go-sponge.com/component/monitor/perftest.html#deploying-perftest-on-kubernetes" rel="noopener noreferrer"&gt;Deploying perftest on Kubernetes&lt;/a&gt;.&lt;/p&gt;



&lt;h3&gt;
  
  
  Horizontal Comparison: The "Players" in Distributed Stress Testing
&lt;/h3&gt;

&lt;p&gt;The distributed capability of &lt;code&gt;perftest&lt;/code&gt; is also unique. Let's see how it compares to other mainstream distributed stress testing tools in the industry.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature / Tool&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;JMeter&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Locust&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;k6 (Distributed)&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;perftest (Distributed)&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Core Architecture&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;GUI Master + Agents&lt;/td&gt;
&lt;td&gt;Code-based Master/Worker&lt;/td&gt;
&lt;td&gt;k6 Operator / CRD&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Web-UI Collector + Agents&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Test Definition&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;GUI (XML)&lt;/td&gt;
&lt;td&gt;Python script&lt;/td&gt;
&lt;td&gt;JavaScript script&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;YAML Configuration&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Resource Consumption&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;High (Java/GUI)&lt;/td&gt;
&lt;td&gt;Medium (Python/gevent)&lt;/td&gt;
&lt;td&gt;Medium (Go)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Low (Go)&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;K8s/Cloud-Native&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Complex (requires self-containerization)&lt;/td&gt;
&lt;td&gt;Good (provides Helm Chart)&lt;/td&gt;
&lt;td&gt;Excellent (native Operator)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Natively Friendly (provides deployment manifest)&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Ease of Use&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Extremely Low&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Dynamic Configuration&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Requires restart&lt;/td&gt;
&lt;td&gt;Requires restart&lt;/td&gt;
&lt;td&gt;Requires restart&lt;/td&gt;
&lt;td&gt;✅ &lt;strong&gt;(Hot-reloading)&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;JMeter (The Veteran)&lt;/strong&gt;: The most powerful and comprehensive stress testing tool, with a vast ecosystem of plugins. However, its Java and GUI-based architecture makes it resource-intensive, and its deployment and automation in cloud-native environments are relatively cumbersome.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Locust (The Coder's Choice)&lt;/strong&gt;: Defines user behavior in Python, making it very friendly for programmers and easy to write complex business logic. Its Master/Worker architecture is clear, but large-scale deployment still requires some DevOps experience.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;k6 (The Modern Contender)&lt;/strong&gt;: k6 is deeply integrated with Kubernetes for distributed testing, managing tests through an Operator and CRDs (Custom Resources), making it a powerful choice for cloud-native scenarios. However, it still relies on writing JavaScript scripts to define the load.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;perftest (The Pragmatist)&lt;/strong&gt;: &lt;code&gt;perftest&lt;/code&gt; continues its "simple and pure" philosophy in distributed scenarios. It &lt;strong&gt;replaces scripts with configuration&lt;/strong&gt;, greatly lowering the barrier to entry for distributed stress testing. Its Collector + Agent architecture is clear and easy to understand, allowing tests to be initiated and monitored via a Web UI, and it provides out-of-the-box Kubernetes deployment files. The &lt;strong&gt;hot-reloading&lt;/strong&gt; feature makes adjusting test parameters exceptionally efficient, eliminating the need to rebuild and redeploy, perfectly fitting the needs of agile iteration.&lt;/li&gt;
&lt;/ul&gt;



&lt;h3&gt;
  
  
  Conclusion: From Single-Point to Cluster, Simple but Not Simplistic
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;perftest&lt;/code&gt; does not intend to replace comprehensive "Swiss Army knife" tools like &lt;code&gt;k6&lt;/code&gt; or &lt;code&gt;JMeter&lt;/code&gt;. Instead, it offers developers and SRE engineers a more modern, focused, and cloud-native-friendly option.&lt;/p&gt;

&lt;p&gt;It cleverly covers two core scenarios of performance testing:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;For single-machine stress testing&lt;/strong&gt;, it is a sharp "scalpel," allowing you to quickly validate and compare the latest network protocols, including &lt;strong&gt;HTTP/3&lt;/strong&gt; and &lt;strong&gt;WebSocket&lt;/strong&gt;, with a minimal learning curve. Through seamless integration with &lt;strong&gt;Prometheus&lt;/strong&gt;, it incorporates performance data into your observability system.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;For distributed stress testing&lt;/strong&gt;, it is a lightweight "command center." Through a concise Collector-Agent architecture and a &lt;strong&gt;configuration-driven&lt;/strong&gt; model, it minimizes the complexity of large-scale stress testing. Its native friendliness to Kubernetes allows it to easily scale to hundreds or thousands of load-generating nodes to simulate massive concurrency.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When your needs are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Single-machine or cluster stress testing of services or systems using http1/2/3 protocols.&lt;/li&gt;
&lt;li&gt;Quickly validating the performance of the latest network protocols (HTTP/3, WebSocket).&lt;/li&gt;
&lt;li&gt;Seamlessly integrating performance testing with the Prometheus monitoring system for visualized stress testing.&lt;/li&gt;
&lt;li&gt;Performing lightweight performance regression testing in CI/CD.&lt;/li&gt;
&lt;li&gt;Quickly setting up and executing large-scale distributed stress tests without writing complex scripts.&lt;/li&gt;
&lt;li&gt;Easily achieving elastic scaling of stress testing capabilities in a Kubernetes environment.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then, &lt;code&gt;perftest&lt;/code&gt; is definitely worth a try. In an era of increasingly complex tools, such a tool that can smoothly scale from a "small and beautiful" single-machine utility to a "broad and strong" distributed platform may be the best answer you've been looking for to tackle modern web performance challenges.&lt;/p&gt;






&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;perftest&lt;/code&gt; is a component of the &lt;strong&gt;Sponge&lt;/strong&gt; ecosystem. &lt;strong&gt;Sponge&lt;/strong&gt; is a powerful and easy-to-use Go development framework that adheres to the core philosophy of "Definition is Code." It enables the easy construction of stable, reliable, and high-performance backend services through a low-code approach, supporting various service types including RESTful API, gRPC, HTTP+gRPC, and gRPC Gateway. Sponge's built-in AI assistant can perceive service code files and their context, generating more suitable business logic code under precise AI constraints, significantly improving development efficiency.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sponge Github Address:&lt;/strong&gt; &lt;a href="https://github.com/go-dev-frame/sponge" rel="noopener noreferrer"&gt;https://github.com/go-dev-frame/sponge&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>test</category>
      <category>performance</category>
      <category>go</category>
      <category>tooling</category>
    </item>
    <item>
      <title>PerfTest: The "Swiss Army Knife" of Load Testing Tools, Natively Supporting HTTP/1/2/3 and WebSocket with Real-Time Monitoring</title>
      <dc:creator>gvison</dc:creator>
      <pubDate>Fri, 12 Sep 2025 15:48:57 +0000</pubDate>
      <link>https://dev.to/zhufuyi/perftest-the-swiss-army-knife-of-load-testing-tools-natively-supporting-http123-and-3m3p</link>
      <guid>https://dev.to/zhufuyi/perftest-the-swiss-army-knife-of-load-testing-tools-natively-supporting-http123-and-3m3p</guid>
      <description>&lt;h3&gt;
  
  
  Preface
&lt;/h3&gt;

&lt;p&gt;Every backend engineer keeps a few load testing tools handy in their toolbox. When we want to quickly check the performance of an API, &lt;code&gt;ab&lt;/code&gt; is often the first tool we reach for. If we’re chasing maximum single-machine QPS, &lt;code&gt;wrk&lt;/code&gt; is usually the weapon of choice. And when it comes to writing complex test scenarios, &lt;code&gt;k6&lt;/code&gt;, with its powerful scripting capabilities and developer-friendly ecosystem, has become the go-to for many teams. Of course, there are plenty of other tools out there as well.&lt;/p&gt;

&lt;p&gt;All of these tools are great, but technology doesn’t stand still. HTTP/3 has moved from being “the future” to “the present,” WebSocket use cases are becoming more common, and in today’s DevOps world, one-off, static performance reports are no longer enough. What we really need is real-time performance data that integrates seamlessly into our observability stack.&lt;/p&gt;

&lt;p&gt;This naturally raises a question:&lt;br&gt;
Is there a tool that’s as simple and straightforward as &lt;code&gt;ab&lt;/code&gt;, supports modern protocols like HTTP/3 and WebSocket, and integrates with monitoring systems like Prometheus just as easily as &lt;code&gt;k6&lt;/code&gt;?&lt;/p&gt;

&lt;p&gt;The answer is yes. Let me introduce you to a rising star—&lt;code&gt;perftest&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  What is PerfTest?
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;perftest&lt;/code&gt; is a lightweight, high-performance load testing tool integrated into the &lt;a href="https://github.com/go-dev-frame/sponge" rel="noopener noreferrer"&gt;Sponge Go framework&lt;/a&gt;. Think of it as a “special forces operator” designed for modern network protocols and cloud-native monitoring.&lt;/p&gt;

&lt;p&gt;Its key highlights are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Protocol versatility&lt;/strong&gt;: Native support for HTTP/1.1, HTTP/2, HTTP/3, and WebSocket.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flexible modes&lt;/strong&gt;: Run a fixed number of requests (&lt;code&gt;--total&lt;/code&gt;) or apply load continuously for a given duration (&lt;code&gt;--duration&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Seamless monitoring integration&lt;/strong&gt;: Its killer feature. &lt;code&gt;perftest&lt;/code&gt; can stream real-time metrics (QPS, latency, etc.) directly into Prometheus or any custom HTTP endpoint—your Grafana dashboards will light up instantly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Simplicity&lt;/strong&gt;: Everything is controlled through clean, minimal CLI parameters, making it incredibly easy to learn.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  When should you use PerfTest?
&lt;/h3&gt;

&lt;p&gt;There are a few scenarios where &lt;code&gt;perftest&lt;/code&gt; really shines:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Testing cutting-edge protocols&lt;/strong&gt;&lt;br&gt;
If your service supports HTTP/3 or gRPC-Web (built on HTTP/2+), &lt;code&gt;perftest&lt;/code&gt; helps you measure the performance benefits without extra hassle.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Load testing real-time communication&lt;/strong&gt;&lt;br&gt;
Have a chat app, real-time trading platform, or collaborative editor using WebSockets? &lt;code&gt;perftest&lt;/code&gt; can simulate large client loads and high-frequency message storms to validate your backend capacity.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Performance checks in CI/CD&lt;/strong&gt;&lt;br&gt;
Add &lt;code&gt;perftest&lt;/code&gt; as a step in your pipeline. After every merge, it can benchmark critical endpoints, push metrics to Prometheus, and trigger alerts when performance regresses.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Quick and simple validation&lt;/strong&gt;&lt;br&gt;
Don’t want to write a full &lt;code&gt;k6&lt;/code&gt; script just to test one API? With &lt;code&gt;perftest&lt;/code&gt;, you can run a concurrency test in seconds and get a detailed report.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  Getting Started
&lt;/h3&gt;

&lt;p&gt;Since &lt;code&gt;perftest&lt;/code&gt; is built in Go, installation is as simple as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go &lt;span class="nb"&gt;install &lt;/span&gt;github.com/go-dev-frame/sponge/cmd/sponge@latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once installed, you’re ready to run tests. Let’s look at some examples.&lt;/p&gt;

&lt;h4&gt;
  
  
  HTTP Load Testing Example
&lt;/h4&gt;

&lt;p&gt;Benchmark an HTTP/1.1 endpoint with 50 workers and 1 million requests:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;sponge perftest http &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--worker&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;50 &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--total&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1000000 &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;http://localhost:8080/user/1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run a continuous 1-minute test instead:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;sponge perftest http &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--worker&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;50 &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--duration&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1m &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;http://localhost:8080/user/1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Switching to HTTP/2 or HTTP/3? Just replace &lt;code&gt;http&lt;/code&gt; with &lt;code&gt;http2&lt;/code&gt; or &lt;code&gt;http3&lt;/code&gt;. Everything else stays the same.&lt;/p&gt;

&lt;p&gt;Want live metrics in Prometheus? Add &lt;code&gt;--prometheus-job-name&lt;/code&gt; and &lt;code&gt;--push-url&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;At the end, you’ll get a detailed report:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;========== HTTP/1.1 Performance Test Report ==========

[Requests]
  • Total Requests:    1000000
  • Successful:        1000000 (100%)
  • Failed:            0
  • Total Duration:    8.55 s
  • Throughput (QPS):  116914.5 req/sec

[Latency]
  • Average:           0.42 ms
  • Minimum:           0 ms
  • Maximum:           22.41 ms
  • P25:               0 ms
  • P50:               0.51 ms
  • P95:               1.18 ms

[Data Transfer]
  • Sent:              25000000 Bytes
  • Received:          49000000 Bytes

[Status Codes]
  • 200:               1000000

[Push Statistics]
  • ok
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Prefer a UI instead of CLI? Just run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;sponge run
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then navigate to &lt;strong&gt;Public → Generate Performance Test Report&lt;/strong&gt;, fill in parameters, and start testing.&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%2Fnvenh2k6zdyg6v70h68m.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%2Fnvenh2k6zdyg6v70h68m.png" alt=" " width="800" height="532"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Simulating a WebSocket Message Storm
&lt;/h4&gt;

&lt;p&gt;Let’s simulate 100 users chatting simultaneously, each sending 2 messages per second (every 500ms) for 5 minutes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;sponge perftest websocket &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--worker&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;100 &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--duration&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;5m &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--send-interval&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;500ms &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--body&lt;/span&gt;&lt;span class="o"&gt;={&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;event&lt;span class="se"&gt;\"&lt;/span&gt;:&lt;span class="se"&gt;\"&lt;/span&gt;message&lt;span class="se"&gt;\"&lt;/span&gt;,&lt;span class="se"&gt;\"&lt;/span&gt;payload&lt;span class="se"&gt;\"&lt;/span&gt;:&lt;span class="se"&gt;\"&lt;/span&gt;Hello, perftest!&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ws://localhost:8080/ws
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At the end, you’ll see clear stats on connection success rates, messages sent/received, and throughput.&lt;/p&gt;

&lt;h3&gt;
  
  
  PerfTest vs. ab, wrk, k6
&lt;/h3&gt;

&lt;p&gt;How does &lt;code&gt;perftest&lt;/code&gt; compare against the classics?&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature / Tool&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;ab&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;wrk / wrk2&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;k6&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;perftest&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Core focus&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Simple validation&lt;/td&gt;
&lt;td&gt;Extreme performance&lt;/td&gt;
&lt;td&gt;Complex scenarios &amp;amp; developer UX&lt;/td&gt;
&lt;td&gt;Modern protocols &amp;amp; monitoring&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;HTTP/1.1&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;HTTP/2&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌ (special branch)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;HTTP/3 (QUIC)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌ (community add-on)&lt;/td&gt;
&lt;td&gt;✅ (native)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;WebSocket&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌ (script needed)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Real-time metrics&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅ (native)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Scripting&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;Lua&lt;/td&gt;
&lt;td&gt;JavaScript&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Ease of use&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Very low&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;td&gt;Very low&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Deep Dive
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ab (The Old Guard)&lt;/strong&gt;: Simple and reliable, but limited to HTTP/1.1.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;wrk (The Speedster)&lt;/strong&gt;: Blazing fast, great for raw throughput, but weak protocol support.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;k6 (The Powerhouse)&lt;/strong&gt;: Rich ecosystem, powerful scripting, widely adopted, but HTTP/3 support is still unofficial.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;perftest (The Specialist)&lt;/strong&gt;: Excels in two areas:&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Cutting-edge protocol support (HTTP/3, WebSocket).&lt;/li&gt;
&lt;li&gt;Native integration with Prometheus for effortless observability.&lt;/li&gt;
&lt;/ol&gt;

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

&lt;p&gt;&lt;code&gt;perftest&lt;/code&gt; is a modern, focused load testing tool designed for today’s cloud-native world.&lt;/p&gt;

&lt;p&gt;It’s perfect if you need to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Benchmark new protocols like HTTP/3 or WebSocket.&lt;/li&gt;
&lt;li&gt;Stream performance metrics directly into Prometheus and visualize them in Grafana.&lt;/li&gt;
&lt;li&gt;Add lightweight performance checks to your CI/CD pipeline.&lt;/li&gt;
&lt;li&gt;Use something stronger than &lt;code&gt;ab&lt;/code&gt; but lighter than &lt;code&gt;k6&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In short, &lt;code&gt;perftest&lt;/code&gt; is like a sharp scalpel: precise, efficient, and built for modern performance testing. At a time when tools are getting bigger and heavier, this small but powerful utility might be exactly what you’ve been looking for.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Upcoming: Distributed cluster testing, with a central coordinator managing multiple nodes.&lt;/p&gt;
&lt;/blockquote&gt;






&lt;p&gt;💡 &lt;strong&gt;About Sponge&lt;/strong&gt;&lt;br&gt;
Sponge is a powerful and easy-to-use Go framework. With the philosophy of &lt;em&gt;“Definition is Code”&lt;/em&gt;, it makes it easy to build stable, reliable, high-performance backend services using a low-code approach. It supports RESTful API, gRPC, HTTP+gRPC, and gRPC Gateway.&lt;br&gt;
Its built-in AI assistant can analyze your service code in context and generate business logic intelligently, significantly improving development efficiency.&lt;/p&gt;

&lt;p&gt;👉 GitHub: &lt;a href="https://github.com/go-dev-frame/sponge" rel="noopener noreferrer"&gt;https://github.com/go-dev-frame/sponge&lt;/a&gt;&lt;/p&gt;

</description>
      <category>http</category>
      <category>websocket</category>
      <category>performancetest</category>
      <category>testing</category>
    </item>
    <item>
      <title>Sponge: A Framework That Reshapes the Go Development Experience and Supercharges Your Projects</title>
      <dc:creator>gvison</dc:creator>
      <pubDate>Sun, 24 Aug 2025 15:38:51 +0000</pubDate>
      <link>https://dev.to/zhufuyi/sponge-a-framework-that-reshapes-the-go-development-experience-and-supercharges-your-projects-451f</link>
      <guid>https://dev.to/zhufuyi/sponge-a-framework-that-reshapes-the-go-development-experience-and-supercharges-your-projects-451f</guid>
      <description>&lt;h3&gt;
  
  
  Preface
&lt;/h3&gt;

&lt;p&gt;Go is simple, efficient, and outstanding in concurrency performance—a true breath of fresh air in backend development. We love its purity and its “less is more” philosophy. But let’s be honest: this “purity” sometimes means starting from scratch, reinventing the wheel every single time.&lt;/p&gt;

&lt;p&gt;Every day you’re writing similar &lt;strong&gt;boilerplate code&lt;/strong&gt;, handling endless database CRUD operations, manually binding data and registering services for HTTP and gRPC… Feels draining, right? Project iterations fly by, requirements pile up, yet you’re still stuck with headaches about project structure, dependency management, logging, and configuration.&lt;/p&gt;

&lt;p&gt;It’s like wanting to drive an F1 car, but instead spending all day hand-assembling the tires.&lt;/p&gt;

&lt;p&gt;That’s the reality of the &lt;strong&gt;traditional Go development model&lt;/strong&gt;. While it offers high flexibility and full control over details, the downsides are clear:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Efficiency bottlenecks&lt;/strong&gt;: Repetitive tasks slow down the pace of core business logic.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mental overhead&lt;/strong&gt;: Beyond business needs, you also have to handle engineering, maintainability, and scalability issues.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Uneven wheel quality&lt;/strong&gt;: Homemade wheels might “work,” but not necessarily “work well.” Robustness and performance often become concerns.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So we can’t help but ask: &lt;em&gt;isn’t there a way to enjoy Go’s high performance while escaping this sea of repetitive work?&lt;/em&gt;&lt;/p&gt;



&lt;h3&gt;
  
  
  Enter the Modern Framework
&lt;/h3&gt;

&lt;p&gt;Yes, there is! Just like equipping a hero with legendary gear, modern Go frameworks aim to solve these pain points. They integrate common components and best practices for project development, freeing you to focus on business logic.&lt;/p&gt;

&lt;p&gt;You might worry: “Isn’t it too heavy?” “Will it restrict my freedom?” “What about performance overhead?”&lt;/p&gt;

&lt;p&gt;Those are valid concerns. A good framework should act like a &lt;strong&gt;helpful assistant&lt;/strong&gt;, not a boss barking orders. It should deliver:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;High cohesion, low coupling&lt;/strong&gt;: Rich functionality, but modular and flexible to use.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Convention over configuration&lt;/strong&gt;: Follow widely accepted practices, reduce decision-making cost, and still keep extensibility.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Code generation, productivity boost&lt;/strong&gt;: Automate repetitive, error-prone work so you can focus on creativity.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Which brings us to today’s star: &lt;strong&gt;Sponge&lt;/strong&gt;—a “magic tool” dedicated to improving Go development efficiency and experience.&lt;/p&gt;



&lt;h3&gt;
  
  
  Sponge: Making Go Development as Natural as Breathing
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Sponge&lt;/strong&gt; is a fascinating open-source project. Its core philosophy is &lt;em&gt;“definition is code”&lt;/em&gt;, embracing the low-code approach to free you from manual labor.&lt;/p&gt;

&lt;p&gt;The coolest part? Like a sponge, it can “absorb” common capabilities and quickly build a stable, reliable, high-performance backend service for you.&lt;/p&gt;



&lt;h4&gt;
  
  
  One-Click Code Generation: CRUD Is Nothing
&lt;/h4&gt;

&lt;p&gt;Picture this: your product manager hands you a prototype with dozens of database tables. Normally, you’d start grumbling while writing DAOs, services, APIs…&lt;/p&gt;

&lt;p&gt;But in Sponge’s world, all you need is to define your database schema (say, a MySQL DDL), then… click a button!&lt;/p&gt;

&lt;p&gt;Yes, you read that right. Sponge can &lt;strong&gt;generate a complete backend service codebase from your data model&lt;/strong&gt;, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;HTTP/gRPC service framework code&lt;/li&gt;
&lt;li&gt;Service/Handler layer code&lt;/li&gt;
&lt;li&gt;DAO layer data access code&lt;/li&gt;
&lt;li&gt;Swagger (OpenAPI) documentation&lt;/li&gt;
&lt;li&gt;Route registration code&lt;/li&gt;
&lt;li&gt;Unit test code&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, with a simple &lt;code&gt;user&lt;/code&gt; table:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="nv"&gt;`user`&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nv"&gt;`id`&lt;/span&gt; &lt;span class="nb"&gt;bigint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nb"&gt;unsigned&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt; &lt;span class="n"&gt;AUTO_INCREMENT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nv"&gt;`name`&lt;/span&gt; &lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nv"&gt;`email`&lt;/span&gt; &lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nv"&gt;`created_at`&lt;/span&gt; &lt;span class="nb"&gt;datetime&lt;/span&gt; &lt;span class="k"&gt;DEFAULT&lt;/span&gt; &lt;span class="k"&gt;CURRENT_TIMESTAMP&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;`id`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;ENGINE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;InnoDB&lt;/span&gt; &lt;span class="k"&gt;DEFAULT&lt;/span&gt; &lt;span class="n"&gt;CHARSET&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;utf8mb4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Traditionally, you’d have to write a GORM model, create CRUD code, maybe run GORM Gen, then still define API endpoints, register routes, and write handlers—a few hundred lines of code easily.&lt;/p&gt;

&lt;p&gt;With Sponge, just go to its code generation page, choose your service type (&lt;code&gt;http&lt;/code&gt; or &lt;code&gt;grpc&lt;/code&gt;), enter the database DSN, select the &lt;code&gt;user&lt;/code&gt; table, and click &lt;strong&gt;“Generate Code.”&lt;/strong&gt; Duang! You instantly get a fully functional, well-structured service. All that’s left is adding your unique &lt;strong&gt;business logic&lt;/strong&gt; into the generated templates.&lt;/p&gt;



&lt;h4&gt;
  
  
  Microservices? Piece of Cake!
&lt;/h4&gt;

&lt;p&gt;Sponge is built with microservices in mind. It comes with service discovery, load balancing, circuit breaking, rate limiting, distributed tracing, and more—all integrated out of the box.&lt;/p&gt;

&lt;p&gt;Instead of struggling to stitch these features together, Sponge has already paved the way. It decouples backend services into flexible, Lego-like modules, making it effortless to scale from monoliths to complex microservice clusters.&lt;/p&gt;



&lt;h4&gt;
  
  
  Built-In AI Assistant: Turbocharging Your Coding
&lt;/h4&gt;

&lt;p&gt;Here’s the kicker: Sponge includes an AI assistant (supporting DeepSeek, ChatGPT, Gemini, etc.).&lt;/p&gt;

&lt;p&gt;When you need to implement business logic, just summon the AI—it will help write the actual code and merge it into your project.&lt;/p&gt;

&lt;p&gt;It’s like strapping a turbo engine onto your development workflow!&lt;/p&gt;



&lt;h3&gt;
  
  
  Don’t Hesitate—Embrace the Change!
&lt;/h3&gt;

&lt;p&gt;From manual gear to automatic, from building your own car to driving a supercar, technology evolves to boost our efficiency and experience.&lt;/p&gt;

&lt;p&gt;Sticking to “pure native Go” is admirable, but if a powerful framework can help you achieve more with less effort, why not embrace it? Sponge doesn’t take away your control over Go—it raises you higher, so you can focus on meaningful, challenging, and valuable work.&lt;/p&gt;

&lt;p&gt;Sponge is a framework worth trying. It solves many Go development pain points in a friendly way, letting developers truly “&lt;strong&gt;focus only on business logic&lt;/strong&gt;.”&lt;/p&gt;

&lt;p&gt;Head over to Sponge’s GitHub repo and try it out for your next project. Trust me, once you experience this “flying” feeling, you’ll never look back.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sponge GitHub Repo&lt;/strong&gt;:&lt;br&gt;
&lt;a href="https://github.com/go-dev-frame/sponge" rel="noopener noreferrer"&gt;https://github.com/go-dev-frame/sponge&lt;/a&gt;&lt;/p&gt;

</description>
      <category>go</category>
      <category>gin</category>
      <category>grpc</category>
      <category>protobuf</category>
    </item>
    <item>
      <title>Master Go Distributed Tasks in 3 Steps! The Asynq Library Makes Async Jobs Simpler Than Ever</title>
      <dc:creator>gvison</dc:creator>
      <pubDate>Thu, 07 Aug 2025 13:23:51 +0000</pubDate>
      <link>https://dev.to/zhufuyi/master-go-distributed-tasks-in-3-steps-the-asynq-library-makes-async-jobs-simpler-than-ever-57j6</link>
      <guid>https://dev.to/zhufuyi/master-go-distributed-tasks-in-3-steps-the-asynq-library-makes-async-jobs-simpler-than-ever-57j6</guid>
      <description>&lt;h3&gt;
  
  
  &lt;strong&gt;How Many Pitfalls of Go Background Tasks Have You Encountered?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;In Go application development, there are always tasks that are &lt;strong&gt;not suitable for immediate execution&lt;/strong&gt;, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Sending emails/SMS&lt;/strong&gt;: Should users have to wait after clicking a button? That's a terrible experience!&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Computationally intensive tasks&lt;/strong&gt;: Generating reports, data analysis—if the CPU is constantly occupied, will all other requests get stuck?&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Scheduled tasks&lt;/strong&gt;: Running statistics at midnight, synchronizing data every hour—are you really going to write an infinite &lt;code&gt;time.Sleep&lt;/code&gt; loop for this?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Therefore, smart developers like us throw these tasks into an &lt;strong&gt;asynchronous task queue&lt;/strong&gt;, letting background "workers" handle them.&lt;/p&gt;

&lt;p&gt;It sounds great in theory, but once you start, you might run into these pitfalls:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Goroutine Explosion&lt;/strong&gt;: When tasks pile up, you might be tempted to call &lt;code&gt;go func()&lt;/code&gt; wildly, leading to thousands of unmanageable Goroutines and immense scheduling pressure.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;What if a Task Fails?&lt;/strong&gt;: Due to network jitters or a service outage, is the task simply lost? A &lt;strong&gt;retry mechanism&lt;/strong&gt; is essential!&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Chaotic Task Priorities&lt;/strong&gt;: Should a payment notification be treated the same as a log entry? Of course not!&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Code Becomes a Mess&lt;/strong&gt;: Defining tasks, serialization, registering handlers... when business logic gets entangled with queue management code, maintenance becomes a nightmare.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you've experienced &lt;strong&gt;any of the pain points above&lt;/strong&gt;, congratulations, &lt;code&gt;sasynq&lt;/code&gt; is the "antidote" you've been looking for!&lt;/p&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;What is &lt;code&gt;sasynq&lt;/code&gt;? And Why Can It Save You?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;sasynq&lt;/code&gt; is a &lt;strong&gt;super easy-to-use wrapper&lt;/strong&gt; built on top of &lt;a href="https://github.com/hibiken/asynq" rel="noopener noreferrer"&gt;asynq&lt;/a&gt;. Asynq is a stable, efficient, Redis-based distributed task queue, and &lt;code&gt;sasynq&lt;/code&gt; makes it even simpler and smoother to use.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What are its advantages?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;✅ &lt;strong&gt;Out-of-the-box&lt;/strong&gt;: Supports Redis Cluster and Sentinel, eliminating single points of failure.&lt;br&gt;
✅ &lt;strong&gt;Comprehensive Features&lt;/strong&gt;: Priority queues, delayed tasks, deduplication, cancellation, and scheduled tasks are all supported.&lt;br&gt;
✅ &lt;strong&gt;Safe and Reliable&lt;/strong&gt;: With retries, timeouts, and deadlines, you'll never have to worry about losing tasks again.&lt;br&gt;
✅ &lt;strong&gt;Extremely Simple API&lt;/strong&gt;: Compared to the native &lt;code&gt;asynq&lt;/code&gt;, writing code is more elegant and clear.&lt;/p&gt;

&lt;p&gt;In short, &lt;strong&gt;it makes complex things incredibly simple&lt;/strong&gt;.&lt;/p&gt;


&lt;h3&gt;
  
  
  &lt;strong&gt;How Easy is &lt;code&gt;sasynq&lt;/code&gt; to Use? Let's See the Code!&lt;/strong&gt;
&lt;/h3&gt;
&lt;h4&gt;
  
  
  &lt;strong&gt;① Defining a Task&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;sasynq&lt;/code&gt; makes task definition effortless.&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;// example/common/task.go&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;TypeEmailSend&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"email:send"&lt;/span&gt;

&lt;span class="c"&gt;// Task payload&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;EmailPayload&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;UserID&lt;/span&gt;  &lt;span class="kt"&gt;int&lt;/span&gt;    &lt;span class="s"&gt;`json:"user_id"`&lt;/span&gt;
    &lt;span class="n"&gt;Message&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`json:"message"`&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// Task handler&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;HandleEmailTask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;EmailPayload&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;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[Email] Email sent successfully to user %d!&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UserID&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Isn't that clean? Just define the payload and the handler, and &lt;strong&gt;no more manual &lt;code&gt;json.Unmarshal&lt;/code&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;② Enqueuing Tasks: The Ultimate Simplicity&lt;/strong&gt;
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;One-off Task Producer&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;payload&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;common&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EmailPayload&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;UserID&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;101&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Message&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Important task!"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&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;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EnqueueNow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;common&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TypeEmailSend&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;sasynq&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithQueue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"critical"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;sasynq&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithRetry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;3&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;&lt;code&gt;EnqueueNow&lt;/code&gt;, &lt;code&gt;EnqueueIn&lt;/code&gt;, &lt;code&gt;EnqueueAt&lt;/code&gt;—the function names are self-explanatory! Use &lt;code&gt;sasynq.WithXXX&lt;/code&gt; for method chaining to configure queues, retries, and deadlines in an intuitive and elegant way.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Periodic Task Producer&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;payload&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;common&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EmailPayload&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;UserID&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;102&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Message&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Periodic task!"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;scheduler&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RegisterTask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"@every 1m"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"request:url"&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;payload&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One line of code is all it takes to set up a scheduled task.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;③ Consuming Tasks: Register a Handler in One Line, and You're Done!&lt;/strong&gt;
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;srv&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;sasynq&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;redisCfg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sasynq&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DefaultServerConfig&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

&lt;span class="n"&gt;sasynq&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RegisterTaskHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;srv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Mux&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;common&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TypeEmailSend&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sasynq&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandleFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;common&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandleEmailTask&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="n"&gt;srv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No redundant code. &lt;strong&gt;Register → Run → Done&lt;/strong&gt;!&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Canceling a Task&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;For a one-off, pending task:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;inspector&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CancelTask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;taskID&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a periodic task:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;scheduler&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unregister&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;entryID&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Cancel a task with a single line of code.&lt;/p&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;Summary: Why Choose &lt;code&gt;sasynq&lt;/code&gt;?&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Simpler&lt;/strong&gt;: Minimalist API design and clear code structure.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;More Powerful&lt;/strong&gt;: Fully covers all common scenarios with support for retries, deduplication, delays, scheduling, and priorities.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Safer&lt;/strong&gt;: Deadlines, timeouts, and retry strategies provide better control over task processing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you're looking for a &lt;strong&gt;simple, efficient, and feature-rich&lt;/strong&gt; asynchronous task solution for your Go project, &lt;code&gt;sasynq&lt;/code&gt; is the best choice.&lt;/p&gt;




&lt;p&gt;&lt;code&gt;sasynq&lt;/code&gt; URL: github.com/go-dev-frame/sponge/pkg/sasynq&lt;/p&gt;

&lt;p&gt;&lt;code&gt;sasynq&lt;/code&gt; is a sub-component of the Sponge framework. Sponge is a powerful and easy-to-use Go development framework based on the core principle of "Definition is Code." It helps developers easily build stable, reliable, and high-performance backend services (including RESTful API, gRPC, HTTP+gRPC, gRPC Gateway, etc.) in a "low-code" manner.&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;Sponge Project URL&lt;/strong&gt;:&lt;br&gt;
&lt;a href="https://github.com/go-dev-frame/sponge" rel="noopener noreferrer"&gt;https://github.com/go-dev-frame/sponge&lt;/a&gt;&lt;/p&gt;

</description>
      <category>go</category>
      <category>backend</category>
      <category>distributedsystems</category>
    </item>
    <item>
      <title>Comparative Analysis of Go Frameworks: Kratos, Go-Zero, GoFrame, and Sponge</title>
      <dc:creator>gvison</dc:creator>
      <pubDate>Mon, 14 Jul 2025 13:50:46 +0000</pubDate>
      <link>https://dev.to/zhufuyi/comparative-analysis-of-go-frameworks-kratos-go-zero-goframe-and-sponge-3a2l</link>
      <guid>https://dev.to/zhufuyi/comparative-analysis-of-go-frameworks-kratos-go-zero-goframe-and-sponge-3a2l</guid>
      <description>&lt;p&gt;The prosperity of the Go language community is as lively as a summer night food stall, with a dazzling array of frameworks to choose from. Today, let's act as "connoisseurs" and talk about the four "martial arts masters": Kratos, Go-Zero, GoFrame, and Sponge, to see which one you should bet your next project on.&lt;/p&gt;




&lt;p&gt;When starting a new project, are you scratching your head again over which framework to choose? On one hand, there's "analysis paralysis," and on the other, the "holy wars" among the senior developers in your team. It's almost more tiring than writing code.&lt;/p&gt;

&lt;p&gt;Today, let's bring four Go frameworks with distinct styles—Kratos, Go-Zero, GoFrame, and Sponge—onto the stage. We'll discuss their tempers, characteristics, and unique skills to help you find the one that's the perfect match.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Arena Showdown: Which One is Your Cup of Tea?
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Framework Comparison
&lt;/h4&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Feature/Framework&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;kratos&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;go-zero&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;goframe&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;sponge&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Design Philosophy&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Microservices framework, emphasizing modularity and extensibility&lt;/td&gt;
&lt;td&gt;High-performance, simple, and easy-to-use, oriented towards microservices&lt;/td&gt;
&lt;td&gt;Backend development framework, emphasizing development efficiency and ease of use&lt;/td&gt;
&lt;td&gt;Adheres to the low-code philosophy of "&lt;strong&gt;Definition is Code&lt;/strong&gt;," emphasizing ease of use, development efficiency, and extensibility&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;HTTP Service&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Supported&lt;/td&gt;
&lt;td&gt;Supported&lt;/td&gt;
&lt;td&gt;Supported&lt;/td&gt;
&lt;td&gt;Supported (gin, gin+protobuf combination)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;RPC Service&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Supported (gRPC)&lt;/td&gt;
&lt;td&gt;Supported (gRPC)&lt;/td&gt;
&lt;td&gt;Supported (gRPC)&lt;/td&gt;
&lt;td&gt;Supported (gRPC)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;HTTP+RPC Hybrid Service&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Supported (http+gRPC)&lt;/td&gt;
&lt;td&gt;Not Supported&lt;/td&gt;
&lt;td&gt;Not Supported&lt;/td&gt;
&lt;td&gt;Supported (gin+gRPC)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Configuration Management&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Supports multiple config sources (file, env variables, etc.)&lt;/td&gt;
&lt;td&gt;Supports multiple config sources (file, env variables, etc.)&lt;/td&gt;
&lt;td&gt;Supports multiple config sources (file, env variables, etc.)&lt;/td&gt;
&lt;td&gt;Supports multiple config sources (file, env variables, etc.)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Logging System&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Supports multiple log output formats and levels&lt;/td&gt;
&lt;td&gt;Supports multiple log output formats and levels&lt;/td&gt;
&lt;td&gt;Supports multiple log output formats and levels&lt;/td&gt;
&lt;td&gt;Supports multiple log output formats and levels&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;ORM Support&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Not supported (requires integrating third-party libraries)&lt;/td&gt;
&lt;td&gt;Built-in ORM&lt;/td&gt;
&lt;td&gt;Built-in ORM, supports multiple databases&lt;/td&gt;
&lt;td&gt;Built-in ORM (gorm, mongo), supports extending with other ORM code&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;API Generation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Supports automatic API generation&lt;/td&gt;
&lt;td&gt;Supports automatic API generation&lt;/td&gt;
&lt;td&gt;Supports automatic API generation&lt;/td&gt;
&lt;td&gt;Supports auto-generating API by parsing SQL, Protobuf, or JSON&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cache Support&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Supports multiple caches (Redis, local memory)&lt;/td&gt;
&lt;td&gt;Supports multiple caches (Redis, Memcached, etc.)&lt;/td&gt;
&lt;td&gt;Supports multiple caches (Redis, Memcached, etc.)&lt;/td&gt;
&lt;td&gt;Supports multiple caches (Redis, local memory)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Service Registry &amp;amp; Discovery&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Supported (etcd, consul, nacos, etc.)&lt;/td&gt;
&lt;td&gt;Supported (etcd, consul, etc.)&lt;/td&gt;
&lt;td&gt;Supported (etcd, zookeeper, polaris, etc.)&lt;/td&gt;
&lt;td&gt;Supported (etcd, consul, nacos, etc.)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Load Balancing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Supported&lt;/td&gt;
&lt;td&gt;Supported&lt;/td&gt;
&lt;td&gt;Supported&lt;/td&gt;
&lt;td&gt;Supported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Circuit Breaking &amp;amp; Rate Limiting&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Supported&lt;/td&gt;
&lt;td&gt;Supported&lt;/td&gt;
&lt;td&gt;Not Supported&lt;/td&gt;
&lt;td&gt;Supported, and also supports setting fallback handlers after circuit breaking&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Monitoring &amp;amp; Tracing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Supported (OpenTelemetry, Prometheus, etc.)&lt;/td&gt;
&lt;td&gt;Supported (OpenTelemetry, Prometheus, etc.)&lt;/td&gt;
&lt;td&gt;Supported (OpenTelemetry, Prometheus, etc.)&lt;/td&gt;
&lt;td&gt;Supported (OpenTelemetry, Prometheus, etc.)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Middleware Support&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Supported&lt;/td&gt;
&lt;td&gt;Supported&lt;/td&gt;
&lt;td&gt;Supported&lt;/td&gt;
&lt;td&gt;Supported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Built-in AI&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;Yes, supports DeepSeek, ChatGPT, Gemini to generate and merge specific business logic code&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Extensibility&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;High, modular design&lt;/td&gt;
&lt;td&gt;High, supports custom plugins&lt;/td&gt;
&lt;td&gt;High, supports custom components&lt;/td&gt;
&lt;td&gt;Very high, modular design, and supports custom templates to generate code required for the project&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Performance&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;High-performance&lt;/td&gt;
&lt;td&gt;High-performance&lt;/td&gt;
&lt;td&gt;High-performance&lt;/td&gt;
&lt;td&gt;High-performance&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Ease of Use&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;td&gt;Medium, simple and easy-to-use&lt;/td&gt;
&lt;td&gt;Simple and easy-to-use, out of the box&lt;/td&gt;
&lt;td&gt;Extremely simple and friendly, out of the box, low-code development&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Learning Curve&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;td&gt;Relatively Low&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Documentation &amp;amp; Community&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Detailed documentation, active community&lt;/td&gt;
&lt;td&gt;Detailed documentation, active community&lt;/td&gt;
&lt;td&gt;Detailed documentation, active community&lt;/td&gt;
&lt;td&gt;Detailed documentation, active community&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Applicable Scenarios&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Medium to large-scale microservice projects&lt;/td&gt;
&lt;td&gt;Medium to large-scale microservice projects&lt;/td&gt;
&lt;td&gt;Small, medium, to large-scale projects&lt;/td&gt;
&lt;td&gt;Medium to large-scale microservice projects&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;From the comparison above, everyone should have a rough picture of each "contestant":&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Kratos:&lt;/strong&gt; A product of Bilibili, battle-tested, focusing on microservices. It emphasizes "modularity" and "extensibility," exuding the rigor of an "architect."&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Go-Zero:&lt;/strong&gt; A lightning-fast efficiency tool. It pursues ultimate performance and simplicity, coming with its own code generation tools, like an efficiency-first assassin who strikes fatally without any delay.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;GoFrame:&lt;/strong&gt; An all-encompassing Swiss Army knife. Nicknamed "GF," its goal is to be your development "family bucket." It can do everything from web development to backend services, focusing on being "out of the box" and "development efficiency."&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Sponge:&lt;/strong&gt; The low-code black magician embracing the future. This is the newcomer "raising the bar." It brings a philosophy of "Definition is Code," not only wanting you to write less code but even having a built-in AI to help you write business logic, which is a bit of an unfair advantage.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Next, let's have a head-to-head confrontation from the angles everyone cares about most.&lt;/p&gt;

&lt;h4&gt;
  
  
  1. Learning Curve &amp;amp; Ease of Use: Who is More Approachable?
&lt;/h4&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Winners: GoFrame, Sponge&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;GoFrame&lt;/strong&gt;: If you're a Go novice or your project is all about being "short, simple, and fast," then GoFrame is definitely a blessing. Its design philosophy is "simple and easy to use," with clear documentation and an active community, lowering the barrier to entry.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Sponge&lt;/strong&gt;: This one takes another "minimalist" route. Its low-code concept allows you to focus only on the most important business logic (defining data models and APIs), and it handles the rest. It can even use its built-in AI to help you fill in the business logic, making it extremely friendly for beginners with a very low learning curve. You can generate complete, compilable, and deployable service code (http or gRPC) just by connecting to a database.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Kratos&lt;/strong&gt; and &lt;strong&gt;Go-Zero&lt;/strong&gt;, due to their distinct microservice architecture concepts, require you to first understand their design patterns (like Kratos's layering, Go-Zero's &lt;code&gt;.api&lt;/code&gt; specification), so their learning curve is slightly higher, at a "medium" level.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  2. Microservice Support: Who is More Practical?
&lt;/h4&gt;

&lt;blockquote&gt;
&lt;p&gt;Evenly Matched: Kratos, Sponge&lt;/p&gt;

&lt;p&gt;Potential Contender: Go-Zero&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;All four support gRPC and are capable of microservice development. But the details vary greatly.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Kratos and Sponge&lt;/strong&gt; support &lt;strong&gt;HTTP+RPC hybrid services&lt;/strong&gt;. This means you can use one set of code to expose both HTTP/JSON interfaces to the frontend and gRPC interfaces for internal service calls. This is very practical in modern microservice architectures and can effectively reduce maintenance costs.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Go-Zero and GoFrame&lt;/strong&gt; are more "specialized" in this regard. The services they generate are either pure HTTP or pure gRPC, and they don't support mixing them in the same service instance.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, if your microservice system requires flexible interface formats, Kratos and Sponge would be a better choice.&lt;/p&gt;

&lt;h4&gt;
  
  
  3. The Love-Hate Relationship with ORM: Built-in or Choose Your Own?
&lt;/h4&gt;

&lt;blockquote&gt;
&lt;p&gt;The Built-in Camp: Go-Zero, GoFrame, Sponge&lt;/p&gt;

&lt;p&gt;The Freedom Camp: Kratos&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is a classic "sweet tofu pudding" versus "salty tofu pudding" debate.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;GoFrame&lt;/strong&gt; and &lt;strong&gt;Go-Zero&lt;/strong&gt; both have powerful built-in ORMs that work out of the box, saving you the trouble of choosing and integrating one. For most projects, this is very convenient.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Sponge&lt;/strong&gt; goes a step further. It not only has built-in GORM and Mongo drivers but also has designed a template mechanism. Theoretically, you can customize templates to have it generate any type of ORM code for you, which is very flexible.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Kratos&lt;/strong&gt; insists on "architectural purity." It does not include a built-in ORM, giving the choice entirely to you. You are free to choose GORM, SQLx, or any library you like. This is an advantage for teams with specific technology stack requirements or those who like to have control over everything.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  4. Code Generation: Who is the Real "Lazy Person's Gospel"?
&lt;/h4&gt;

&lt;blockquote&gt;
&lt;p&gt;The King: Sponge&lt;/p&gt;

&lt;p&gt;The Strong Contenders: Go-Zero, GoFrame&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In this era of "if it can be automated, never write it by hand," code generation capability is an important measure of a framework's productivity.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Go-Zero&lt;/strong&gt;'s &lt;code&gt;goctl&lt;/code&gt; toolchain is very powerful. With an &lt;code&gt;.api&lt;/code&gt; file, you can generate an entire service skeleton with one click, greatly improving development efficiency.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GoFrame&lt;/strong&gt;'s &lt;code&gt;gf&lt;/code&gt; development tool generates corresponding service code through &lt;code&gt;.yaml&lt;/code&gt; configuration, improving development efficiency.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sponge&lt;/strong&gt; takes this to the extreme. Its philosophy is "Definition is Code." You can start from &lt;strong&gt;SQL&lt;/strong&gt;, &lt;strong&gt;Protobuf&lt;/strong&gt;, or even &lt;strong&gt;JSON&lt;/strong&gt; to generate service code, including Web and gRPC, with complete CRUD functionality. The most "outrageous" part is that it &lt;strong&gt;has built-in AI&lt;/strong&gt;! You can have DeepSeek/ChatGPT/Gemini help you fill in the specific business logic code while maintaining a consistent code style. It truly achieves semi-automation from definition to business logic, making it the "pinnacle of development efficiency."&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Kratos also supports code generation, but compared to the other three, it is slightly more conservative in terms of "automation" and "intelligence."&lt;/p&gt;

&lt;h3&gt;
  
  
  Who Should Your Project Choose?
&lt;/h3&gt;

&lt;p&gt;Based on the comparison above, here are some selection recommendations:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;If you are: A large enterprise or a die-hard fan of Bilibili, pursuing architectural standardization, stability, and ultimate extensibility.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;👉 Choose Kratos.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Kratos is like an experienced architect who lays a solid foundation and provides a clear blueprint for you. Although it requires some initial investment to understand its design philosophy, this investment is worthwhile for large-scale microservice projects that need long-term evolution and collaboration among many people. It ensures your project won't "go off track" in the future.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If you are: A team pursuing ultimate performance and development efficiency, with a business centered around APIs.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;👉 Choose Go-Zero.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Go-Zero is like a sharp dagger: fast, precise, and ruthless. All its designs are for performance and efficiency. With the powerful &lt;code&gt;goctl&lt;/code&gt; tool, you can build and iterate API services like on a production line, which is very suitable for internet projects that need to quickly capture the market.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If you are: A small to medium-sized team pursuing efficient development and needing to quickly develop and validate projects.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;👉 Choose GoFrame.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;GoFrame is your "universal toolbox." It has everything, and everything works well. You don't need to spend too much time on technology selection and component integration to quickly implement business functions. Its development experience is very smooth, making it an excellent choice for rapid prototyping and small to medium-sized projects.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If you are: A team pursuing the ultimate in development efficiency, needing to maintain the flexibility and extensibility of the project architecture.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;👉 Choose Sponge.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Sponge is a "magician" from the future. It uses the power of low-code and AI to push development efficiency to new heights. It can quickly build small and medium-sized web services, and like Kratos, it can also build complex large-scale microservice projects. It also supports hybrid services and is feature-complete. It is especially suitable for teams that want "all of the above" and is the ultimate weapon for improving the overall productivity of a team.&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;p&gt;Of course, there is no absolute "best" framework, only the "most suitable." Hopefully, this article helps you cut through the fog and see the true faces of these "masters."&lt;/p&gt;

&lt;p&gt;The best way is to get your hands dirty, spend some time running their &lt;code&gt;Hello World&lt;/code&gt;, and get a "feel" for them. After all, the code doesn't lie.&lt;/p&gt;

&lt;p&gt;If you have used one or more of the above frameworks in your projects, feel free to leave your user experience in the comments section!&lt;/p&gt;




&lt;p&gt;GitHub addresses for the 4 frameworks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;kratos&lt;/strong&gt;: &lt;a href="https://github.com/go-kratos/kratos" rel="noopener noreferrer"&gt;https://github.com/go-kratos/kratos&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;go-zero&lt;/strong&gt;: &lt;a href="https://github.com/zeromicro/go-zero" rel="noopener noreferrer"&gt;https://github.com/zeromicro/go-zero&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;goframe&lt;/strong&gt;: &lt;a href="https://github.com/gogf/gf" rel="noopener noreferrer"&gt;https://github.com/gogf/gf&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;sponge&lt;/strong&gt;: &lt;a href="https://github.com/go-dev-frame/sponge" rel="noopener noreferrer"&gt;https://github.com/go-dev-frame/sponge&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>go</category>
      <category>microservices</category>
      <category>web</category>
      <category>grpc</category>
    </item>
    <item>
      <title>Is Real-Time Pushing in Go Too Hard? Try Sponge SSE and Get It Done in One Click!</title>
      <dc:creator>gvison</dc:creator>
      <pubDate>Wed, 02 Jul 2025 07:41:04 +0000</pubDate>
      <link>https://dev.to/zhufuyi/is-real-time-pushing-in-go-too-hard-try-sponge-sse-and-get-it-done-in-one-click-3c94</link>
      <guid>https://dev.to/zhufuyi/is-real-time-pushing-in-go-too-hard-try-sponge-sse-and-get-it-done-in-one-click-3c94</guid>
      <description>&lt;p&gt;Hey Gophers! Have you ever encountered scenarios like these:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  You're developing a backend monitoring system and want to display real-time data like CPU usage and memory consumption on the frontend, but the only way is to have the frontend send a request every few seconds, exhausting the server?&lt;/li&gt;
&lt;li&gt;  You want to build an information feed similar to Facebook or Twitter, where new messages are instantly "dinged" and pushed to the user's page, instead of waiting for them to scratch their heads and manually refresh?&lt;/li&gt;
&lt;li&gt;  Or, you simply want to notify a user: "Your delivery has been picked up by [Handsome John Doe] and is speeding your way!", rather than having them stare anxiously at the order page?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you nodded to any of the questions above, then congratulations, you've probably been using the old method of "polling." It's like sending a subordinate to the kitchen every five seconds to ask, "Is the food ready yet?". Not only does the subordinate run their legs off, but the chef gets annoyed too.&lt;/p&gt;

&lt;p&gt;Isn't there a more elegant way? Of course, there is! Today's star is &lt;strong&gt;Server-Sent Events (SSE)&lt;/strong&gt;, and it's here to save the day! And the Go &lt;a href="https://github.com/go-dev-frame/sponge/tree/main/pkg/sse" rel="noopener noreferrer"&gt;SSE&lt;/a&gt; library we're about to introduce will give you this superpower with "one click"!&lt;/p&gt;

&lt;h3&gt;
  
  
  What is SSE? How is it different from WebSocket?
&lt;/h3&gt;

&lt;p&gt;Before diving into the code, let's explain the principle in plain language.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SSE (Server-Sent Events)&lt;/strong&gt;, as the name suggests, are "events sent by the server." It's built on a standard HTTP connection, but this connection is a "long-lived" and &lt;strong&gt;unidirectional&lt;/strong&gt; one.&lt;/p&gt;

&lt;p&gt;Think of it as a &lt;strong&gt;radio broadcast&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  The &lt;strong&gt;server&lt;/strong&gt; is the radio station that broadcasts 24/7.&lt;/li&gt;
&lt;li&gt;  The &lt;strong&gt;client (browser)&lt;/strong&gt; is the radio.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once you tune your radio to the right channel (establish a connection), the station (server) can send you news and music (data) at any time, and you don't need to call every minute to ask, "Are there any new programs?".&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;So, how is it different from WebSocket?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;SSE&lt;/strong&gt;: It's a &lt;strong&gt;one-way street&lt;/strong&gt;. Only the server can push data to the client. It's simple, lightweight, based on standard HTTP, and natively supports auto-reconnect. It's perfect for scenarios that only require server-to-client information pushing.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;WebSocket&lt;/strong&gt;: It's a &lt;strong&gt;two-way highway&lt;/strong&gt;. The client and server can "shout" at each other at any time. It's more powerful, but the protocol is also more complex. It's suitable for scenarios like online chat and collaborative editing that require frequent two-way communication.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In summary, if your requirement is one-way notification from "server -&amp;gt; client," then SSE is the simpler, more appropriate "wheel" for the job.&lt;/p&gt;

&lt;h3&gt;
  
  
  What features does this Go library offer?
&lt;/h3&gt;

&lt;p&gt;There are many SSE libraries on the market, but many only offer basic functionality. This &lt;code&gt;sse&lt;/code&gt; library, however, is incredibly thoughtful, like an all-in-one butler:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;High Performance&lt;/strong&gt;: Excellent underlying design, capable of easily managing thousands of client connections.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Automatic Reconnection&lt;/strong&gt;: Network jitter? User accidentally closed and reopened the page? No worries! The library has built-in mechanisms for automatic reconnection and event resending, ensuring no important messages are lost! (Requires persistent storage).&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Message Persistence&lt;/strong&gt;: You can store historical events in Redis, MySQL, or anywhere you like. Mom no longer has to worry about losing messages after a server restart.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Built-in Heartbeats&lt;/strong&gt;: Automatically detects "zombie connections" and cleans them up in time, keeping the connection pool healthy.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Broadcast and Unicast&lt;/strong&gt;: You can "whisper" to one or more specific users, or "shout" a broadcast to all online users.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sounds cool, right? Just wait, seeing the code is even cooler!&lt;/p&gt;

&lt;h3&gt;
  
  
  Get Started in Three Minutes: Build Your First SSE Service
&lt;/h3&gt;

&lt;p&gt;Let's use a simple example to see how easy it is to quickly set up a service with the &lt;code&gt;sse&lt;/code&gt; library. Suppose we want to build a service that broadcasts "Hello World" to all clients every 5 seconds.&lt;/p&gt;

&lt;h4&gt;
  
  
  1. Server-side Code (&lt;code&gt;server.go&lt;/code&gt;)
&lt;/h4&gt;

&lt;p&gt;You'll need a Go environment and the Gin framework installed (this example uses Gin, but you can also use Go's native &lt;code&gt;net/http&lt;/code&gt;).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go get github.com/gin-gonic/gin
go get github.com/go-dev-frame/sponge/pkg/sse
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, create a &lt;code&gt;main.go&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
    &lt;span class="s"&gt;"math/rand"&lt;/span&gt;
    &lt;span class="s"&gt;"net/http"&lt;/span&gt;
    &lt;span class="s"&gt;"strconv"&lt;/span&gt;
    &lt;span class="s"&gt;"time"&lt;/span&gt;

    &lt;span class="s"&gt;"github.com/gin-gonic/gin"&lt;/span&gt;
    &lt;span class="s"&gt;"github.com/go-dev-frame/sponge/pkg/sse"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// 1. Initialize our SSE "Broadcast Center" (Hub)&lt;/span&gt;
    &lt;span class="c"&gt;// Think of it as the main control room of the radio station&lt;/span&gt;
    &lt;span class="n"&gt;hub&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;sse&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewHub&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;hub&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c"&gt;// 2. Create a web server with Gin&lt;/span&gt;
    &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;gin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Default&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c"&gt;// 3. Create a "/events" endpoint for clients to "tune in"&lt;/span&gt;
    &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GET&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/events"&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;c&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;gin&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;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"New listener joined!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="c"&gt;// For demonstration, we assign a random ID to each connecting client&lt;/span&gt;
        &lt;span class="n"&gt;uid&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;strconv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Itoa&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rand&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Intn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;999&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="m"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;hub&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Serve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;uid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="c"&gt;// 4. [Optional] Create an endpoint to manually trigger a broadcast&lt;/span&gt;
    &lt;span class="c"&gt;// You can test it with a curl command:&lt;/span&gt;
    &lt;span class="c"&gt;// curl -X POST -H "Content-Type: application/json" -d '{"events":[{"event":"message","data":"This is a manual broadcast!"}]}' http://localhost:8080/push&lt;/span&gt;
    &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;POST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/push"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hub&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PushEventHandler&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

    &lt;span class="c"&gt;// 5. Start a tireless "broadcaster" (goroutine)&lt;/span&gt;
    &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&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="c"&gt;// Prepare a new message every 5 seconds&lt;/span&gt;
            &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Second&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;
            &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;"Hello everyone, this is automatic broadcast number "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;strconv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Itoa&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"!"&lt;/span&gt;

            &lt;span class="c"&gt;// Create a standard event&lt;/span&gt;
            &lt;span class="n"&gt;event&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;sse&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Event&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;Event&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c"&gt;// Event type, can be customized&lt;/span&gt;
                &lt;span class="n"&gt;Data&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="c"&gt;// Call hub.Push to broadcast (passing nil for uids means broadcasting to everyone)&lt;/span&gt;
            &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Broadcasting: %s&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hub&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Push&lt;/span&gt;&lt;span class="p"&gt;(&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;event&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="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"SSE server started at http://localhost:8080"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c"&gt;// Start the server&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;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ListenAndServe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;":8080"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&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="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&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;See? It's super clear! Initialize Hub -&amp;gt; Create connection point -&amp;gt; Push message. Done!&lt;/p&gt;

&lt;h4&gt;
  
  
  2. Client-side Code (&lt;code&gt;client.go&lt;/code&gt;)
&lt;/h4&gt;

&lt;p&gt;Now, we need a "radio" to receive the messages. This library also provides a client implementation, which is very convenient.&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
    &lt;span class="s"&gt;"github.com/go-dev-frame/sponge/pkg/sse"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&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="s"&gt;"http://localhost:8080/events"&lt;/span&gt;

    &lt;span class="c"&gt;// 1. Create an SSE client pointing to our server address&lt;/span&gt;
    &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;sse&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewClient&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="c"&gt;// 2. Register an event listener&lt;/span&gt;
    &lt;span class="c"&gt;// Tell the client: "Once you receive an event of type 'message', execute the following function"&lt;/span&gt;
    &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OnEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"message"&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;event&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;sse&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c"&gt;// event.Data is the message content we receive from the server&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Received a new broadcast! Content: [%s], ID: %s&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="c"&gt;// 3. Start connecting!&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;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Connect&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="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Connection failed, oh no: %v&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&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;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Radio is on, waiting for broadcast... (Press Ctrl+C to exit)"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// Block the main program, waiting for the client to exit&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Wait&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;Now, first run &lt;code&gt;go run server.go&lt;/code&gt;, then open another terminal and run &lt;code&gt;go run client.go&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You will see that the client prints a new message from the server every 5 seconds, without the client needing to do anything extra! That's the magic of SSE!&lt;/p&gt;

&lt;p&gt;Of course, you can also use other clients for testing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Advanced Usage: Make Your SSE Service More Powerful
&lt;/h3&gt;

&lt;p&gt;The power of the &lt;code&gt;sse&lt;/code&gt; library goes far beyond this.&lt;/p&gt;

&lt;h4&gt;
  
  
  Scenario 1: I don't want to lose a single message!
&lt;/h4&gt;

&lt;p&gt;Imagine your service is pushing critical stock prices. If a client disconnects for 10 seconds due to network issues, they could miss out on a fortune!&lt;/p&gt;

&lt;p&gt;This is where &lt;strong&gt;persistent storage&lt;/strong&gt; and &lt;strong&gt;event resending&lt;/strong&gt; come into play.&lt;/p&gt;

&lt;p&gt;You just need to implement a simple &lt;code&gt;Store&lt;/code&gt; interface to tell the &lt;code&gt;sse&lt;/code&gt; library how to save and read events (e.g., using Redis).&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;// Pseudo-code: Implement your own Store&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;MyRedisStore&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c"&gt;/* ... redis client ... */&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;MyRedisStore&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;sse&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Event&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="c"&gt;// Serialize the event into JSON and save it to a Redis List or ZSet&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="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;MyRedisStore&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;ListByLastID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;eventType&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lastID&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pageSize&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;sse&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Event&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="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="c"&gt;// Based on the lastID received by the client, query for new events from Redis&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;events&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nextLastID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// When initializing the Hub, include your storage and resend configuration&lt;/span&gt;
&lt;span class="n"&gt;hub&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;sse&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewHub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;sse&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithStore&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;MyRedisStore&lt;/span&gt;&lt;span class="p"&gt;{}),&lt;/span&gt; &lt;span class="c"&gt;// Use your Redis storage&lt;/span&gt;
    &lt;span class="n"&gt;sse&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithEnableResendEvents&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;  &lt;span class="c"&gt;// Enable the disconnect-and-resend feature!&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's that simple! Now, when a client disconnects and reconnects, it will automatically include the ID of the last message it received. The server, upon seeing this, will fetch all the missed messages from your Redis and send them all at once. The fortune is saved!&lt;/p&gt;

&lt;h4&gt;
  
  
  Scenario 2: I want to know if a message was successfully delivered.
&lt;/h4&gt;

&lt;p&gt;Sometimes, you want to know if a message pushed to a specific user failed (for example, if that user has gone offline). You can set up a "failure callback function."&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;failedHandler&lt;/span&gt; &lt;span class="o"&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;uid&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;sse&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// The code here will be executed when a push fails&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Oops, failed to push message %s to user %s! You can log it and retry later."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;uid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;hub&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;sse&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewHub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sse&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithPushFailedHandleFn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;failedHandler&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This way, you can log, alert, or perform other compensatory actions for failed push events.&lt;/p&gt;

&lt;h3&gt;
  
  
  Summary
&lt;/h3&gt;

&lt;p&gt;Server-Sent Events (SSE) is a powerful tool for building modern real-time applications. Especially when dealing with one-way data streams from the server to the client, it is lighter and simpler than WebSocket.&lt;/p&gt;

&lt;p&gt;And this &lt;code&gt;sse&lt;/code&gt; library is like a well-equipped Swiss Army knife. It not only provides the core functionality of SSE but also thoughtfully prepares a series of "deluxe features" for you, such as persistence, auto-reconnection, failure handling, and performance monitoring. It frees developers from the tedious tasks of connection management and exception handling, allowing them to focus on implementing business logic.&lt;/p&gt;

&lt;p&gt;So, the next time your product manager comes up with a "real-time update" requirement, don't frown and write polling code anymore. Confidently puff out your chest and tell them, "No problem, I'll get it done in minutes!" Then, gracefully &lt;code&gt;import "github.com/go-dev-frame/sponge/pkg/sse"&lt;/code&gt; and let the magic happen!&lt;/p&gt;

&lt;p&gt;GitHub Address: &lt;a href="https://github.com/go-dev-frame/sponge/tree/main/pkg/sse" rel="noopener noreferrer"&gt;Sponge SSE&lt;/a&gt;&lt;/p&gt;

</description>
      <category>go</category>
      <category>sse</category>
      <category>gin</category>
    </item>
    <item>
      <title>Go Project Scaffolding Guide: A Choice That Earned My Team's Rave Reviews</title>
      <dc:creator>gvison</dc:creator>
      <pubDate>Fri, 27 Jun 2025 10:44:18 +0000</pubDate>
      <link>https://dev.to/zhufuyi/go-project-scaffolding-guide-a-choice-that-earned-my-teams-rave-reviews-i03</link>
      <guid>https://dev.to/zhufuyi/go-project-scaffolding-guide-a-choice-that-earned-my-teams-rave-reviews-i03</guid>
      <description>&lt;p&gt;When developing with Go, who hasn't been through the wringer with frameworks like the standard library's HTTP, Gin, Echo, Iris, Fiber, Beego, GoFrame, gRPC, Go-Micro, Go-Zero, or Kratos? They all claim to have great performance and powerful features, but in practice, there are always those "not-so-great" moments, right?&lt;/p&gt;

&lt;p&gt;It's like dating. At first, everyone seems wonderful, but over time, little frictions and pain points start to surface. Today, I'm going to share how, after trying them all, I finally found my "dream framework" — &lt;a href="https://github.com/go-dev-frame/sponge" rel="noopener noreferrer"&gt;Sponge&lt;/a&gt; — and just how much of a game-changer it is!&lt;/p&gt;

&lt;h3&gt;
  
  
  The Pains We've All Endured
&lt;/h3&gt;

&lt;p&gt;Before I found Sponge, my Go development life was a mix of pain and pleasure.&lt;/p&gt;

&lt;h4&gt;
  
  
  Gin, Echo: Freedom is Great, But You Have to Build Everything from Scratch
&lt;/h4&gt;

&lt;p&gt;Gin and Echo are old friends to us Gophers—lightweight, fast, and easy to get started with. But the price of freedom is that you have to build a lot of things yourself.&lt;/p&gt;

&lt;p&gt;Want to write a simple CRUD? Okay, start by defining a &lt;code&gt;struct&lt;/code&gt;, writing the &lt;code&gt;handler&lt;/code&gt;, &lt;code&gt;service&lt;/code&gt;, and &lt;code&gt;model&lt;/code&gt;, then registering the routes. After all that "grunt work," half the day is gone. It's manageable for small projects, but as projects grow, the code structure starts to become a "wild west," with different people writing in wildly different styles.&lt;/p&gt;

&lt;p&gt;Let me show you a "familiar" scene. Writing a user creation endpoint with Gin, does it feel like you're copy-pasting this in every project?&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;// main.go&lt;/span&gt;
&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"github.com/gin-gonic/gin"&lt;/span&gt;
    &lt;span class="s"&gt;"net/http"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;User&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Name&lt;/span&gt;  &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`json:"name"`&lt;/span&gt;
    &lt;span class="n"&gt;Email&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`json:"email"`&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;gin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Default&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;POST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/users"&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;c&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;gin&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="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="n"&gt;User&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;ShouldBindJSON&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;user&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="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;JSON&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;StatusBadRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;gin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;H&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"error"&lt;/span&gt;&lt;span class="o"&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;Error&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="c"&gt;// ... service and model layer calls omitted here ...&lt;/span&gt;
        &lt;span class="c"&gt;// Let's "pretend" we saved the user here&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;JSON&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;StatusOK&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;gin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;H&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"status"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"user created"&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is just the simplest example. If you add database operations, logging, parameter validation, and error handling... you can imagine the amount of code and repetitive labor involved. Every time I started a new project, it felt like reinventing the wheel. It was exhausting.&lt;/p&gt;

&lt;h4&gt;
  
  
  Go-Micro, Go-Zero, Kratos: Microservices are Great, But a Bit "Heavy"
&lt;/h4&gt;

&lt;p&gt;To solve the problems above, a batch of excellent "heavyweight" contenders emerged in the community, like go-micro, go-zero, and kratos. They provide comprehensive microservice governance capabilities, including everything from RPC, service discovery, and configuration centers to distributed tracing.&lt;/p&gt;

&lt;p&gt;But their "pain" lies here as well:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Steep learning curve&lt;/strong&gt;: To use them effectively, you have to spend a lot of time learning the framework's philosophy and its various components. For projects that need to get started and iterate quickly, this is a bit too "heavy."&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;"Black box" code generation&lt;/strong&gt;: Although they offer code generation tools, the generated code can sometimes be too "magical." When a problem occurs, it's hard to know where to start debugging. And for developers like us who are code purists, the feeling of not having full control over the code... you get it.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Bloated project structure&lt;/strong&gt;: A simple service might generate a huge pile of files and directories. Sometimes it feels like using a sledgehammer to crack a nut.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Discovering Sponge: My "Game-Changer" Moment!
&lt;/h3&gt;

&lt;p&gt;Just when I was about to lose my mind oscillating between "reinventing the wheel" and "being held hostage by a framework," I discovered &lt;strong&gt;Sponge&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Sponge perfectly balances &lt;strong&gt;development efficiency&lt;/strong&gt; and &lt;strong&gt;code controllability&lt;/strong&gt;, solving all the pain points mentioned above.&lt;/p&gt;

&lt;h4&gt;
  
  
  1. "Idiot-Proof" Code Generation, Say Goodbye to Repetitive Labor
&lt;/h4&gt;

&lt;p&gt;What amazed me most about Sponge is its powerful code generation capability. It doesn't just generate some template code; it's &lt;strong&gt;truly one-click generation of a complete project&lt;/strong&gt;!&lt;/p&gt;

&lt;p&gt;All you need to do is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Define your database table structure (e.g., in an SQL file).&lt;/li&gt;
&lt;li&gt;  Or define your API interface (in a Protobuf file).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then, with just a few clicks on Sponge's provided &lt;strong&gt;web interface&lt;/strong&gt;, a complete, production-ready backend service code is generated!&lt;/p&gt;

&lt;p&gt;Let's take the same user creation example. How do you do it with Sponge?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1&lt;/strong&gt;: Using MySQL as an example, write a &lt;code&gt;user.sql&lt;/code&gt; file and import it into your MySQL service. The process is similar for other databases (like PostgreSQL, MongoDB, etc.).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="nv"&gt;`user`&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nv"&gt;`id`&lt;/span&gt; &lt;span class="nb"&gt;bigint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nb"&gt;unsigned&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt; &lt;span class="n"&gt;AUTO_INCREMENT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nv"&gt;`name`&lt;/span&gt; &lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nv"&gt;`email`&lt;/span&gt; &lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;`id`&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="k"&gt;UNIQUE&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt; &lt;span class="nv"&gt;`idx_email`&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;`email`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;ENGINE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;InnoDB&lt;/span&gt; &lt;span class="k"&gt;DEFAULT&lt;/span&gt; &lt;span class="n"&gt;CHARSET&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;utf8mb4&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;Step 2&lt;/strong&gt;: In Sponge's web interface, select "Generate Web Service from SQL," enter your MySQL DSN, and choose the table.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3&lt;/strong&gt;: Click "Generate Code" and download the zip file.&lt;/p&gt;

&lt;p&gt;After unzipping, you get a &lt;strong&gt;complete, runnable project&lt;/strong&gt;! It includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;API Endpoints&lt;/strong&gt; (&lt;code&gt;/api/v1/user&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Swagger Docs&lt;/strong&gt; (auto-generated, for direct online debugging)&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Handler Layer&lt;/strong&gt; (request handling)&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Service Layer&lt;/strong&gt; (business logic)&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;DAO Layer&lt;/strong&gt; (database CRUD operations, based on GORM)&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;A complete project structure&lt;/strong&gt;, &lt;strong&gt;Makefile&lt;/strong&gt;, &lt;strong&gt;Dockerfile&lt;/strong&gt;...&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You read that right. &lt;strong&gt;Without writing a single line of Go code&lt;/strong&gt;, a fully functional CRUD service is ready! The development efficiency is off the charts!&lt;/p&gt;

&lt;h4&gt;
  
  
  2. Modular, "Lego-like" Architecture: Flexible and Decoupled
&lt;/h4&gt;

&lt;p&gt;The code generated by Sponge is not a pile of "spaghetti code." It adopts a very clear &lt;strong&gt;layered and decoupled design&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Each module is like a Lego block that you can freely combine and extend. For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Don't want to use GORM?&lt;/strong&gt; No problem. The DAO layer is interface-based, so you can easily replace it with any ORM you like.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Want to add custom logic?&lt;/strong&gt; The Service layer has already left a "template" for you. You just need to fill in the core business logic, without worrying about framework chores.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Want to migrate from a monolith to microservices?&lt;/strong&gt; A Sponge-generated project is naturally a microservice architecture, making it easy to split and combine services.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This design ensures development efficiency while giving developers immense &lt;strong&gt;freedom and a sense of control&lt;/strong&gt;. The code is "your" code, not the "framework's" code.&lt;/p&gt;

&lt;h4&gt;
  
  
  3. Rich Built-in Components, Out of the Box
&lt;/h4&gt;

&lt;p&gt;Sponge is more than just a code generator; it's an "all-in-one suite."&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Web Framework&lt;/strong&gt;: Built on Gin, allowing you to seamlessly use all of Gin's middleware and ecosystem.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;RPC Framework&lt;/strong&gt;: Supports gRPC and can generate a gRPC Gateway with one click, enabling your gRPC service to support HTTP calls simultaneously.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Service Governance&lt;/strong&gt;: Integrates essential microservice components like service discovery, circuit breaking, rate limiting, distributed tracing, and monitoring.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Common Libraries&lt;/strong&gt;: Redis, MongoDB, Kafka, RabbitMQ... they're all pre-packaged and ready to use out of the box.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With Gin, I used to have to find, integrate, and wrap each of these libraries myself. Now with Sponge, I just enable them in the configuration file. It's incredibly convenient!&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion: Why I'm Raving About Sponge
&lt;/h3&gt;

&lt;p&gt;Returning to the original question, after looking at so many Go frameworks, why did I ultimately choose Sponge?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;For individual developers and startups&lt;/strong&gt;: In the world of software, speed is king. Sponge lets you build product prototypes and validate ideas at maximum speed, allowing you to focus on core business logic instead of repetitive grunt work.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;For medium to large teams&lt;/strong&gt;: Sponge unifies project structure and development standards, lowering the learning curve for new members and improving team collaboration. Its high-cohesion, low-coupling design also makes projects easier to maintain and extend.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;For Gophers who strive for excellence&lt;/strong&gt;: Sponge has no "black magic." The generated code is clean and standardized, allowing you to enjoy high-efficiency development while still having complete control over your code and learning excellent architectural design principles from it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Of course, no framework is a perfect silver bullet. But Sponge truly won me over. It's like an experienced senior developer who takes care of all the dirty work for you, so you can focus on the creative tasks.&lt;/p&gt;

&lt;p&gt;If you, like me, are tired of wavering between different frameworks and fed up with day-to-day repetitive labor, I highly recommend giving Sponge a try. Head over to its GitHub repository, run the examples, and trust me, you'll find yourself shouting the same thing I did: &lt;strong&gt;This is a game-changer!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sponge Project Link&lt;/strong&gt;: &lt;a href="https://github.com/go-dev-frame/sponge" rel="noopener noreferrer"&gt;https://github.com/go-dev-frame/sponge&lt;/a&gt;&lt;/p&gt;



</description>
      <category>go</category>
      <category>gin</category>
      <category>grpc</category>
      <category>backend</category>
    </item>
    <item>
      <title>From Node.js to Go: How to Smoothly Transition from NestJS and Fall in Love with the Sponge Framework</title>
      <dc:creator>gvison</dc:creator>
      <pubDate>Mon, 23 Jun 2025 09:23:30 +0000</pubDate>
      <link>https://dev.to/zhufuyi/from-nodejs-to-go-how-to-smoothly-transition-from-nestjs-and-fall-in-love-with-the-sponge-3l5l</link>
      <guid>https://dev.to/zhufuyi/from-nodejs-to-go-how-to-smoothly-transition-from-nestjs-and-fall-in-love-with-the-sponge-3l5l</guid>
      <description>&lt;h3&gt;
  
  
  Introduction
&lt;/h3&gt;

&lt;p&gt;Hey NestJS veterans, let's be honest, &lt;strong&gt;developing APIs with decorators feels like waltzing on your keyboard&lt;/strong&gt;—a spin with &lt;code&gt;@Controller&lt;/code&gt;, a tiptoe with &lt;code&gt;@Get&lt;/code&gt;, an elegant bow with &lt;code&gt;@Injectable&lt;/code&gt;, and voilà, a decent backend service is up and running in no time. TypeScript's type checking is like a considerate butler, and the CLI's &lt;code&gt;nest g&lt;/code&gt; is practically a magic wand in the coding world. A few keystrokes, and your project scaffold magically appears—it's exhilarating!&lt;/p&gt;

&lt;p&gt;However, when the requirements suddenly shift to handling real-time data from millions of smart light bulbs, or your boss slams the table shouting, "Cut the server budget in half!", do you find yourself sighing at Node.js's single thread: "Buddy, can your small frame handle this?" Just then, Go strides in confidently, showcasing its concurrency primitives, compilation speed, and memory efficiency... Wow, who wouldn't be tempted?&lt;/p&gt;

&lt;p&gt;But, when you eagerly open your Go IDE, ready to make your mark—&lt;strong&gt;wait, where are my &lt;code&gt;@Decorator&lt;/code&gt;s? Where's my dependency injection? My code generator?&lt;/strong&gt; Switching from NestJS's "fully automatic coffee machine" to Go's "manual coffee bean grinding" mode, the drop in experience is like going from a five-star hotel buffet back to instant noodles with a sausage...&lt;/p&gt;



&lt;h3&gt;
  
  
  Five "Culture Shocks" for Node.js Developers Switching to Go
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. CLI Dependency Withdrawal
&lt;/h4&gt;

&lt;p&gt;In NestJS:&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="c"&gt;# Just a few keystrokes, and the project scaffold magically appears!&lt;/span&gt;
nest new my-project
nest g module &lt;span class="nb"&gt;users
&lt;/span&gt;nest g controller &lt;span class="nb"&gt;users
&lt;/span&gt;nest g service &lt;span class="nb"&gt;users&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In native Go:&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;my-project
&lt;span class="nb"&gt;cd &lt;/span&gt;my-project
go mod init my-project
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="nb"&gt;users&lt;/span&gt;/handlers &lt;span class="nb"&gt;users&lt;/span&gt;/services
&lt;span class="nb"&gt;touch users&lt;/span&gt;/handlers/users.go &lt;span class="nb"&gt;users&lt;/span&gt;/services/users.go
&lt;span class="c"&gt;# Then start manually writing a bunch of boilerplate code...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;h4&gt;
  
  
  2. The Loss of Modularity and DI
&lt;/h4&gt;

&lt;p&gt;The elegance of NestJS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Watch me wave my decorator wand, dependencies auto-injected!&lt;/span&gt;
&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Module&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;imports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;DatabaseModule&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;controllers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;UserController&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;UserService&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserModule&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The "simplicity" of native Go:&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;// You need to manually initialize all dependencies&lt;/span&gt;
&lt;span class="n"&gt;db&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;NewDB&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;userRepo&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;NewUserRepository&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;userService&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;NewUserService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userRepo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;userHandler&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;NewUserHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userService&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;h4&gt;
  
  
  3. Missing Type Systems and Decorators
&lt;/h4&gt;

&lt;p&gt;The comfort zone of NestJS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Route decorators are more versatile than a magician's hat&lt;/span&gt;
&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;:id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;getUser&lt;/span&gt;&lt;span class="p"&gt;(@&lt;/span&gt;&lt;span class="nd"&gt;Param&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;UserDto&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findOne&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&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;The explicit style of native Go:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;GetUser&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;gin&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;id&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;Param&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;user&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;userService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FindOne&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="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="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;gin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;H&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"error"&lt;/span&gt;&lt;span class="o"&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;Error&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;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user&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;h4&gt;
  
  
  4. Shift in Asynchronous Programming Mindset
&lt;/h4&gt;

&lt;p&gt;Node.js's linear thinking:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// `await` is my time-stopper; code must follow my script&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getUserWithOrders&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userId&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;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userId&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;orders&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getOrders&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;orders&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;Go's concurrency philosophy:&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;// Welcome to the concurrency circus! Watch me juggle multiple task balls simultaneously!&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;GetUserWithOrders&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userId&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;UserWithOrders&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;user&lt;/span&gt; &lt;span class="n"&gt;User&lt;/span&gt;
    &lt;span class="k"&gt;var&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;Order&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;userErr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ordersErr&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;

    &lt;span class="n"&gt;wg&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;sync&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WaitGroup&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Done&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;userErr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;GetUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}()&lt;/span&gt;

    &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Done&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;ordersErr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;GetOrders&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}()&lt;/span&gt;

    &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Wait&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;userErr&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;ordersErr&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;UserWithOrders&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"errors: %v, %v"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;userErr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ordersErr&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="n"&gt;UserWithOrders&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Orders&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;h4&gt;
  
  
  5. Change in Error Handling Habits
&lt;/h4&gt;

&lt;p&gt;Node.js's try-catch:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Error? Just toss it into the black hole for now&lt;/span&gt;
&lt;span class="k"&gt;try&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;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;someAsyncOperation&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="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;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Oops:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Go's explicit error handling:&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;// Every error is a traffic light; must stop and check!&lt;/span&gt;
&lt;span class="n"&gt;result&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;SomeOperation&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="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Oops: %v"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;h3&gt;
  
  
  Sponge Framework – The Savior for Node.js to Go Transition Arrives
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. What is Sponge?
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://github.com/go-dev-frame" rel="noopener noreferrer"&gt;&lt;strong&gt;sponge&lt;/strong&gt;&lt;/a&gt; is a powerful and easy-to-use Go development framework. Its core philosophy is to reverse-generate modular code by parsing &lt;code&gt;SQL&lt;/code&gt;, &lt;code&gt;Protobuf&lt;/code&gt;, and &lt;code&gt;JSON&lt;/code&gt; files. These code modules can be flexibly combined into various types of complete backend services.&lt;/p&gt;

&lt;p&gt;sponge provides a one-stop project development solution with excellent project engineering capabilities, covering code generation, development, testing, API documentation, and deployment. It helps developers easily build stable and reliable high-performance backend service systems (including RESTful API, gRPC, HTTP+gRPC, gRPC Gateway, etc.) in a "low-code" manner.&lt;/p&gt;



&lt;h4&gt;
  
  
  2. Sponge's Three Killer Features
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;① Code Generator&lt;/strong&gt; – Faster Than Copy-Pasting&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="c"&gt;# Start the code generation UI&lt;/span&gt;
sponge run
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Visit &lt;code&gt;http://localhost:24631&lt;/code&gt;, and you'll see:&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%2Fekm6og9vwad16u40d794.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%2Fekm6og9vwad16u40d794.png" alt="sponge-ui" width="800" height="682"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Automatically generate RESTful API, gRPC, HTTP+gRPC, gRPC Gateway, etc., service code&lt;/li&gt;
&lt;li&gt;One-click CRUD code generation&lt;/li&gt;
&lt;li&gt;Custom APIs only require filling in business logic&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;🚀 Effect: What used to take a day's work, now done in 1 minute!&lt;/p&gt;
&lt;/blockquote&gt;



&lt;p&gt;&lt;strong&gt;② Modular Design&lt;/strong&gt; – Project Structure as Clear as LEGOs&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;// Auto-generated user module structure&lt;/span&gt;
&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;api&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="n"&gt;internal&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
    &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;    &lt;span class="c"&gt;// Business logic layer&lt;/span&gt;
    &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;dao&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;        &lt;span class="c"&gt;// Data access layer&lt;/span&gt;
    &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;      &lt;span class="c"&gt;// Entity classes&lt;/span&gt;
    &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;     &lt;span class="c"&gt;// Service&lt;/span&gt;
    &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;      &lt;span class="c"&gt;// Cache&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;p&gt;&lt;strong&gt;③ Built-in Enterprise-Grade Components&lt;/strong&gt; – Say Goodbye to Decision Paralysis&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Web Framework √
gRPC Framework √
ORM √
Configuration Management √
Logging √ 
Tracing √
Monitoring √
Service Discovery √
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;h3&gt;
  
  
  Practical Comparison: Creating a User API
&lt;/h3&gt;

&lt;p&gt;In NestJS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// user.controller.ts&lt;/span&gt;
&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Controller&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;users&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserController&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;userService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UserService&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="nd"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;:id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;getUser&lt;/span&gt;&lt;span class="p"&gt;(@&lt;/span&gt;&lt;span class="nd"&gt;Param&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findOne&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&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="c1"&gt;// user.service.ts&lt;/span&gt;
&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Injectable&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;userRepo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UserRepository&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;findOne&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userRepo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findOne&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&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;Sponge-generated version:&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;// Auto-generated handler&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;userHandler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;CreateUser&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;gin&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="c"&gt;// Note: Original had CreatUser, common typo, corrected to CreateUser&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;pb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CreateUserRequest&lt;/span&gt; &lt;span class="c"&gt;// Corrected typo from CreatUserRequest&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;ShouldBindJSON&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="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&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="c"&gt;// Assuming h.dao.CreateUser exists and follows this pattern.&lt;/span&gt;
    &lt;span class="c"&gt;// The original snippet was:&lt;/span&gt;
    &lt;span class="c"&gt;// if result, err := h.dao.CreatUser(ctx, &amp;amp;req); err != nil {&lt;/span&gt;
    &lt;span class="c"&gt;//     return 0, err // This implies the DAO returns (uint64, error)&lt;/span&gt;
    &lt;span class="c"&gt;// }&lt;/span&gt;
    &lt;span class="c"&gt;// For a create operation, it might not return a result directly in the handler like this.&lt;/span&gt;
    &lt;span class="c"&gt;// More typically, you'd call the service/DAO and then respond.&lt;/span&gt;
    &lt;span class="c"&gt;// Let's adjust to a more common pattern for a handler.&lt;/span&gt;
    &lt;span class="n"&gt;_&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;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;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;Request&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="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="c"&gt;// Example: calling a service method&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="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&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;// Assuming response.Error handles logging and JSON response&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;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Success&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// Auto-generated DAO (example, assuming direct call from handler was intended to be to DAO)&lt;/span&gt;
&lt;span class="c"&gt;// The original was:&lt;/span&gt;
&lt;span class="c"&gt;// func (d *dao) CreatUser(ctx context.Context, req *pb.CreatUserRequest) (uint64, error) {&lt;/span&gt;
&lt;span class="c"&gt;//     // business logic code ...&lt;/span&gt;
&lt;span class="c"&gt;//     if err := CreateUser(ctx, req); err != nil { // This CreateUser is undefined in this context&lt;/span&gt;
&lt;span class="c"&gt;//         return 0, err&lt;/span&gt;
&lt;span class="c"&gt;//     }&lt;/span&gt;
&lt;span class="c"&gt;// }&lt;/span&gt;
&lt;span class="c"&gt;// Let's make it more concrete based on typical DAO patterns&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;d&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;userDao&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="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CreateUserRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;uint64&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="c"&gt;// Business logic... e.g., convert req to a model, save to DB&lt;/span&gt;
    &lt;span class="c"&gt;// userModel := &amp;amp;model.User{Name: req.Name, Email: req.Email} // Example&lt;/span&gt;
    &lt;span class="c"&gt;// result, err := d.db.Create(userModel).Error // Example with GORM&lt;/span&gt;
    &lt;span class="c"&gt;// if err != nil {&lt;/span&gt;
    &lt;span class="c"&gt;//     return 0, err&lt;/span&gt;
    &lt;span class="c"&gt;// }&lt;/span&gt;
    &lt;span class="c"&gt;// return userModel.ID, nil&lt;/span&gt;
    &lt;span class="c"&gt;// For simplicity, let's assume the business logic is here:&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Creating user: %v"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetName&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="c"&gt;// Example of using the request&lt;/span&gt;
    &lt;span class="c"&gt;// Placeholder for actual database interaction&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;userID&lt;/span&gt; &lt;span class="kt"&gt;uint64&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="c"&gt;// Dummy ID&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;userID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; 
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="c"&gt;// Apart from the business logic, all other code is generated by sponge.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;🔍 See the difference? Although the syntax is different, the development experience is highly consistent!&lt;/p&gt;
&lt;/blockquote&gt;



&lt;h3&gt;
  
  
  Why Node.js Developers Should Try Sponge?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Seamless Productivity Transition&lt;/strong&gt;: Sponge's CLI and code generation capabilities let you experience NestJS-like development efficiency in the Go world.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Familiar "Recipe"&lt;/strong&gt;: Modular design, API definition methods, and microservice component integration will make you feel the familiarity of using NestJS.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;"Best of Both Worlds"&lt;/strong&gt;: Enjoy the performance and concurrency advantages of Go while getting a NestJS-like efficient development experience.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Microservices "Power Tool"&lt;/strong&gt;: Sponge is inherently designed for microservices, integrating essential components like service governance, tracing, and monitoring.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;



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

&lt;p&gt;The hardest part of transitioning to Go isn't the syntax, but the &lt;strong&gt;shift in mindset&lt;/strong&gt;. While you can't write Node.js-style code in Go, you can enjoy a NestJS-like development experience with Sponge!&lt;/p&gt;

&lt;p&gt;What are you waiting for? Get moving! Follow the official documentation and whip up a demo in 1 minute.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sponge GitHub Address: &lt;a href="https://github.com/go-dev-frame/sponge" rel="noopener noreferrer"&gt;https://github.com/go-dev-frame/sponge&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Sponge Development Documentation: &lt;a href="https://go-sponge.com/" rel="noopener noreferrer"&gt;https://go-sponge.com/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>node</category>
      <category>nestjs</category>
      <category>backend</category>
    </item>
    <item>
      <title>From PHP to Go: How to Gracefully Escape the Laravel Comfort Zone and Experience the "Truly Sweet" Joy of Sponge</title>
      <dc:creator>gvison</dc:creator>
      <pubDate>Wed, 28 May 2025 05:28:56 +0000</pubDate>
      <link>https://dev.to/zhufuyi/from-php-to-go-how-to-gracefully-escape-the-laravel-comfort-zone-and-experience-the-truly-sweet-1p9a</link>
      <guid>https://dev.to/zhufuyi/from-php-to-go-how-to-gracefully-escape-the-laravel-comfort-zone-and-experience-the-truly-sweet-1p9a</guid>
      <description>&lt;h3&gt;
  
  
  The Joys and Worries of an Experienced PHP Developer
&lt;/h3&gt;

&lt;p&gt;Dear experienced PHP developers, honestly, isn't writing PHP incredibly satisfying? Variables can change types however you like, forgetting a semicolon is no biggie, and with the Laravel framework, a few &lt;code&gt;php artisan make:controller&lt;/code&gt; commands and a CRUD is done, faster than instant noodles!&lt;/p&gt;

&lt;p&gt;But when your website user base rockets upwards like a missile, or the boss suddenly talks about microservices and high concurrency, the PHP developers start huffing and puffing. That's when the Go developer at the next desk might wink at you: "Hey, buddy, wanna give me a try? Compiles into a single file, deployment is as easy as drinking milk tea, and the performance is stellar!"&lt;/p&gt;



&lt;h3&gt;
  
  
  Five Major "Soul-Searching Questions" for PHP Developers Switching to Go
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. Dynamic Typing vs. Static Typing: From "Wild Card" to "Sharp Dresser"
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;PHP's Joy:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"PHP Developer"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// Today I'm a string&lt;/span&gt;
&lt;span class="nv"&gt;$name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;        &lt;span class="c1"&gt;// Tomorrow I want to be a number&lt;/span&gt;
&lt;span class="nv"&gt;$name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;        &lt;span class="c1"&gt;// The day after, I'll be an array&lt;/span&gt;
&lt;span class="c1"&gt;// PHP: No problem, buddy, whatever makes you happy!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Go's "OCD":&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Go Developer"&lt;/span&gt;
&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="m"&gt;42&lt;/span&gt; &lt;span class="c"&gt;// Compilation will hit you hard: cannot assign int to string!&lt;/span&gt;
&lt;span class="c"&gt;// Go: Buddy, we need to be clear, what exactly do you want to be?&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;h4&gt;
  
  
  2. OOP Differences: From "Inheritance Magic" to "Composition is King"
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;PHP's Comfort Zone:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Model&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;SoftDeletes&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Traits are so useful!&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;Go's New World:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;User&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;gorm&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Model&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// Go: Inheritance? Doesn't exist! We focus on composition.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;h4&gt;
  
  
  3. Framework Dependency Syndrome: From "Fully Automatic Luxury Car" to "Manual Tractor"
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;PHP's Luxury Experience:&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;php artisan make:model Product -mc
// One command generates model, controller, migration file
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Go's DIY Life:&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;Manually choose Gin or Echo...
Manually choose GORM or Xorm, Sqlx, Ent...
Manually set up project structure...
// Feels like going back to the Stone Age
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;h4&gt;
  
  
  4. Concurrency Models: From "External Player" to "Native Champion"
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;PHP's Concurrency:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Either rely on PHP-FPM multi-process&lt;/span&gt;
&lt;span class="c1"&gt;// Or bring in Swoole/Workerman as external help&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Go's Killer Feature:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// Easily start a goroutine&lt;/span&gt;
&lt;span class="p"&gt;}()&lt;/span&gt;
&lt;span class="c"&gt;// Go: Concurrency? Piece of cake!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;h4&gt;
  
  
  5. Dependency Management: From "Composer One-Stop Shop" to "Go Modules New Style"
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;PHP's Convenience:&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;composer require laravel/sanctum
// Everything done with one command
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Go's Evolution:&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;go mod init
go get -u github.com/gin-gonic/gin
// While not as convenient as Composer, it's much better than the GOPATH era
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;h3&gt;
  
  
  Sponge Framework - The Go Language Plugin for Phpers
&lt;/h3&gt;

&lt;p&gt;Missing the convenience of Laravel? Actually, Sponge isn't bad either!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is Sponge?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/go-dev-frame" rel="noopener noreferrer"&gt;&lt;strong&gt;sponge&lt;/strong&gt;&lt;/a&gt; is a powerful and easy-to-use Go development framework. Its core concept is to generate modular code by parsing &lt;code&gt;SQL&lt;/code&gt;, &lt;code&gt;Protobuf&lt;/code&gt;, and &lt;code&gt;JSON&lt;/code&gt; files. These modules can be flexibly combined to form various types of complete backend services.&lt;/p&gt;

&lt;p&gt;Sponge provides a one-stop project development solution with excellent project engineering capabilities, covering code generation, development, testing, API documentation, and deployment. It helps developers easily build stable and reliable high-performance backend service systems (including RESTful API, gRPC, HTTP+gRPC, gRPC Gateway, etc.) in a "low-code" manner.&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;Sponge's Magic: Powerful Code Generation Engine&lt;/strong&gt;&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%2Fqt3dwe44tly10410i0w7.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%2Fqt3dwe44tly10410i0w7.png" alt=" " width="800" height="683"&gt;&lt;/a&gt;&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;PHP-like Comfort Brought by Sponge:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Code Generation: As satisfying as artisan&lt;/li&gt;
&lt;li&gt;All-in-one integration: Gin, GORM, Redis, etc., all packaged&lt;/li&gt;
&lt;li&gt;Unified Standards: No more arguing about code style&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With Sponge as your "plugin", you're guaranteed to complete the transition from PHP to Go with a smile!&lt;/p&gt;



&lt;h3&gt;
  
  
  Why PHP Developers Should Try Sponge?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Development Efficiency Takes Off:&lt;/strong&gt; Sponge's code generation capabilities and rich integrated components allow you to experience the lightning-fast development speed of PHP frameworks within a Go project. No more starting from scratch like "eating raw meat and blood".&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Familiar "Recipe", Familiar "Taste":&lt;/strong&gt; Many features and the "convention over configuration" philosophy provided by Sponge will give you that sense of familiarity you had when using PHP frameworks like Laravel and Symfony, significantly flattening the learning curve.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The Joy of "Having Your Cake and Eating It Too":&lt;/strong&gt; You get to enjoy the ultimate performance, powerful concurrency capabilities, and deployment convenience brought by the Go language, while also gaining the development efficiency and project standardization that come with a mature framework. Isn't this what we want?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Low Code, High Efficiency, Pure Bliss:&lt;/strong&gt; You only need to focus on the core business logic. A large amount of generic, repetitive, and basic code is automatically generated by Sponge, truly letting you experience the fun of "low-code development".&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Easily Master Modern Microservice Architecture:&lt;/strong&gt; Sponge inherently supports the components and concepts required for microservice development, helping PHP developers build and migrate to cloud-native applications more easily.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;



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

&lt;p&gt;The Sponge framework is like a powerful "accelerator" that helps you smoothly transition, enjoy the charm of the Go language, and maintain high development efficiency and happiness. By using Sponge to make up for engineering shortcomings, experienced Laravel developers can still race on the Go track!&lt;/p&gt;

&lt;p&gt;Take action! What are you waiting for? Follow the official documentation and build a demo in 1 minute.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sponge GitHub address: &lt;a href="https://github.com/go-dev-frame/sponge" rel="noopener noreferrer"&gt;https://github.com/go-dev-frame/sponge&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Sponge Development Documentation: &lt;a href="https://go-sponge.com/zh/" rel="noopener noreferrer"&gt;https://go-sponge.com/zh/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>php</category>
      <category>laravel</category>
    </item>
    <item>
      <title>From Java to Go: The Elegant Escape from Spring's Comfort Zone to the "True Fragrance" of Sponge</title>
      <dc:creator>gvison</dc:creator>
      <pubDate>Sat, 24 May 2025 14:00:36 +0000</pubDate>
      <link>https://dev.to/zhufuyi/from-java-to-go-the-elegant-escape-from-springs-comfort-zone-to-the-true-fragrance-of-sponge-5248</link>
      <guid>https://dev.to/zhufuyi/from-java-to-go-the-elegant-escape-from-springs-comfort-zone-to-the-true-fragrance-of-sponge-5248</guid>
      <description>&lt;p&gt;Hey, Java folks, isn't using the Spring full stack as comfortable as wearing thermal underwear? Maven and Gradle manage dependencies more closely than your own mom, and IntelliJ IDEA makes writing code as smooth as Dove chocolate. But with the cloud-native trend blowing like a mischievous wind, Go language, this young fellow, with concurrency performance comparable to Liu Xiang's speed and agility like Bruce Lee, has unexpectedly become the "new top flow" in the coding community!&lt;/p&gt;

&lt;p&gt;Java developers entering the Go world for the first time feel like a Northerner visiting a Cantonese dim sum restaurant for the first time – don't know how to use the utensils, can't name the dim sum! Today, let's watch those "culture shock" moments that make you not know whether to laugh or cry, and then recommend a magic tool – the Sponge framework – that can turn Javaers into "local experts" in seconds!&lt;/p&gt;



&lt;h3&gt;
  
  
  Java Veterans' Showcase of Confusing Go Behaviors
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. The OOP Obsessive's Nightmare
&lt;/h4&gt;

&lt;p&gt;Java folks write code like this:&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="c1"&gt;// A class structure like a 3-bedroom apartment, inheritance like a family tree&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;abstract&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Animal&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
   &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
   &lt;span class="c1"&gt;// Constructors showcasing a multitude of techniques&lt;/span&gt;
   &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;Animal&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;name&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/*...*/&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&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;Cat&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Animal&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;ClimbTree&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
   &lt;span class="c1"&gt;// Method overloading played better than Russian nesting dolls&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;meow&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="cm"&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;Go newbies tremble:&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;// That's it? struct + composition is all you need?&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Animal&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Cat&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Animal&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;  &lt;span class="c"&gt;// Ancestral inheritance? Doesn't exist!&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;c&lt;/span&gt; &lt;span class="n"&gt;Cat&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Meow&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Meow Punch!"&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;blockquote&gt;
&lt;p&gt;Inner Monologue: My Six-Meridian Divine Swords of design patterns are just useless now?&lt;/p&gt;
&lt;/blockquote&gt;



&lt;h4&gt;
  
  
  2. The Soul-Searching Question of Exception Handling
&lt;/h4&gt;

&lt;p&gt;Java-style elegance:&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="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
   &lt;span class="n"&gt;riskyOperation&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;Exception&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="c1"&gt;// Elegantly passing the buck to the global exception handler&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Go-style robustness:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;result&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;riskyOperation&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="c"&gt;// Writing foolproof code on every line&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Something went wrong, folks!"&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;blockquote&gt;
&lt;p&gt;Real experience: After three days of writing Go, the number of 'if err' exceeds three years of Java try-catch&lt;/p&gt;
&lt;/blockquote&gt;



&lt;h4&gt;
  
  
  3. Framework Dependency Withdrawal Symptoms
&lt;/h4&gt;

&lt;p&gt;Day one after leaving Spring Boot:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Want to use ORM? gorm, xorm, sqlx, Ent - choose whatever you like (Choice paralysis strikes)&lt;/li&gt;
&lt;li&gt;Need DI? wire, dig - various manual fiddling (Missing @Autowired for the 114514th second)&lt;/li&gt;
&lt;li&gt;Microservice governance? Assemble Prometheus+Jaeger yourself (Gradually getting irritable)&lt;/li&gt;
&lt;/ul&gt;



&lt;h4&gt;
  
  
  4. The Dimensional Wall of Concurrency Programming
&lt;/h4&gt;

&lt;p&gt;Java Old Hand:&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="c1"&gt;// Thread pool configuration can fill three pages of A4 paper&lt;/span&gt;
&lt;span class="nc"&gt;ExecutorService&lt;/span&gt; &lt;span class="n"&gt;executor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Executors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newFixedThreadPool&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="nc"&gt;Future&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="n"&gt;future&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;executor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;submit&lt;/span&gt;&lt;span class="o"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"Async Task"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Go Newbie:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  &lt;span class="c"&gt;// So lightweight, just like cracking melon seeds&lt;/span&gt;
   &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"I'm the coolest goroutine!"&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;blockquote&gt;
&lt;p&gt;Confusing behavior: Always trying to find a Go version of ThreadPoolExecutor, only to find channels are actually quite good&lt;/p&gt;
&lt;/blockquote&gt;



&lt;h3&gt;
  
  
  Sponge Framework - The Go Language Plugin for Javaers
&lt;/h3&gt;

&lt;p&gt;What is sponge?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/go-dev-frame/sponge" rel="noopener noreferrer"&gt;&lt;strong&gt;sponge&lt;/strong&gt;&lt;/a&gt; is a powerful and easy-to-use Go development framework. Its core idea is to generate modular code by parsing &lt;code&gt;SQL&lt;/code&gt;, &lt;code&gt;Protobuf&lt;/code&gt;, and &lt;code&gt;JSON&lt;/code&gt; files, which can be flexibly combined to form various types of complete backend services.&lt;/p&gt;

&lt;p&gt;Sponge provides a one-stop project development solution with excellent engineering capabilities, covering code generation, development, testing, API documentation, and deployment. It helps developers easily build stable, reliable, high-performance backend service systems (including RESTful API, gRPC, HTTP+gRPC, gRPC Gateway, etc.) in a "low-code" manner.&lt;/p&gt;

&lt;p&gt;When you encounter setbacks and feel discouraged in the Go programming world, Sponge appears like a timely programming companion! This efficient framework, designed specifically to alleviate the "Java to Go adaptation difficulty", has three core components:&lt;/p&gt;



&lt;h4&gt;
  
  
  🚀 Low-Code Generator (Comparable to Spring Initializr)
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Start the code generation page&lt;/span&gt;
sponge run
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Visit &lt;code&gt;http://localhost:24631&lt;/code&gt;, you will see:&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%2Ftsfiixdhyugvqkc3wnlp.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%2Ftsfiixdhyugvqkc3wnlp.png" alt=" " width="800" height="683"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On the page, click the mouse a few times, and instantly generate a project containing these luxury packages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🍔 Gin/gRPC Framework (Choose either)&lt;/li&gt;
&lt;li&gt;🥤 GORM/Mongodb Database Package&lt;/li&gt;
&lt;li&gt;🍟 JWT Auth + Tracing + Metrics&lt;/li&gt;
&lt;li&gt;🍰 Swagger Documentation and more, all included&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;The effect is comparable to JHipster in the Java world, no more worrying about setting up the framework!&lt;/p&gt;
&lt;/blockquote&gt;



&lt;h4&gt;
  
  
  🎮 Spring-style Development Experience
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;IoC Equivalent&lt;/strong&gt;: Module auto-wiring, say goodbye to manual dependency fiddling&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AOP Equivalent&lt;/strong&gt;: Middleware interceptors implement aspect-oriented programming&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Configuration Center&lt;/strong&gt;: Supports local files / nacos remote configuration&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DevOps Full Stack&lt;/strong&gt;: Dockerfile + k8s YAML one-click generation&lt;/li&gt;
&lt;/ul&gt;



&lt;h4&gt;
  
  
  ⚡ Implementing Business Code is Like Doing Fill-in-the-Blanks
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// Auto-generated CRUD code (A whiff of Java flavor)&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;UserService&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;userDao&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;dao&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UserDao&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;NewUserService&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;UserService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;UserService&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;userDao&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;dao&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewUserDao&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="c"&gt;// Similar to dependency injection&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// Writing business logic by hand is like filling in blanks&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;UserService&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;GetUser&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;uint&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;User&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;return&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;userDao&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;id&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;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Sponge framework, like a powerful "accelerator", can help you smoothly transition, enjoy the charm of the Go language, while maintaining efficient development productivity and happiness. Use Sponge to make up for engineering shortcomings, Spring Boot/Cloud old drivers can still speed on the Go track!&lt;/p&gt;

&lt;p&gt;Get into action! What are you waiting for? Quickly follow the official documentation and build a demo in 1 minute&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;sponge github address: &lt;a href="https://github.com/go-dev-frame/sponge" rel="noopener noreferrer"&gt;https://github.com/go-dev-frame/sponge&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;sponge development documentation: &lt;a href="https://go-sponge.com/zh/" rel="noopener noreferrer"&gt;https://go-sponge.com/zh/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>java</category>
      <category>spring</category>
      <category>springboot</category>
    </item>
    <item>
      <title>Sponge vs Spring: A Comprehensive Comparison and Selection Guide</title>
      <dc:creator>gvison</dc:creator>
      <pubDate>Wed, 19 Feb 2025 07:50:35 +0000</pubDate>
      <link>https://dev.to/zhufuyi/sponge-vs-spring-a-comprehensive-comparison-and-selection-guide-490e</link>
      <guid>https://dev.to/zhufuyi/sponge-vs-spring-a-comprehensive-comparison-and-selection-guide-490e</guid>
      <description>&lt;h3&gt;
  
  
  Framework Comparison and Selection Guide
&lt;/h3&gt;

&lt;p&gt;In today's fast-evolving technological landscape, choosing the right development framework is crucial for the success of a project. This article provides a detailed comparison of two popular frameworks—Sponge and Spring—to help developers make an informed choice based on project requirements.&lt;/p&gt;

&lt;h4&gt;
  
  
  Framework Feature Comparison
&lt;/h4&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Sponge&lt;/th&gt;
&lt;th&gt;Spring&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Programming Language&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Go (Golang)&lt;/td&gt;
&lt;td&gt;Java&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Design Paradigm&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Low-code, Code Generation, Modularization&lt;/td&gt;
&lt;td&gt;IoC (Inversion of Control), DI (Dependency Injection), AOP (Aspect-Oriented Programming)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Performance&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;High performance, fast execution speed, excellent concurrency&lt;/td&gt;
&lt;td&gt;Mature performance, requires JVM tuning, potentially long startup time&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Maturity &amp;amp; Stability&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Relatively new, rapidly evolving&lt;/td&gt;
&lt;td&gt;Highly mature, industry standard, high stability&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Applicable Scenarios&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;RESTFul API, Backend Services, Microservices, Rapid Development&lt;/td&gt;
&lt;td&gt;Enterprise applications, Web applications, Microservices, Backend systems, Broad applicability&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Learning Curve&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Relatively low, low-code reduces development barriers&lt;/td&gt;
&lt;td&gt;Steep learning curve, vast and complex ecosystem&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Core Features&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Code generation (SQL, Protobuf, JSON, Custom Templates), Gin, gRPC, ORM, API Documentation, CRUD, Modularization&lt;/td&gt;
&lt;td&gt;IoC container, DI, AOP, Spring MVC, Data Access, Transaction Management, Web Services, JDBC Abstraction, Testing Framework, Modularization&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Web Framework&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Gin&lt;/td&gt;
&lt;td&gt;Spring MVC, Spring WebFlux (Reactive)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Microservices Support&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Natively designed for microservices, supports multiple microservice architectures&lt;/td&gt;
&lt;td&gt;Excellent microservices support through Spring Boot and Spring Cloud&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Code Generation Capability&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Core feature, powerful, highly automated&lt;/td&gt;
&lt;td&gt;Relatively weak, Spring Initializr provides project initialization and limited scaffolding&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Database Support&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;MySQL, MongoDB, PostgreSQL, SQLite&lt;/td&gt;
&lt;td&gt;Extensive database support via Spring Data and JDBC&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Service Governance&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Service registration &amp;amp; discovery (Consul, Etcd, Nacos), Load balancing, Circuit breaker, Rate limiting, Tracing, Monitoring, Configuration Center&lt;/td&gt;
&lt;td&gt;Spring Cloud suite (e.g., Eureka, Consul, Nacos, Ribbon, Hystrix, Gateway, Sleuth, Zipkin), Service registration &amp;amp; discovery, Load balancing, Circuit breaker, Rate limiting, API Gateway, Tracing, Configuration Center, Monitoring&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Community&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Relatively small but growing&lt;/td&gt;
&lt;td&gt;Large and highly active, with extensive resources and support&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Toolchain&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;UI tools, Command-line tools&lt;/td&gt;
&lt;td&gt;Spring Boot, Spring Initializr, Maven, Gradle, IDE support&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Documentation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Comprehensive official documentation (&lt;a href="https://go-sponge.com/" rel="noopener noreferrer"&gt;https://go-sponge.com/&lt;/a&gt;)&lt;/td&gt;
&lt;td&gt;Extensive documentation, tutorials, books, online resources, official site (&lt;a href="https://spring.io/" rel="noopener noreferrer"&gt;https://spring.io/&lt;/a&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h4&gt;
  
  
  Summary &amp;amp; Selection Recommendations
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Spring&lt;/strong&gt; is a mature and comprehensive Java enterprise application framework with a vast community and ecosystem. It is centered around IoC, DI, and AOP, offering numerous modules and functionalities needed to build complex applications. Spring is suitable for large-scale enterprise applications, particularly those requiring high scalability, reliability, and security. However, Spring has a steep learning curve, involves complex configurations, and has relatively long startup times.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sponge&lt;/strong&gt; is an emerging Go development framework focused on improving development efficiency and lowering entry barriers. It emphasizes code generation and integrates common components such as the Gin web framework, gRPC RPC framework, and microservice capabilities. It also provides a user-friendly UI interface and comprehensive documentation. Sponge is ideal for rapidly developing high-performance web services, API endpoints, and microservices, especially when quick delivery and low-code development are priorities. The learning curve for Sponge is relatively low, but its community and ecosystem are not as mature as Spring's.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How to Choose:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Choose Spring if:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  You need to build large, complex, enterprise-grade Java applications.&lt;/li&gt;
&lt;li&gt;  Your team has extensive experience with Java and Spring.&lt;/li&gt;
&lt;li&gt;  You require high maturity, stability, and strong community support.&lt;/li&gt;
&lt;li&gt;  Application performance bottlenecks are primarily in business logic or database layers rather than the framework itself.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Choose Sponge if:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  You need to rapidly develop high-performance Go web services, RESTFul APIs, or microservices.&lt;/li&gt;
&lt;li&gt;  You prioritize development efficiency and low-code development.&lt;/li&gt;
&lt;li&gt;  Your team has solid Go development experience or wants to explore a new Go framework.&lt;/li&gt;
&lt;li&gt;  Fast startup time and low resource consumption are critical.&lt;/li&gt;
&lt;li&gt;  Suitable for small to large backend services with rapid iteration and scalability needs.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;With this comparison and selection guide, developers can choose the most suitable framework based on their project requirements and team technology stack, ensuring successful and efficient development.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>microservices</category>
      <category>go</category>
      <category>java</category>
    </item>
  </channel>
</rss>
