<?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: Alireza Feizi</title>
    <description>The latest articles on DEV Community by Alireza Feizi (@alireza_feizi_2aa9c86cac4).</description>
    <link>https://dev.to/alireza_feizi_2aa9c86cac4</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%2F3646197%2Fa38ba784-1a7d-449c-8838-5ad3a98b0031.jpg</url>
      <title>DEV Community: Alireza Feizi</title>
      <link>https://dev.to/alireza_feizi_2aa9c86cac4</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/alireza_feizi_2aa9c86cac4"/>
    <language>en</language>
    <item>
      <title>Code-Level Monolith: The Hybrid Architecture &amp; The Art of "Flexible Deployment"</title>
      <dc:creator>Alireza Feizi</dc:creator>
      <pubDate>Thu, 04 Dec 2025 14:23:16 +0000</pubDate>
      <link>https://dev.to/alireza_feizi_2aa9c86cac4/code-level-monolith-the-hybrid-architecture-the-art-of-flexible-deployment-2jm2</link>
      <guid>https://dev.to/alireza_feizi_2aa9c86cac4/code-level-monolith-the-hybrid-architecture-the-art-of-flexible-deployment-2jm2</guid>
      <description>&lt;h3&gt;
  
  
  1. The Illusion of Choice and the End of False Dichotomies
&lt;/h3&gt;

&lt;p&gt;Over the past decade, the software development industry has witnessed radical swings in architectural paradigms; a rapid, sometimes impulsive movement from Monolithic systems to Microservices, and more recently, a reflective return toward modern, structured monolithic architectures.&lt;/p&gt;

&lt;p&gt;For years, software engineers have faced a false dichotomy: either choose the &lt;strong&gt;"simplicity and development speed"&lt;/strong&gt; of a Monolith and accept the risk of it turning into a &lt;strong&gt;"Big Ball of Mud,"&lt;/strong&gt; or submit to the back-breaking complexity of Microservices (network management, distributed consistency, and orchestration) to achieve &lt;strong&gt;"scalability."&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;But is there a third way?&lt;/p&gt;

&lt;p&gt;This article provides a deep anatomical analysis of the &lt;strong&gt;"Code-Level Monolith"&lt;/strong&gt; (or Modulith) architecture. This architecture is an engineered attempt to achieve the "Holy Grail" of software engineering: combining the modular independence of microservices with the operational simplicity and performance of monolithic systems.&lt;/p&gt;

&lt;p&gt;In this approach, we face a paradigm shift:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"Modularity is a logical concept, not a physical one."&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In this article, we will demonstrate how to design a system that is completely modular and isolated during development (like microservices) but can be executed as a single binary (All-in-One) or a set of distributed services at deployment time, depending on your needs. This capability of &lt;strong&gt;"frictionless switching"&lt;/strong&gt; is exactly the missing link that engineering teams need to escape "premature complexity."&lt;/p&gt;




&lt;h3&gt;
  
  
  2. A Return to Reason: Why Tech Giants Shifted Gears
&lt;/h3&gt;

&lt;p&gt;Leading companies like &lt;strong&gt;Amazon Prime Video&lt;/strong&gt; (which reduced costs by 90% by returning to a monolith), &lt;strong&gt;Shopify&lt;/strong&gt;, &lt;strong&gt;Google&lt;/strong&gt;, and &lt;strong&gt;Segment&lt;/strong&gt; have all redefined their strategies in favor of modular monoliths, driven by technical reasons and economic pressures. This return is not out of nostalgia for the past, but a pragmatic response to unmanageable complexity.&lt;/p&gt;

&lt;p&gt;To understand why the &lt;strong&gt;Code-Level Monolith&lt;/strong&gt; is emerging as a winning architecture today, we must review the turbulent evolution of software architecture.&lt;/p&gt;

&lt;h4&gt;
  
  
  2.1. The Era of Traditional Monoliths and the Curse of the "Big Ball of Mud"
&lt;/h4&gt;

&lt;p&gt;The history of modern software development began with monolithic systems. In this classic architecture, all system components—UI, Business Logic, and Data Access—resided in a single Codebase and were deployed as a single Executable unit.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The Deceptive Advantage:&lt;/strong&gt; Simplicity. Developers wrote code quickly, applied changes, and deployment ended with simply copying a file to the server.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Fall:&lt;/strong&gt; As systems grew and complexity increased, this architecture often morphed into the famous &lt;strong&gt;"Big Ball of Mud"&lt;/strong&gt; anti-pattern. In this state:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Blurred Boundaries:&lt;/strong&gt; Lines between different modules vanished, and classes became &lt;strong&gt;Tightly Coupled&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Destructive Butterfly Effect:&lt;/strong&gt; A small change in tax calculation logic could lead to unpredictable errors in inventory management.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fragility:&lt;/strong&gt; "Fear of Change" slowed down development and degraded software quality.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h4&gt;
  
  
  2.2. The Microservices Mirage: Promises and Hidden Costs
&lt;/h4&gt;

&lt;p&gt;In response to the dead-end of traditional monoliths, and inspired by companies like &lt;strong&gt;Netflix&lt;/strong&gt; and &lt;strong&gt;Uber&lt;/strong&gt; facing planetary-scale scalability challenges, Microservices emerged as the savior.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The Core Idea:&lt;/strong&gt; Breaking the "Big Ball" into small, independent services, each responsible for a specific Business Capability and communicating over a network.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Golden Promises:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Team Independence:&lt;/strong&gt; Each team can work with their preferred technology and speed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Granular Scaling:&lt;/strong&gt; Allocating more resources only to high-consumption services (e.g., the Search service).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fault Isolation:&lt;/strong&gt; A crash in the payment service doesn't necessarily bring down the whole site.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;The Bitter Reality:&lt;/strong&gt; Over time, many organizations faced a painful truth: &lt;strong&gt;"You are not Netflix!"&lt;/strong&gt;
Microservices didn't eliminate complexity; according to the "Conservation of Complexity" law, they merely shifted it from the &lt;strong&gt;Code level (Logic)&lt;/strong&gt; to the &lt;strong&gt;Infrastructure &amp;amp; Ops level&lt;/strong&gt;. New challenges included:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Network Latency:&lt;/strong&gt; Replacing fast in-memory calls with slow HTTP/gRPC requests.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Debugging Nightmare:&lt;/strong&gt; Tracing a bug across 10 different services.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Distributed Transactions:&lt;/strong&gt; Needing complex patterns like Sagas to maintain data integrity.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Overhead Costs:&lt;/strong&gt; Needing specialized DevOps teams just to keep the lights on.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h4&gt;
  
  
  2.3. The Rise of Code-Level Monolith: The Golden Balance (2020 - 2025)
&lt;/h4&gt;

&lt;p&gt;In recent years, a new approach known as &lt;strong&gt;"Modular Monolith"&lt;/strong&gt; or &lt;strong&gt;Code-Level Monolith&lt;/strong&gt; has gained popularity. This architecture attempts to reconcile "development simplicity" with "architectural order."&lt;/p&gt;

&lt;p&gt;In this paradigm:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Physical Monolith:&lt;/strong&gt; The system is still built and deployed as a &lt;strong&gt;Single Unit&lt;/strong&gt; (like the &lt;strong&gt;Quick Connect&lt;/strong&gt; project in &lt;code&gt;all-in-one&lt;/code&gt; mode).&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Logical Modularity:&lt;/strong&gt; All code is usually kept in a &lt;strong&gt;Monorepo&lt;/strong&gt;, but at the code level, modules are strictly isolated, and &lt;strong&gt;Strict Boundaries&lt;/strong&gt; are enforced by the compiler or linting tools.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;The Fundamental Difference:&lt;/strong&gt;&lt;br&gt;
Communication between modules (e.g., between the Order module and User module) happens via &lt;strong&gt;Function Calls&lt;/strong&gt; in memory, not over the network. This means &lt;strong&gt;Zero Latency&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This architecture rests on a key principle:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"You can have a fully modular system that runs in a single process (Code-Level Monolith), and conversely, you can have a system of microservices that are tightly coupled and dependent (Distributed Monolith)."&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h3&gt;
  
  
  3. Theoretical Foundations: Anatomy of a "Modular Monolith"
&lt;/h3&gt;

&lt;p&gt;To successfully implement a Code-Level Monolith, simply "dumping all files into one folder" is not enough. This architecture requires high engineering discipline, which we summarize in three fundamental principles: &lt;strong&gt;Strict Boundaries&lt;/strong&gt;, &lt;strong&gt;Location Transparency&lt;/strong&gt;, and &lt;strong&gt;Isolated Data Strategy&lt;/strong&gt;.&lt;/p&gt;
&lt;h4&gt;
  
  
  3.1. Strict Boundaries: The Firewall Between Modules
&lt;/h4&gt;

&lt;p&gt;In a Monorepo, your biggest enemy is "Abstraction Leak." If a developer can freely use any class inside another class, you will very quickly end up with "Spaghetti Code."&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Compile-Time Enforcement:&lt;/strong&gt; In &lt;strong&gt;Go&lt;/strong&gt;, the &lt;code&gt;internal&lt;/code&gt; packages mechanism is designed exactly for this purpose. Code inside an &lt;code&gt;internal&lt;/code&gt; folder is only accessible by its parent package; other modules cannot &lt;code&gt;import&lt;/code&gt; it. This turns "Encapsulation" from an ethical recommendation into a compiler constraint. &lt;em&gt;(In ecosystems like Python/Django or Java/Spring, this is done using Linting Tools or separate Maven/Gradle modules).&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Alignment with DDD:&lt;/strong&gt; Each module in this architecture corresponds to a &lt;strong&gt;Bounded Context&lt;/strong&gt; in Domain-Driven Design (DDD). The &lt;code&gt;Chat&lt;/code&gt; module should not directly see the &lt;code&gt;User&lt;/code&gt; database model; it should only speak to the "Public API" or "Contract" of the &lt;code&gt;Manager&lt;/code&gt; module.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;
  
  
  3.2. Data Strategy: Physical Sharing, Logical Separation
&lt;/h4&gt;

&lt;p&gt;The Achilles' heel of most architectural migrations is the database layer. In Code-Level Monolith, the golden rule is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"The Database is shared, but the Schema is private."&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No Foreign Keys:&lt;/strong&gt; There should be no Foreign Keys between tables of different modules (e.g., &lt;code&gt;orders&lt;/code&gt; and &lt;code&gt;users&lt;/code&gt;). While this makes Referential Integrity harder to guarantee, it is vital for preserving module independence.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Indirect Access:&lt;/strong&gt; No module has the right to directly &lt;code&gt;SELECT&lt;/code&gt; or &lt;code&gt;JOIN&lt;/code&gt; on another module's tables. If the &lt;code&gt;Chat&lt;/code&gt; module needs to know the user's name, it shouldn't read the &lt;code&gt;users&lt;/code&gt; table; instead, it must call the &lt;code&gt;GetUserProfile&lt;/code&gt; method from the &lt;code&gt;Manager&lt;/code&gt; module. This ensures that if the &lt;code&gt;Manager&lt;/code&gt; database structure changes one day, the &lt;code&gt;Chat&lt;/code&gt; code won't break.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;
  
  
  3.3. Location Transparency Principle
&lt;/h4&gt;

&lt;p&gt;This is the beating heart of the "Modular Monolith" architecture. Your business logic code &lt;strong&gt;should not know&lt;/strong&gt; if the service it calls is running in the same process (In-Memory) or on another server (Over Network).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Dependency Inversion:&lt;/strong&gt; Instead of the &lt;code&gt;Order&lt;/code&gt; service depending on the &lt;code&gt;User&lt;/code&gt; service, it should depend on an &lt;strong&gt;Interface&lt;/strong&gt; that it defines itself.

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Wrong:&lt;/em&gt; &lt;code&gt;import "myapp/user/service"&lt;/code&gt; and using &lt;code&gt;UserService&lt;/code&gt; directly.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Right:&lt;/em&gt; Defining &lt;code&gt;type UserProvider interface&lt;/code&gt; inside the &lt;code&gt;Order&lt;/code&gt; module.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Runtime Binding:&lt;/strong&gt; It is the job of the &lt;code&gt;main.go&lt;/code&gt; file (or Composition Root) to decide what implementation to inject into this interface:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;All-in-One Mode:&lt;/strong&gt; Inject the service object directly (In-Memory Adapter) -&amp;gt; Call speed: Nanoseconds.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Microservice Mode:&lt;/strong&gt; Inject a gRPC Client Wrapper (Network Adapter) -&amp;gt; Call speed: Milliseconds.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;
  
  
  3.4. The Grafana Pattern: The Art of Poly-Deployment
&lt;/h4&gt;

&lt;p&gt;The &lt;strong&gt;Grafana Loki&lt;/strong&gt; project (log aggregation system) is the best industrial example of this architecture. Loki's source code includes various components like &lt;code&gt;Ingester&lt;/code&gt;, &lt;code&gt;Distributor&lt;/code&gt;, and &lt;code&gt;Querier&lt;/code&gt;, all compiled into a single binary.&lt;/p&gt;

&lt;p&gt;The magic happens at runtime:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Run with flag &lt;code&gt;./loki -target=all&lt;/code&gt;: All components spin up in one process and talk via Function Calls (suitable for local development or light workloads).&lt;/li&gt;
&lt;li&gt;Run with flag &lt;code&gt;./loki -target=ingester&lt;/code&gt;: The binary acts only as an Ingester, and other codes are turned off (suitable for scalable environments needing 50 Ingester nodes).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This pattern allows the engineering team to change the &lt;strong&gt;Deployment Architecture&lt;/strong&gt; without changing a single line of &lt;strong&gt;Business Logic&lt;/strong&gt;.&lt;/p&gt;


&lt;h3&gt;
  
  
  4. Anatomy of &lt;a href="https://github.com/syntaxfa/quick-connect" rel="noopener noreferrer"&gt;Quick Connect&lt;/a&gt;: Theory in Practice
&lt;/h3&gt;

&lt;p&gt;In this section, we go straight into the "operating room." The open-source project &lt;strong&gt;Quick Connect&lt;/strong&gt; was designed as a laboratory to implement the Code-Level Monolith pattern in Go. Let's see how these theories translate into code.&lt;/p&gt;
&lt;h4&gt;
  
  
  4.1. Project Structure: Order in Chaos
&lt;/h4&gt;

&lt;p&gt;The repository for this project is a &lt;strong&gt;Monorepo&lt;/strong&gt;, but not a messy, free-for-all one. The directory structure is designed to scream "Service Independence":&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;app/&lt;/code&gt; (Service Domain):&lt;/strong&gt; All main services (like &lt;code&gt;chatapp&lt;/code&gt;, &lt;code&gt;managerapp&lt;/code&gt;, and &lt;code&gt;notificationapp&lt;/code&gt;) live in this directory. The vital point is that each service has a completely isolated database and repository. No service has the right to peek into another service's &lt;code&gt;repository&lt;/code&gt; directory.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;pkg/&lt;/code&gt; (Shared Code):&lt;/strong&gt; Since all code is in one repository, general utilities (like Logger, Error Handling, and Auth tools) are placed here to prevent rewriting.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;cmd/&lt;/code&gt; (Entry Point):&lt;/strong&gt; This is where we decide &lt;em&gt;how&lt;/em&gt; the application runs (Microservice or Monolith).&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;
  
  
  4.2. The Art of Defining Interfaces: The Consumer Law
&lt;/h4&gt;

&lt;p&gt;In Quick Connect, direct communication is forbidden. If the &lt;code&gt;chatapp&lt;/code&gt; service needs user information to display the sender's name, it must not depend on the &lt;code&gt;managerapp&lt;/code&gt; service.&lt;/p&gt;

&lt;p&gt;The solution is &lt;strong&gt;Dependency Inversion&lt;/strong&gt;. The chat service defines an interface that says: &lt;em&gt;"I need someone who gives me the user's name given an ID."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Golden Rule:&lt;/strong&gt; The interface must be defined at the &lt;strong&gt;Consumer&lt;/strong&gt; side, not the &lt;strong&gt;Provider&lt;/strong&gt; side.&lt;/p&gt;
&lt;h4&gt;
  
  
  4.3. The Adapter Pattern: The Bridge
&lt;/h4&gt;

&lt;p&gt;This is where the real magic happens. For every external dependency (like the User service), we write two different implementations (Adapters). The decision of which one to use is deferred to &lt;strong&gt;Runtime&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A) Network Adapter (gRPC Adapter):&lt;/strong&gt;&lt;br&gt;
When the system runs as a Microservice, this adapter serializes the request and sends it over the network:&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;manager&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;"context"&lt;/span&gt;
    &lt;span class="s"&gt;"github.com/syntaxfa/quick-connect/protobuf/manager/golang/userinternalpb"&lt;/span&gt;
    &lt;span class="s"&gt;"google.golang.org/grpc"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;// UserInternalAdapter acts as a client adapter via gRPC network call.&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;UserInternalAdapter&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;client&lt;/span&gt; &lt;span class="n"&gt;userinternalpb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UserInternalServiceClient&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;NewUserInternalAdapter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt; &lt;span class="n"&gt;grpc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ClientConnInterface&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;UserInternalAdapter&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;UserInternalAdapter&lt;/span&gt;&lt;span class="p"&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;userinternalpb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewUserInternalServiceClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ui&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;UserInternalAdapter&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;UserInfo&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;userinternalpb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UserInfoRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;opts&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="n"&gt;grpc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CallOption&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;userinternalpb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UserInfoResponse&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;// Sends request over the network&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ui&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;UserInfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;opts&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;B) Local Adapter (In-Memory Adapter):&lt;/strong&gt;&lt;br&gt;
When the system runs as a Code-Level Monolith, this adapter directly calls the other service's method in memory (RAM). There is no network and no latency involved:&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;manager&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;"context"&lt;/span&gt;
    &lt;span class="s"&gt;"github.com/syntaxfa/quick-connect/app/managerapp/service/userservice"&lt;/span&gt;
    &lt;span class="s"&gt;"github.com/syntaxfa/quick-connect/protobuf/manager/golang/userinternalpb"&lt;/span&gt;
    &lt;span class="s"&gt;"github.com/syntaxfa/quick-connect/types"&lt;/span&gt;
    &lt;span class="s"&gt;"google.golang.org/grpc"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;// UserInternalLocalAdapter acts as a client local adapter with func calls.&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;UserInternalLocalAdapter&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;userSvc&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;Service&lt;/span&gt; &lt;span class="c"&gt;// Direct reference to the service struct&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;NewUserInternalLocalAdapter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userSvc&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;Service&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;UserInternalLocalAdapter&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;UserInternalLocalAdapter&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="n"&gt;userSvc&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;userSvc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;uil&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;UserInternalLocalAdapter&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;UserInfo&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;userinternalpb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UserInfoRequest&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;grpc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CallOption&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;userinternalpb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UserInfoResponse&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;// Direct Function Call (No Network)&lt;/span&gt;
    &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sErr&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;uil&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;userSvc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UserInfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;types&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="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetUserId&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;sErr&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sErr&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// Convert Domain Entity back to Protobuf to satisfy the contract&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;convertUserInfoToPB&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resp&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;p&gt;&lt;strong&gt;A Smart Architectural Decision: Protobuf as the Single Contract&lt;/strong&gt;&lt;br&gt;
There is a subtle point in the code above: the input and output of &lt;em&gt;both&lt;/em&gt; adapters are &lt;strong&gt;Protobuf&lt;/strong&gt;.&lt;br&gt;
In Quick Connect, we accepted that Protobuf plays the role of the final &lt;strong&gt;Contract&lt;/strong&gt;. Even in local mode, domain data (&lt;code&gt;types.ID&lt;/code&gt;) is converted to Protobuf format. This makes switching between local and network modes completely transparent, requiring no changes to the calling service layer.&lt;/p&gt;
&lt;h4&gt;
  
  
  4.4. The Climax: The All-in-One Binary
&lt;/h4&gt;

&lt;p&gt;All these puzzle pieces come together in the &lt;code&gt;cmd/all-in-one/main.go&lt;/code&gt; file.&lt;br&gt;
This file plays the role of the &lt;strong&gt;Composition Root&lt;/strong&gt;. Here:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; All services (&lt;code&gt;Chat&lt;/code&gt;, &lt;code&gt;Manager&lt;/code&gt;, &lt;code&gt;Notification&lt;/code&gt;) are instantiated in memory.&lt;/li&gt;
&lt;li&gt; Instead of injecting gRPC clients into services, &lt;code&gt;LocalAdapters&lt;/code&gt; are created and passed to them.&lt;/li&gt;
&lt;li&gt; The final result is a single executable file that possesses all system capabilities, but communication between components happens at &lt;code&gt;Function Call&lt;/code&gt; speed.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;
  
  
  4.5. Why Did Quick Connect Choose This Path?
&lt;/h4&gt;

&lt;p&gt;The answer is summed up in one word: &lt;strong&gt;Realism&lt;/strong&gt;.&lt;br&gt;
More than 90% of software projects never reach massive scale. Starting a project with 10 microservices, 5 databases, and Kubernetes clusters only results in wasted resources and futile complexity.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;Quick Connect&lt;/strong&gt; architecture allows you to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Today:&lt;/strong&gt; Develop and deploy the product with the simplicity of an &lt;code&gt;all-in-one&lt;/code&gt; (Easy Deployment).&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Tomorrow:&lt;/strong&gt; If a part of the system (e.g., Chat) comes under heavy traffic, you can separate it into an independent microservice just by changing the &lt;code&gt;main&lt;/code&gt; file (Scalability without Rewrite).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This means Deployment Architecture is decoupled from Code Architecture; and this is the freedom of action every software engineer dreams of.&lt;/p&gt;


&lt;h3&gt;
  
  
  5. Returning Speed and Simplicity
&lt;/h3&gt;

&lt;p&gt;Perhaps the biggest victim of Microservice architecture is &lt;strong&gt;Developer Experience (DX)&lt;/strong&gt;. In a typical microservice setup, to test a simple feature, a programmer has to spin up 10 Docker containers, manage ports, and fight with their system's 32GB RAM usage.&lt;/p&gt;

&lt;p&gt;But in &lt;strong&gt;Quick Connect&lt;/strong&gt;, the story is different.&lt;/p&gt;
&lt;h4&gt;
  
  
  5.1. The End of &lt;code&gt;Localhost&lt;/code&gt; Hell
&lt;/h4&gt;

&lt;p&gt;In the Code-Level Monolith architecture, your development environment isn't exactly like your production environment; and that is &lt;strong&gt;Good&lt;/strong&gt;!&lt;br&gt;
For a developer working on the &lt;code&gt;Chat&lt;/code&gt; service, it doesn't matter if the &lt;code&gt;Auth&lt;/code&gt; service is running in a separate Kubernetes pod or not. They just want their code to work.&lt;/p&gt;

&lt;p&gt;In this project, the whole system comes up with a simple command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go run cmd/all-in-one/main.go
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This magic command runs all services (&lt;code&gt;Manager&lt;/code&gt;, &lt;code&gt;Chat&lt;/code&gt;, &lt;code&gt;Notification&lt;/code&gt;) in a single process.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Resource Usage:&lt;/strong&gt; Less than 100MB of RAM (compared to gigabytes for microservices).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hot Reload:&lt;/strong&gt; Code changes and server restarts take less than 1 second.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Debugging:&lt;/strong&gt; Placing a breakpoint in the &lt;code&gt;Chat&lt;/code&gt; service and stepping into the &lt;code&gt;Manager&lt;/code&gt; service code is possible without any &lt;strong&gt;Remote Debugging&lt;/strong&gt; complexity.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  5.2. Integration Tests: Fast, Stable, Cheap
&lt;/h4&gt;

&lt;p&gt;End-to-End tests in the microservices world are often slow and flaky because they depend on the network and all services being up.&lt;br&gt;
In the Quick Connect approach, we can run integration tests &lt;strong&gt;in memory&lt;/strong&gt;.&lt;br&gt;
Since modules are connected via interfaces and &lt;code&gt;LocalAdapter&lt;/code&gt;s, we can write a scenario where:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; A user registers in &lt;code&gt;Manager&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt; Sends a message in &lt;code&gt;Chat&lt;/code&gt; with the same token.&lt;/li&gt;
&lt;li&gt; Receives a notification in &lt;code&gt;Notification&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;All of this happens in a fraction of a second without a single byte crossing the network card. This means fast feedback for the developer and CI Pipelines that pass in 2 minutes instead of 20.&lt;/p&gt;

&lt;h4&gt;
  
  
  5.3. Eliminating "Latency" in Chatty Modules
&lt;/h4&gt;

&lt;p&gt;In chat systems, some services are inherently "chatty." For example, the WebSocket service might need to request the &lt;code&gt;manager&lt;/code&gt; service for every incoming message.&lt;br&gt;
If these requests require a gRPC call (2ms) and you have 10,000 messages per second, the network overhead will choke the system.&lt;br&gt;
In &lt;code&gt;All-in-One&lt;/code&gt; mode, this check becomes a &lt;strong&gt;Function Call&lt;/strong&gt; taking nanoseconds. This means we have multiplied performance without any complex optimization.&lt;/p&gt;




&lt;h3&gt;
  
  
  6. The Future of Architecture
&lt;/h3&gt;

&lt;p&gt;What we did manually (Explicitly) in Quick Connect—defining interfaces and writing two adapter versions (Local vs. Remote)—is a demonstration of the future where software engineering is heading.&lt;/p&gt;

&lt;h4&gt;
  
  
  6.1. The Rise of Poly-Deployment Frameworks (Google Service Weaver)
&lt;/h4&gt;

&lt;p&gt;Google recently introduced a framework called &lt;strong&gt;Service Weaver&lt;/strong&gt; for Go that follows this exact philosophy, but with a difference: &lt;strong&gt;"Magical Automation."&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In Quick Connect, we decide ourselves whether to use &lt;code&gt;UserLocalAdapter&lt;/code&gt; or &lt;code&gt;UserGrpcAdapter&lt;/code&gt;. But in Service Weaver:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; You write code as if everything is a Monolith.&lt;/li&gt;
&lt;li&gt; Components are defined with standard Go interfaces.&lt;/li&gt;
&lt;li&gt; At &lt;strong&gt;Deploy time&lt;/strong&gt;, you tell the system via a simple config file (&lt;code&gt;weaver.toml&lt;/code&gt;): &lt;em&gt;"Separate this component and that component and run them on different servers."&lt;/em&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The Service Weaver framework scans the code, and if it detects two components are in the same process, it uses Function Calls (with zero serialization); if they are separate, it generates and runs the gRPC and Protobuf code itself.&lt;/p&gt;

&lt;p&gt;This implies:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"Complete separation of Logical Architecture from Physical Architecture."&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  7. Final Recommendation: The Winning Strategy for 99% of Projects
&lt;/h3&gt;

&lt;p&gt;And finally, what I want to say is this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"Start with Monolith, but code as if it were Microservices."&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The history of software engineering is a graveyard full of startups buried under the complexity of managing 50 microservices before reaching their first 1000 users. And also companies choked by the "Big Ball of Mud."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Our Proposed Roadmap (Based on Quick Connect experience):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Day 1 (Project Start):&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Create a &lt;strong&gt;Monorepo&lt;/strong&gt; structure.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;internal&lt;/code&gt; folders in Go to lock down boundaries (which, essentially, we didn't use directly in this project, but strict discipline was applied :)).&lt;/li&gt;
&lt;li&gt;Establish communication between modules &lt;strong&gt;only and exclusively&lt;/strong&gt; through Interfaces.&lt;/li&gt;
&lt;li&gt;Deploy the system as &lt;strong&gt;All-in-One&lt;/strong&gt; (like &lt;code&gt;cmd/all-in-one/main.go&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Day 100 (Traffic Growth):&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Since your code is isolated, you have no technical debt.&lt;/li&gt;
&lt;li&gt;Continue deploying on a stronger server (&lt;strong&gt;Vertical Scaling&lt;/strong&gt;). (The cost of a strong server is cheaper than the cost of a DevOps team).&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Day 1000 (Massive Scalability):&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;The profiler (&lt;code&gt;pprof&lt;/code&gt;) shows that the &lt;code&gt;Chat&lt;/code&gt; module has become a bottleneck.&lt;/li&gt;
&lt;li&gt;You write a separate &lt;code&gt;main.go&lt;/code&gt; just for the &lt;code&gt;Chat&lt;/code&gt; module (like &lt;code&gt;cmd/chat/main.go&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;You replace the Local Adapter with the gRPC Adapter.&lt;/li&gt;
&lt;li&gt;Now you have a microservice system, exactly where you needed it and exactly when you needed it.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Code-Level Monolith&lt;/strong&gt; is not a regression; it is engineering maturity. This architecture allows you to have the &lt;strong&gt;speed&lt;/strong&gt; of a startup and the &lt;strong&gt;order&lt;/strong&gt; of an enterprise simultaneously.&lt;/p&gt;

&lt;p&gt;If you enjoyed this article, I would appreciate your support for Quick Connect by starring the repo and sharing it with others:&lt;br&gt;
&lt;a href="https://github.com/syntaxfa/quick-connect" rel="noopener noreferrer"&gt;https://github.com/syntaxfa/quick-connect&lt;/a&gt;&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>microservices</category>
      <category>systemdesign</category>
    </item>
  </channel>
</rss>
