<?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: ynwd</title>
    <description>The latest articles on DEV Community by ynwd (@ynwd).</description>
    <link>https://dev.to/ynwd</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F421184%2F9535087e-87df-4055-88cc-950c1dedf2e1.png</url>
      <title>DEV Community: ynwd</title>
      <link>https://dev.to/ynwd</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ynwd"/>
    <language>en</language>
    <item>
      <title>Horizontal Scaling: Solving One Problem, Creating Another</title>
      <dc:creator>ynwd</dc:creator>
      <pubDate>Wed, 12 Aug 2026 02:18:05 +0000</pubDate>
      <link>https://dev.to/ynwd/horizontal-scaling-solving-one-problem-creating-another-46n6</link>
      <guid>https://dev.to/ynwd/horizontal-scaling-solving-one-problem-creating-another-46n6</guid>
      <description>&lt;p&gt;When learning system design, we are almost always fed the exact same doctrine: start with one API + one Database, then as traffic increases, add a Load Balancer, Redis, a Separate Database Server, and eventually Read Replicas.&lt;/p&gt;

&lt;p&gt;The problem is that this standard pattern is built on a single assumption: &lt;strong&gt;every user must crowd into the same shared database.&lt;/strong&gt; However, if your application's data characteristics allow it to be segregated per user from day one, blindly following this pattern becomes a &lt;strong&gt;complexity trap&lt;/strong&gt; that makes your system increasingly fragile.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Sin of Mainstream Architecture: Compounding New Problems
&lt;/h2&gt;

&lt;p&gt;In conventional architecture, all users share the same database tables. As server load increases, a developer's first reflex is usually to add more infrastructure layers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[User] 
  └─► [Load Balancer]
        ├─► [API Instance 1] ──┐
        │                      ├─► [Redis Cache]
        └─► [API Instance 2] ──┴─► [DB Server (Postgres)]

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While the initial intent is to solve scaling challenges, the execution creates a dramatic contradiction:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Seeking Fault Tolerance, but Adding a Single Point of Failure
&lt;/h3&gt;

&lt;p&gt;To distribute traffic, we introduce a Load Balancer and spin up additional API instances. However, because user requests now bounce between instances, their session state is lost.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Solution?&lt;/strong&gt;&lt;br&gt;
We are forced to introduce Redis for centralized session storage.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Absurd Result:&lt;/strong&gt; We added a Load Balancer to make the system fault-tolerant, but now, if Redis crashes, the entire application goes down.&lt;/p&gt;
&lt;h3&gt;
  
  
  2. Seeking Easy Scaling, but Paying with Complex Bugs
&lt;/h3&gt;

&lt;p&gt;In theory, spinning up another API server is just a click of a button. However, once a single business transaction touches multiple servers simultaneously, standard database transactions (&lt;code&gt;BEGIN...COMMIT&lt;/code&gt;) no longer work.&lt;/p&gt;

&lt;p&gt;We are forced to implement complex patterns like Two-Phase Commit or the Saga Pattern. We chose horizontal scaling in pursuit of simplicity, but ended up trapped in race conditions and data inconsistency issues that are notoriously hard to debug in production.&lt;/p&gt;


&lt;h2&gt;
  
  
  A Radical Solution: The File-per-User Architecture
&lt;/h2&gt;

&lt;p&gt;Instead of forcing all data into one giant database, this approach offers a remarkably simple concept: &lt;strong&gt;give every user their own separate SQLite file.&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;/data
  ├── user_01.db
  ├── user_02.db
  └── global_index.db  &amp;lt;-- For public metadata/aggregates only

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So, what happens when the application needs public features like a feed, global search, or cross-user data aggregation?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Answer:&lt;/strong&gt; Separate the read path.&lt;/p&gt;

&lt;p&gt;Private source data remains safely stored in each user's individual file. Whenever a user publishes something, the application simply writes a lightweight metadata entry (&lt;em&gt;write-on-publish&lt;/em&gt;) to a dedicated aggregate database. If this aggregate database becomes corrupted, its data can easily be re-indexed from the users' primary files.&lt;/p&gt;

&lt;p&gt;By eliminating a separate database server and embedding the SQLite engine directly inside the application process, system mechanics shift naturally:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Data Leaks Become Structurally Impossible:&lt;/strong&gt; In a shared database, a single bug forgetting a &lt;code&gt;WHERE user_id = ?&lt;/code&gt; clause can leak data between users. In this approach, the application connection strictly opens the target user's file. The risk of data leakage is eliminated not by developer vigilance, but by physical file boundaries.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Radically Simple Backups:&lt;/strong&gt; You no longer need to execute gigabyte-sized database dumps or manage complex log replication pipelines. To back up a user's data, you simply stream or copy their single &lt;code&gt;.db&lt;/code&gt; file to Object Storage (e.g., using Litestream).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zero Network Latency:&lt;/strong&gt; Because the database engine runs inside the application process itself, every query is processed directly in memory and local disk. Network calls from the API server to the DB server—which typically consume milliseconds—vanish entirely.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The Rationality of Vertical Scaling: Why It Is More Than Enough
&lt;/h2&gt;

&lt;p&gt;A reasonable question arises: &lt;em&gt;"If the database lives as local files, how do we handle traffic spikes? We can't just slap a Load Balancer in front of it."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Answer:&lt;/strong&gt; Use &lt;strong&gt;Vertical Scaling&lt;/strong&gt; (scale up the machine's resources).&lt;/p&gt;

&lt;p&gt;In the modern cloud era, scaling CPU and RAM on a single server is often overlooked because it is deemed less fashionable than running dozens of small nodes. Yet, the logic behind vertical scaling is stronger than ever: a single modern machine can handle tens of thousands of requests per second &lt;strong&gt;provided&lt;/strong&gt; its performance isn't bogged down by database network latency and distributed state synchronization.&lt;/p&gt;

&lt;p&gt;The physical capacity of a single server today has reached almost absurd levels. On Google Cloud Platform (GCP), a standard Virtual Machine can offer up to &lt;strong&gt;224 vCPUs&lt;/strong&gt;. In Memory-Optimized categories (such as the M or X4 series), limits reach up to &lt;strong&gt;1,920 vCPUs&lt;/strong&gt; and a massive &lt;strong&gt;32 Terabytes (32,768 GB) of RAM&lt;/strong&gt; on a single machine. These specs prove that the physical ceiling of a single server far exceeds the compute needs of 99.9% of web applications on the market.&lt;/p&gt;

&lt;p&gt;Based on this reality, the architecture divides infrastructure responsibilities pragmatically:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Compute (CPU/RAM):&lt;/strong&gt; Scaled vertically. You leverage the capacity of a single machine to execute all application logic and embedded database operations in one place without network overhead.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Storage (Disk):&lt;/strong&gt; Scaled horizontally without limits. Storage capacity is not constrained by the machine itself; you can attach new block storage volumes (e.g., up to hundreds of Terabytes) instantly with zero downtime.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ultimately, instead of stressing over a complex architecture built for hypothetical hyper-scale traffic, you choose a simple, rational system: &lt;strong&gt;one application, one server, and zero network overhead.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  When to Use This Pattern?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Highly Recommended If:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Most user activity takes place within their own isolated data context (SaaS, E-commerce, Social Platforms, Productivity Tools).&lt;/li&gt;
&lt;li&gt;You prioritize operational simplicity and low maintenance overhead with a small engineering team.&lt;/li&gt;
&lt;li&gt;You want to ship and deploy applications rapidly without managing server clusters.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Avoid If:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Your application is dominated by ad-hoc, cross-user queries with unpredictable read patterns—making it difficult to structure a lightweight aggregate database.&lt;/li&gt;
&lt;li&gt;The total traffic and compute load of a single application has been empirically proven to exceed the physical limits of the largest single server available on the market.&lt;/li&gt;
&lt;/ul&gt;




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

&lt;p&gt;Load balancers, Redis, and separate database clusters are not badges of system maturity—more often than not, they are technical debt stemming from poor architectural choices made early on.&lt;/p&gt;

&lt;p&gt;If your user data can be isolated per file, stop bundling it into one giant shared database. Separate the data, offload global search to a lightweight aggregate index, drop the separate database server, and enjoy a system that is significantly faster, more stable, and easier to maintain.&lt;/p&gt;




&lt;h2&gt;
  
  
  Q&amp;amp;A: Addressing Operational and Security Concerns
&lt;/h2&gt;

&lt;h3&gt;
  
  
  "A single server is a Single Point of Failure (SPOF) &amp;amp; hard to Failover!"
&lt;/h3&gt;

&lt;p&gt;That mindset belongs to an era when SQLite was viewed merely as a passive local disk file. The modern SQLite ecosystem has solved this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;For Disaster Recovery (DR):&lt;/strong&gt; Use &lt;strong&gt;Litestream&lt;/strong&gt;. It performs byte-level streaming replication in real-time to Object Storage (S3/Cloudflare R2). If the primary server is completely destroyed, you can restore the latest state to a fresh server in minutes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;For Automatic Failover (High Availability):&lt;/strong&gt; Use &lt;strong&gt;LiteFS&lt;/strong&gt;. LiteFS creates a multi-node SQLite cluster where read requests are handled locally and write requests are automatically forwarded to the primary node. (To be intellectually honest: adopting LiteFS means re-introducing a degree of distributed system complexity that was initially avoided. However, this aligns with the core philosophy: add infrastructure complexity only when HA requirements are genuinely proven, not on day one).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  "How do you handle Zero-Downtime Deployments?"
&lt;/h3&gt;

&lt;p&gt;You do not need Kubernetes just to achieve zero-downtime deployments! There are two straightforward approaches:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;At the Server Level:&lt;/strong&gt; Use a reverse proxy like Caddy, Nginx, or Envoy to execute hot-reloads. Alternatively, leverage Linux's &lt;strong&gt;&lt;code&gt;systemd&lt;/code&gt; Socket Activation&lt;/strong&gt;—the OS buffers incoming requests for a few milliseconds at the kernel level while the application process switches over, resulting in zero dropped requests.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;At the Edge Level:&lt;/strong&gt; Utilize &lt;strong&gt;Cloudflare&lt;/strong&gt; (via Cloudflare Tunnel). You can re-route traffic to a new port or binary version via API, get free DDoS protection, and serve automatic maintenance pages if the server ever requires a full reboot.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  "Complexity is just shifted to the Application Layer!"
&lt;/h3&gt;

&lt;p&gt;That is actually a net positive!&lt;/p&gt;

&lt;p&gt;Application-layer complexity can be tested automatically using standard unit and integration tests on your local machine (&lt;code&gt;localhost&lt;/code&gt;). In contrast, distributed infrastructure complexity (such as split-brain scenarios in a DB cluster or subtle Redis race conditions) manifests as ghost bugs that are nearly impossible to reproduce locally and only surface when production breaks.&lt;/p&gt;

&lt;p&gt;Would you rather deal with complex test suites or be paged at 3 AM because production is down?&lt;/p&gt;

&lt;h3&gt;
  
  
  "What about Analytics / Data Warehouse Queries?"
&lt;/h3&gt;

&lt;p&gt;No one should run heavy analytical queries directly against production SQLite files. Even in conventional distributed architectures, best practices strictly dictate &lt;strong&gt;never&lt;/strong&gt; pointing OLAP/analytics queries at a production OLTP database.&lt;/p&gt;

&lt;p&gt;Because all &lt;code&gt;.db&lt;/code&gt; files are backed up automatically to S3 via Litestream, the Data team can point query engines like &lt;strong&gt;DuckDB&lt;/strong&gt; or &lt;strong&gt;ClickHouse&lt;/strong&gt; directly at those S3 snapshots. DuckDB can query thousands of SQLite files in parallel with exceptional speed, leaving the production database completely unburdened.&lt;/p&gt;

&lt;h3&gt;
  
  
  "Hard to pass Compliance Audits (GDPR/ISO) &amp;amp; handle Backups!"
&lt;/h3&gt;

&lt;p&gt;The File-per-User architecture actually simplifies data isolation and compliance governance:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Right to be Forgotten (GDPR Erasure):&lt;/strong&gt; In a shared database, deleting a user's data requires cascading &lt;code&gt;DELETE&lt;/code&gt; statements across dozens of tables, running the risk of table locks or orphaned records. In this approach, a user's private data is completely isolated. You simply delete their &lt;code&gt;user.db&lt;/code&gt; file and clear their entry in the aggregate database. &lt;em&gt;(Ensure you configure proper **Lifecycle / Retention Policies&lt;/em&gt;* on your Object Storage where Litestream streams backups, so historical copies are permanently purged according to regulatory windows).*&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data Portability:&lt;/strong&gt; If a user requests a full export of their personal data, you hand them a copy of their single &lt;code&gt;.db&lt;/code&gt; file—no complex export scripts required.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  "Career-Safety Principle (&lt;em&gt;Nobody gets fired for buying IBM&lt;/em&gt;)"
&lt;/h3&gt;

&lt;p&gt;This is the real underlying reason: &lt;strong&gt;Fear&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Many choose complex architectures not because the application requires it, but out of fear of blame if things break, or simply to polish their resume with industry buzzwords (&lt;em&gt;Resume-Driven Development&lt;/em&gt;).&lt;/p&gt;

&lt;p&gt;The mark of a mature Engineering Leader is having the courage to choose the simplest possible architecture that solves the business problem while incurring the lowest possible distributed infrastructure tax.&lt;/p&gt;

</description>
      <category>distributedsystems</category>
      <category>webdev</category>
      <category>modular</category>
      <category>monolith</category>
    </item>
    <item>
      <title>I Built a Web Framework That Only Works With AI</title>
      <dc:creator>ynwd</dc:creator>
      <pubDate>Fri, 17 Jul 2026 10:22:38 +0000</pubDate>
      <link>https://dev.to/ynwd/i-built-a-web-framework-that-only-works-with-ai-2meb</link>
      <guid>https://dev.to/ynwd/i-built-a-web-framework-that-only-works-with-ai-2meb</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Stop fixing boilerplate. Let AI do the boring parts — scaffold, code, review, ship.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Here's the problem nobody talks about: &lt;strong&gt;most AI coding assistants are wasted on repos that weren't designed for them.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You ask Copilot to "add a billing feature" and it generates files in the wrong places, imports from the wrong modules, or writes code that doesn't match your project's conventions. You spend more time fixing the AI's output than you would writing it yourself.&lt;/p&gt;

&lt;p&gt;I got tired of this. So I built something different.&lt;/p&gt;

&lt;h2&gt;
  
  
  Meet Flow
&lt;/h2&gt;

&lt;p&gt;Flow is a modular monolith (Go + React) where &lt;strong&gt;every convention exists for the AI, not for you&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;┌──────────────────────────────────────────────┐
│ "buat fitur billing" →                        │
│   @analyst asks 2 questions →                 │
│   you approve →                               │
│   AI scaffolds, codes &amp;amp; reviews →             │
│   you ship.                                   │
└──────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One command from zero to running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone &amp;lt;repo&amp;gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;flow
.github/skills/init-core-project/scripts/init-core.sh
go run &lt;span class="nb"&gt;.&lt;/span&gt;    &lt;span class="c"&gt;# → localhost:3000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Problem: Frameworks Were Built for Humans
&lt;/h2&gt;

&lt;p&gt;Traditional frameworks assume a person writes the code. The folder structure, the conventions, the design patterns — they all make sense to a human brain.&lt;/p&gt;

&lt;p&gt;But AI doesn't think like us. It hallucinates file paths. It imports from the wrong module. It guesses conventions instead of following them.&lt;/p&gt;

&lt;p&gt;Flow flips this: &lt;strong&gt;everything is designed so an AI can't get it wrong.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How It Works
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. One Feature = One Folder
&lt;/h3&gt;

&lt;p&gt;No more "where do I put the handler?" The AI can't scatter your code across the tree because &lt;strong&gt;both your Go backend and React frontend live in the same folder&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;modules/billing/
├── handler.go        # HTTP handlers
├── service.go        # Business logic
├── repository.go     # Data access
├── model.go          # Types
├── module.go         # Self-registration
├── billing.tsx       # React component
├── api.ts            # Fetch client
└── components/       # Local React components
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Self-Registration Pattern
&lt;/h3&gt;

&lt;p&gt;Modules register themselves via Go's &lt;code&gt;init()&lt;/code&gt; function. No manual wiring, no import management. The AI just needs to create the folder and the rest happens automatically.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Skills — Not Hallucinations
&lt;/h3&gt;

&lt;p&gt;Instead of letting the AI guess how to scaffold a module, I gave it &lt;strong&gt;battle-tested shell scripts&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;.github/skills/new-feature-module/scripts/scaffold.sh billing
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This creates a full CRUD module — Go backend, React frontend, tests, auto-registered — in one command. The AI doesn't guess. It executes.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Custom Agent Modes
&lt;/h3&gt;

&lt;p&gt;Flow ships with preset &lt;strong&gt;GitHub Copilot agent modes&lt;/strong&gt;:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Agent&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@implementer&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Has write access — implements features, fixes bugs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@reviewer&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Read-only — checks architecture and module boundaries&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@analyst&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Clarifies requirements and writes specs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@planner&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Produces user stories for large features&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Workflow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You → @analyst writes spec → You approve → @implementer codes → @reviewer checks → Ship
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  A Real Use Case: Building a Blog Feature
&lt;/h2&gt;

&lt;p&gt;Let's walk through what it looks like to build something real — a simple blog feature.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Init the project (once)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;.github/skills/init-core-project/scripts/init-core.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This creates the entire core structure — router, middlewares, templates, static files, Tailwind CSS — from templates. It runs &lt;code&gt;go mod tidy&lt;/code&gt;, &lt;code&gt;npm install&lt;/code&gt;, &lt;code&gt;npm run build:css&lt;/code&gt;, and &lt;code&gt;go build ./...&lt;/code&gt; automatically.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Scaffold the blog module
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;.github/skills/new-feature-module/scripts/scaffold.sh blog &lt;span class="nt"&gt;--ssr&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;--ssr&lt;/code&gt; flag enables server-side rendering (SEO-friendly). This creates:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;modules/blog/
├── handler.go         # Page + API handlers
├── service.go         # Blog logic
├── repository.go      # In-memory store
├── model.go           # Post struct
├── module.go          # Routes registration
├── router.go          # Route definitions
├── templates/         # HTML templates (SSR)
├── blog.tsx           # React component
├── api.ts             # Fetch client
├── package.json       # Frontend deps
├── esbuild.mjs        # Build config
└── handler_test.go, service_test.go, api.test.ts, blog.test.tsx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 3: Have the AI implement it
&lt;/h3&gt;

&lt;p&gt;In VS Code, open the Copilot chat and type:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@implementer implement the blog feature per the spec at .github/specs/blog.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;@implementer&lt;/code&gt; agent will:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Read the spec&lt;/li&gt;
&lt;li&gt;Fill in the handler, service, and repository with business logic&lt;/li&gt;
&lt;li&gt;Add tests&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;go build ./... &amp;amp;&amp;amp; go test ./...&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Build the frontend bundle&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Step 4: Review
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@reviewer review the blog module against spec
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;@reviewer&lt;/code&gt; agent reads the code, checks module boundaries, and reports any issues. If it finds problems, it calls &lt;code&gt;@implementer&lt;/code&gt; to fix them automatically.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 5: Ship
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run build &lt;span class="nt"&gt;-w&lt;/span&gt; modules/blog
go run &lt;span class="nb"&gt;.&lt;/span&gt;    &lt;span class="c"&gt;# → localhost:3000/blog&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What You Get Out of the Box
&lt;/h2&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;How&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Project init&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;init-core.sh&lt;/code&gt; — single command from clone to running&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Module scaffolding&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;scaffold.sh&lt;/code&gt; — full CRUD with Go + React + tests&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Code generation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;4 agent modes + 3 prompt templates&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Code review&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;@reviewer&lt;/code&gt; checks architecture automatically&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;State tracking&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;.core-state.json&lt;/code&gt; prevents overwriting existing files&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Styling&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Tailwind CSS v4, built via PostCSS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Database&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;In-memory (swap to SQLite/Postgres when ready)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Auth&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Bearer token middleware (extensible)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Why Devs Like It
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Took me 10 minutes to go from first commit to a working API. The AI did all the boring parts."&lt;/em&gt;&lt;br&gt;
&lt;em&gt;"Finally — a framework that doesn't fight me when I use Copilot."&lt;/em&gt;&lt;br&gt;
&lt;em&gt;"The scaffold script alone saves me 30 minutes per module."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Try It Yourself
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/ynwd/flow
&lt;span class="nb"&gt;cd &lt;/span&gt;flow
.github/skills/init-core-project/scripts/init-core.sh
go run &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then open VS Code, press &lt;code&gt;Cmd+I&lt;/code&gt;, and tell Copilot:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@implementer add a blog module with SSR
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It just works.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Flow is open source. Built with Go 1.24, React 18, TypeScript 5, Tailwind CSS v4, and a lot of coffee.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>go</category>
      <category>react</category>
      <category>typescript</category>
      <category>githubcopilot</category>
    </item>
    <item>
      <title>Making the Filing Cabinet Enterprise-Ready: Tricks to Scale with SQLite</title>
      <dc:creator>ynwd</dc:creator>
      <pubDate>Sun, 17 May 2026 02:34:55 +0000</pubDate>
      <link>https://dev.to/ynwd/making-the-filing-cabinet-enterprise-ready-tricks-to-scale-with-sqlite-2nm2</link>
      <guid>https://dev.to/ynwd/making-the-filing-cabinet-enterprise-ready-tricks-to-scale-with-sqlite-2nm2</guid>
      <description>&lt;p&gt;In my &lt;a href="https://dev.to/ynwd/the-secret-of-the-small-database-why-big-technology-often-slows-you-down-150"&gt;previous article&lt;/a&gt;, we talked about why big databases (like Postgres or MySQL) act like a remote, slow mega-warehouse. Meanwhile, SQLite acts like a fast filing cabinet right under your desk.&lt;/p&gt;

&lt;p&gt;But a common question arises: &lt;strong&gt;"Can a simple filing cabinet handle a serious, growing enterprise business?"&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The answer is &lt;strong&gt;yes&lt;/strong&gt;. You don't need a massive warehouse just because your business is growing. You just need to know how to organize your filing cabinet.&lt;/p&gt;

&lt;p&gt;Here are the simple, practical tricks to make SQLite ready for enterprise apps.&lt;/p&gt;




&lt;h3&gt;
  
  
  1. Turn on WAL Mode (The "Double Desk" Trick)
&lt;/h3&gt;

&lt;p&gt;By default, SQLite works like a cautious clerk: if someone is writing down a new file, nobody else can read the existing files until the writing is finished. This can cause a small delay.&lt;/p&gt;

&lt;p&gt;To fix this, you must turn on &lt;strong&gt;WAL (Write-Ahead Log) mode&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Think of WAL mode as having two desks.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Desk A (The Archive):&lt;/strong&gt; People can read files from here anytime without waiting.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Desk B (The Scratchpad):&lt;/strong&gt; New data is written here first in the background.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every once in a while, the system automatically moves data from Desk B to Desk A. With WAL mode, readers never block writers, and writers never block readers. It makes concurrency instant.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;How to do it:&lt;/strong&gt; Just run this simple command when your app connects to SQLite:&lt;br&gt;
&lt;code&gt;PRAGMA journal_mode=WAL;&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  2. Optimize the Speed (The "Hyper-Drive" Settings)
&lt;/h3&gt;

&lt;p&gt;To make your filing cabinet even faster, you can give SQLite a few extra instructions (called PRAGMAs) when your application starts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;PRAGMA synchronous = NORMAL;&lt;/code&gt;&lt;/strong&gt; Instead of stopping and checking the hard drive after every single letter is written, SQLite trusts the computer's memory cache. It is safe, and it makes writing data significantly faster.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;PRAGMA cache_size = -64000;&lt;/code&gt;&lt;/strong&gt; This tells SQLite to keep more data inside the RAM (around 64MB). Reading data from RAM is like instantly remembering a phone number instead of looking it up in a book.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;PRAGMA busy_timeout = 5000;&lt;/code&gt;&lt;/strong&gt; If two actions happen at the exact same fraction of a second, this tells the second action to wait patiently for up to 5 seconds instead of crashing with an error.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  3. The Multi-Tenant Strategy: One Tenant, One File
&lt;/h3&gt;

&lt;p&gt;In a big enterprise application, you usually have many customers (tenants). The old corporate way is to dump millions of rows from all customers into one giant database table. This makes queries slow and dangerous if data leaks between clients.&lt;/p&gt;

&lt;p&gt;The enterprise SQLite way is beautiful: &lt;strong&gt;Give every customer their own separate SQLite file.&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Safer:&lt;/strong&gt; Customer A can never accidentally see Customer B's data because they are literally in different files (&lt;code&gt;tenant_A.db&lt;/code&gt;, &lt;code&gt;tenant_B.db&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Faster:&lt;/strong&gt; Backing up data is as simple as copying a single file for that specific customer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Infinite Scaling:&lt;/strong&gt; You don't need a bigger server. If you get 10,000 new customers, you just create 10,000 small files. You can even distribute these files across cheap, simple servers.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  4. Automatic Backups to the Cloud
&lt;/h3&gt;

&lt;p&gt;People worry: &lt;em&gt;"What if the server crashes and I lose my SQLite file?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In an enterprise setup, you use a tool like &lt;strong&gt;Litestream&lt;/strong&gt; or &lt;strong&gt;LiteFS&lt;/strong&gt;. These are tiny, invisible background helpers designed for SQLite.&lt;/p&gt;

&lt;p&gt;Every time a user changes a single piece of data in your SQLite file, Litestream instantly streams that tiny change to secure, cheap cloud storage (like Amazon S3 or Google Cloud Storage). If your server burns down, you can restore your database up to the last millisecond.&lt;/p&gt;




&lt;h3&gt;
  
  
  5. Keep the Frontend as the Orchestrator
&lt;/h3&gt;

&lt;p&gt;To keep your backend fast and lightweight, let your frontend (the user interface) handle the complex user flows. The backend should focus on doing one thing perfectly: reading and writing data to the local SQLite file as quickly as possible.&lt;/p&gt;

&lt;p&gt;By keeping the business logic modular and letting the frontend drive the orchestration, your SQLite database stays clean, unburdened, and lightning-fast.&lt;/p&gt;




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

&lt;p&gt;Enterprise-ready doesn't mean "complex." It means &lt;strong&gt;reliable, secure, and fast.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;By turning on WAL mode, tuning the cache, using a "One Tenant, One File" strategy, and adding automated cloud streaming, SQLite can easily power a highly profitable SaaS platform.&lt;/p&gt;

&lt;p&gt;Stop paying for expensive database clusters that sleep most of the time. Optimize your desk drawer, and watch your application fly.&lt;/p&gt;

</description>
      <category>sqlite</category>
      <category>performance</category>
      <category>modular</category>
      <category>database</category>
    </item>
    <item>
      <title>The Secret of the Small Database: Why "Big" Technology Often Slows You Down</title>
      <dc:creator>ynwd</dc:creator>
      <pubDate>Fri, 15 May 2026 01:28:06 +0000</pubDate>
      <link>https://dev.to/ynwd/the-secret-of-the-small-database-why-big-technology-often-slows-you-down-150</link>
      <guid>https://dev.to/ynwd/the-secret-of-the-small-database-why-big-technology-often-slows-you-down-150</guid>
      <description>&lt;p&gt;Imagine you are running a business. You need to save and retrieve files every day. You have two choices:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The Remote Mega-Warehouse:&lt;/strong&gt; A massive, high-security building located 10 miles away. Every time you want to save a single piece of paper, you have to call a courier, wait for them to drive there, pass through three security checkpoints, wait for a clerk to find an empty shelf, and then get a confirmation call back.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Desktop Filing Cabinet:&lt;/strong&gt; A small, incredibly fast drawer right under your desk. You open it, drop the paper in, and close it. Total time: half a second.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In the world of technology, &lt;strong&gt;Oracle, Microsoft SQL Server, MySQL, and PostgreSQL&lt;/strong&gt; are the Mega-Warehouses. &lt;strong&gt;SQLite&lt;/strong&gt; is the filing cabinet.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;The "Big Four" and the Hidden Tax&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;When companies choose big names like &lt;strong&gt;Oracle&lt;/strong&gt; or &lt;strong&gt;MySQL&lt;/strong&gt;, they think they are buying "power." While these systems are very capable, they come with a "Hidden Tax" that most people don't notice until their app starts feeling slow.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;1. The "Distance Tax" (Networking)&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Big databases usually live on a different computer (server) than your app. Every time your app wants to save data, it has to send a message over a network "wire." Even at the speed of light, this takes time.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Big Databases:&lt;/strong&gt; Every request is a round-trip journey.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SQLite:&lt;/strong&gt; It lives &lt;em&gt;inside&lt;/em&gt; your app. There is no journey.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;2. The "Bureaucracy Tax" (Locking &amp;amp; Security)&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Because big databases are designed for thousands of people to use at once, they have massive "red tape." Before saving data, the database checks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"Who are you?" (Authentication)&lt;/li&gt;
&lt;li&gt;"Do you have permission?" (Authorization)&lt;/li&gt;
&lt;li&gt;"Is someone else touching this specific row?" (Locking)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While this sounds smart, it creates a massive line-up. If 1,000 people try to save data at the same time, the "Mega-Warehouse" gets a traffic jam at the front gate.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;3. The "Maintenance Tax" (Cost)&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Systems like &lt;strong&gt;Oracle&lt;/strong&gt; or &lt;strong&gt;MS SQL Server&lt;/strong&gt; are so complex that you need to hire highly-paid specialists (DBAs) just to keep them running. They require expensive monthly subscriptions and heavy hardware.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;SQLite: The Invisible Champion&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Most people think &lt;strong&gt;SQLite&lt;/strong&gt; is a "lite" or "toy" version of a database. This is a mistake. SQLite is likely the most used piece of software on Earth. It is inside your iPhone, your Android, your car's GPS, and even inside the airplanes you fly in.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why is it so fast?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No Paperwork:&lt;/strong&gt; It doesn't ask for a password every time you save a word. It trusts the app it's sitting in.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No Travel:&lt;/strong&gt; It’s a file on your hard drive. Reading it is as fast as opening a photo.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Extreme Reliability:&lt;/strong&gt; It is designed to never crash, even if the power goes out suddenly.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;The Common Trap: "We Might Need to Scale"&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The biggest reason developers choose the "Mega-Warehouse" (MySQL/Postgres) is a fear of the future. They think, &lt;em&gt;"What if we have millions of users one day?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;So, they build a complex, expensive system on Day 1. But here is the irony: &lt;strong&gt;The complexity itself makes the system slow.&lt;/strong&gt; By trying to prepare for a million users, they make the experience worse for their first 1,000 users.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A Better Way: The "Personal Cabinet" Strategy&lt;/strong&gt;&lt;br&gt;
Instead of putting 1,000,000 users into one giant, slow warehouse, smart architects are now giving each user (or group of users) their own "Personal Filing Cabinet" (a separate SQLite file).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Result:&lt;/strong&gt; 1,000 users can all save data at the exact same time without ever waiting in line. No traffic jams. No "Remote Warehouse" fees.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Summary: Which one do you actually need?&lt;/strong&gt;
&lt;/h3&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;The Big Guys (Oracle, MySQL, etc.)&lt;/th&gt;
&lt;th&gt;The Simple Guy (SQLite)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Speed&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Slow (due to network &amp;amp; red tape).&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Instant&lt;/strong&gt; (it's right there).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cost&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Expensive (Servers + Staff).&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Free&lt;/strong&gt; (Zero maintenance).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Setup&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Hard (Needs a professional).&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Easy&lt;/strong&gt; (Just works).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Best For&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Many different servers sharing data.&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Apps that need to be fast and cheap.&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;The Bottom Line:&lt;/strong&gt;&lt;br&gt;
Don't be fooled by big names and expensive price tags. In technology, "complex" doesn't mean "better." Sometimes, the fastest way to get the job done is to stop calling the warehouse and just open your own desk drawer.&lt;/p&gt;

</description>
      <category>sqlite</category>
      <category>performance</category>
      <category>database</category>
      <category>modular</category>
    </item>
    <item>
      <title>Why Use Google Cloud Run for Your MVP?</title>
      <dc:creator>ynwd</dc:creator>
      <pubDate>Sat, 25 Oct 2025 06:58:01 +0000</pubDate>
      <link>https://dev.to/ynwd/why-use-google-cloud-run-for-your-mvp-4476</link>
      <guid>https://dev.to/ynwd/why-use-google-cloud-run-for-your-mvp-4476</guid>
      <description>&lt;h2&gt;
  
  
  🧭 TL;DR
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Cloud Run = deploy fast, scale smart, pay only when used.&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
It’s the perfect environment to validate your MVP idea without committing to complex infrastructure or large bills.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;Using &lt;strong&gt;Google Cloud Run&lt;/strong&gt; for your &lt;strong&gt;MVP (Minimum Viable Product)&lt;/strong&gt; is a smart move — especially if you want &lt;strong&gt;speed, scalability, and low operational overhead&lt;/strong&gt;. Here’s why it’s often the best fit 👇  &lt;/p&gt;

&lt;h2&gt;
  
  
  🚀 1. Fast Deployment — Focus on the Product, Not Infrastructure
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Deploy a containerized web app or API with &lt;strong&gt;one command&lt;/strong&gt; (&lt;code&gt;gcloud run deploy&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;No need to manage servers, VMs, or Kubernetes clusters.&lt;/li&gt;
&lt;li&gt;Perfect for testing ideas and iterating quickly.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  💰 2. Pay Only for What You Use
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Cloud Run is &lt;strong&gt;fully serverless&lt;/strong&gt; — it scales down to zero when idle.&lt;/li&gt;
&lt;li&gt;You pay only when requests are being handled (per CPU/Memory/Request).&lt;/li&gt;
&lt;li&gt;Ideal for MVPs with unpredictable or low traffic at the start.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  ⚙️ 3. Scales Automatically
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;If your MVP suddenly gets traction, Cloud Run automatically scales up to handle thousands of requests.&lt;/li&gt;
&lt;li&gt;When traffic drops, it scales back down to zero — no manual tuning.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🧩 4. Easy Integration with Other GCP Services
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Works seamlessly with:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cloud SQL&lt;/strong&gt; (for databases)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cloud Storage&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pub/Sub&lt;/strong&gt;, &lt;strong&gt;Firestore&lt;/strong&gt;, &lt;strong&gt;Secret Manager&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Great for evolving an MVP into a production system later.&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  🧱 5. Language &amp;amp; Framework Agnostic
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Use &lt;strong&gt;Node.js, Go, Python, Rust, Java&lt;/strong&gt;, or anything that runs in a container.&lt;/li&gt;
&lt;li&gt;Perfect if your team uses diverse stacks or microservices.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🔐 6. Built-in Security
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;HTTPS by default with automatic TLS certificates.&lt;/li&gt;
&lt;li&gt;IAM-based access control.&lt;/li&gt;
&lt;li&gt;Private service connections for secure internal APIs.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🧪 7. Smooth Dev→Prod Path
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Start with local Docker builds and deploy the same image to Cloud Run — no surprises.&lt;/li&gt;
&lt;li&gt;Great compatibility with &lt;strong&gt;GitHub Actions&lt;/strong&gt; or &lt;strong&gt;Cloud Build&lt;/strong&gt; for CI/CD.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  ⚡ Bonus: Example MVP Use Cases
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;MVP Type&lt;/th&gt;
&lt;th&gt;Cloud Run Advantage&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;API backend&lt;/td&gt;
&lt;td&gt;Auto-scale and low idle cost&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Web dashboard&lt;/td&gt;
&lt;td&gt;Easy HTTPS and zero-maintenance&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Background jobs&lt;/td&gt;
&lt;td&gt;Event-driven with Pub/Sub triggers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AI inference microservice&lt;/td&gt;
&lt;td&gt;Scales per-request, fast cold starts&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;p&gt;source:&lt;br&gt;
&lt;a href="https://chatgpt.com/share/68fc51f5-94c0-800d-a18b-f0c43d5286a3" rel="noopener noreferrer"&gt;https://chatgpt.com/share/68fc51f5-94c0-800d-a18b-f0c43d5286a3&lt;/a&gt;&lt;/p&gt;

</description>
      <category>serverless</category>
      <category>cloud</category>
      <category>api</category>
      <category>database</category>
    </item>
    <item>
      <title>Build React SSR Page in Seconds Powered by Deno and TypeScript</title>
      <dc:creator>ynwd</dc:creator>
      <pubDate>Tue, 01 Aug 2023 06:00:52 +0000</pubDate>
      <link>https://dev.to/ynwd/build-react-ssr-page-in-seconds-powered-by-deno-and-typescript-3gkc</link>
      <guid>https://dev.to/ynwd/build-react-ssr-page-in-seconds-powered-by-deno-and-typescript-3gkc</guid>
      <description>&lt;p&gt;&lt;em&gt;Supercharge your SSR workflow: Harness the power of &lt;a href="https://fastro.deno.dev" rel="noopener noreferrer"&gt;Fastro&lt;/a&gt;, &lt;a href="https://deno.com" rel="noopener noreferrer"&gt;Deno&lt;/a&gt;, and &lt;a href="https://www.typescriptlang.org/" rel="noopener noreferrer"&gt;TypeScript&lt;/a&gt; to build React SSR pages in mere seconds.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;First, make sure you have Deno installed. See &lt;a href="https://deno.land/manual/getting_started/installation" rel="noopener noreferrer"&gt;the deno manual&lt;/a&gt; for details.&lt;/p&gt;

&lt;p&gt;Then, create a folder for your project and enter to it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;my-project &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;my-project
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Generate default project from command line.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;deno run &lt;span class="nt"&gt;-A&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; https://fastro.deno.dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above command will generate default folders and files that you can use for the initial project.&lt;/p&gt;

&lt;p&gt;Now let's run the application&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;deno task start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If there is no problem, you will see this message on the terminal&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Listening on http://localhost:8000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open that link on &lt;a href="http://localhost:8000" rel="noopener noreferrer"&gt;your browser&lt;/a&gt; or hit them via &lt;code&gt;curl&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;curl http://localhost:8000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can find more detailed instructions in &lt;a href="https://fastro.dev/manual" rel="noopener noreferrer"&gt;the fastro manual page&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>fastro</category>
      <category>ssr</category>
      <category>deno</category>
      <category>react</category>
    </item>
    <item>
      <title>Design pattern in golang: builder</title>
      <dc:creator>ynwd</dc:creator>
      <pubDate>Sun, 14 Nov 2021 10:25:42 +0000</pubDate>
      <link>https://dev.to/ynwd/design-pattern-in-golang-builder-2am</link>
      <guid>https://dev.to/ynwd/design-pattern-in-golang-builder-2am</guid>
      <description>&lt;p&gt;&lt;em&gt;Builder pattern&lt;/em&gt; dipakai untuk membuat sebuah &lt;em&gt;instance&lt;/em&gt; dari sebuah &lt;code&gt;struct&lt;/code&gt; -- beserta dengan semua propertinya.&lt;/p&gt;

&lt;p&gt;Perhatikan &lt;code&gt;struct&lt;/code&gt; berikut:&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;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="n"&gt;email&lt;/span&gt;       &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="n"&gt;address&lt;/span&gt;     &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="n"&gt;dateOfBirth&lt;/span&gt; &lt;span class="n"&gt;DateOfBirth&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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;type&lt;/span&gt; &lt;span class="n"&gt;DateOfBirth&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;year&lt;/span&gt;  &lt;span class="kt"&gt;int&lt;/span&gt;
    &lt;span class="n"&gt;month&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;
    &lt;span class="n"&gt;day&lt;/span&gt;   &lt;span class="kt"&gt;int&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Implementasi pattern
&lt;/h2&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;"strconv"&lt;/span&gt;
    &lt;span class="s"&gt;"strings"&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;newUserBuilder&lt;/span&gt;&lt;span class="p"&gt;()&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="k"&gt;return&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="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;u&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;Build&lt;/span&gt;&lt;span class="p"&gt;()&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="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;User&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;        &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;       &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;     &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;dateOfBirth&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dateOfBirth&lt;/span&gt;&lt;span class="p"&gt;,&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="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;u&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;SetName&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="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;name&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;u&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;SetEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&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;u&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;email&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;u&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;SetAddress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;address&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;u&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;address&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;u&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;SetDateOfBirth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dob&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;splitted&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;strings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dob&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;day&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;strconv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Atoi&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;splitted&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;0&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;u&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dateOfBirth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DateOfBirth&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;month&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;strconv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Atoi&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;splitted&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="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;u&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dateOfBirth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DateOfBirth&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;year&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;strconv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Atoi&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;splitted&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;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;u&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dateOfBirth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DateOfBirth&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dateOfBirth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DateOfBirth&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;day&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;month&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;year&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;Bahkan, kalau mau, kamu dapat menambahkan validasi pada setiap variabel yang akan menjadi input -- sebelum ia dipakai oleh setiap properti dari sebuah &lt;code&gt;struct&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cara penggunaan
&lt;/h2&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;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;builder&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;newUserBuilder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SetName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"agus"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SetAddress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"cirebon"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SetEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"agus@email.com"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SetDateOfBirth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"01/01/2020"&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;builder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Build&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;Println&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="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;h2&gt;
  
  
  Kesimpulan
&lt;/h2&gt;

&lt;p&gt;Dengan &lt;code&gt;builder pattern&lt;/code&gt; kita dapat membuat instance dari sebuah struct dan menambahkan validasi pada variabel-variabel yang akan menjadi &lt;em&gt;input&lt;/em&gt;-nya.&lt;/p&gt;

&lt;h2&gt;
  
  
  Source code
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://play.golang.org/p/7nBzfPFT8ix" rel="noopener noreferrer"&gt;https://play.golang.org/p/7nBzfPFT8ix&lt;/a&gt;&lt;/p&gt;

</description>
      <category>bahasa</category>
      <category>go</category>
      <category>designpattern</category>
      <category>creational</category>
    </item>
    <item>
      <title>Measuring mutex, channel and waitGroup performance</title>
      <dc:creator>ynwd</dc:creator>
      <pubDate>Sat, 13 Nov 2021 06:45:06 +0000</pubDate>
      <link>https://dev.to/ynwd/measuring-mutex-channel-and-waitgroup-performance-47j3</link>
      <guid>https://dev.to/ynwd/measuring-mutex-channel-and-waitgroup-performance-47j3</guid>
      <description>&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;function&lt;/th&gt;
&lt;th&gt;concurrency&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;getText&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;getTextWithChannel&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;getTextWithWaitGroup&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;getTextWithMutex&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Source code:&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;"sync"&lt;/span&gt;
    &lt;span class="s"&gt;"time"&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;getText&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="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;"hi"&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="s"&gt;"hello"&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;i&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;getTextWithWaitGroup&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="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;"hi"&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;waitgroup&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="n"&gt;waitgroup&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;1&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="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"hello"&lt;/span&gt;
        &lt;span class="n"&gt;waitgroup&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="p"&gt;}()&lt;/span&gt;

    &lt;span class="n"&gt;waitgroup&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;return&lt;/span&gt; &lt;span class="n"&gt;t&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;getTextWithChannel&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="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;"hi"&lt;/span&gt;
    &lt;span class="n"&gt;done&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="kt"&gt;bool&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="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"hello"&lt;/span&gt;
        &lt;span class="n"&gt;done&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
    &lt;span class="p"&gt;}()&lt;/span&gt;

    &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;done&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;t&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;getTextWithMutex&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="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;txt&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"hi"&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="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"hello"&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;i&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="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;text&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;txt&lt;/span&gt;   &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="n"&gt;mutex&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;Mutex&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;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;txt&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;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mutex&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Lock&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;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mutex&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unlock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;txt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;txt&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;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Get&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="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mutex&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Lock&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;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mutex&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unlock&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;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;txt&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Benchmark test:&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="s"&gt;"testing"&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;BenchmarkGetText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;testing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;B&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="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="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;N&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="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;getText&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="n"&gt;BenchmarkGetTextWithChannel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;testing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;B&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="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="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;N&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="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;getTextWithChannel&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="n"&gt;BenchmarkGetTextWithWaitGroup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;testing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;B&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="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="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;N&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="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;getTextWithWaitGroup&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="n"&gt;BenchmarkGetTextWithMutex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;testing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;B&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="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="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;N&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="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;getTextWithMutex&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;Result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Running tool: /usr/local/go/bin/go test -benchmem -run=^$ -coverprofile=/var/folders/43/sjvtz21j0kq56_7vc9nchb400000gq/T/vscode-goeIm86z/go-code-cover -bench . github.com/ynwd/monorepo/Documents/apps/cms/cmd

goos: darwin
goarch: amd64
pkg: github.com/ynwd/monorepo/Documents/apps/cms/cmd
cpu: Intel(R) Core(TM) i5-1038NG7 CPU @ 2.00GHz
BenchmarkGetText-8                  1000000000           0.5197 ns/op          0 B/op          0 allocs/op
BenchmarkGetTextWithChannel-8        1826163           644.4 ns/op       136 B/op          3 allocs/op
BenchmarkGetTextWithWaitGroup-8      1780219           670.9 ns/op        56 B/op          3 allocs/op
BenchmarkGetTextWithMutex-8          3833086           311.2 ns/op        40 B/op          2 allocs/op
PASS
coverage: 100.0% of statements
ok      github.com/ynwd/monorepo/Documents/apps/cms/cmd 6.332s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>benchmark</category>
      <category>go</category>
      <category>datarace</category>
      <category>concurrency</category>
    </item>
    <item>
      <title>Data Races di Golang: Fixing with Mutex</title>
      <dc:creator>ynwd</dc:creator>
      <pubDate>Sat, 13 Nov 2021 05:39:05 +0000</pubDate>
      <link>https://dev.to/ynwd/data-races-di-golang-fixing-with-mutex-4d80</link>
      <guid>https://dev.to/ynwd/data-races-di-golang-fixing-with-mutex-4d80</guid>
      <description>&lt;p&gt;Sebelumnya, kita telah membahas &lt;a href="https://dev.to/ynwd/data-races-di-golang-fixing-with-channels-4ign"&gt;data race di golang dan channel&lt;/a&gt;. Sekarang kita akan mencoba memperbaiki data races dengan mutex.&lt;/p&gt;

&lt;p&gt;Tapi sebelumnya, kita akan menambahkan sebuah struct &lt;code&gt;text&lt;/code&gt; serta &lt;em&gt;getter-setter&lt;/em&gt;-nya dan mengubah fungsi &lt;code&gt;getText()&lt;/code&gt;, menjadi seperti ini:&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="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;getText&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="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;txt&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"hi"&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="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"hello"&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;i&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="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;text&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;txt&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;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;txt&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;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;txt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;txt&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;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Get&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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;txt&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;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="n"&gt;getText&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;Kalau dilihat secara sequence diagram, ia mirip dengan &lt;a href="https://dev.to/ynwd/data-races-di-golang-5b90"&gt;kode sebelumnya&lt;/a&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Go routine #1 : &lt;code&gt;main()&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Go routine #2 : fungsi di mana &lt;code&gt;i.Set()&lt;/code&gt; dipanggil.&lt;/li&gt;
&lt;/ul&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%2Fpilulew1v953glnxn5kc.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%2Fpilulew1v953glnxn5kc.png" alt="data races" width="800" height="338"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Dan jika kita jalankan dengan &lt;code&gt;-race&lt;/code&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 run -race main.go  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Maka ia juga akan menghasilkan warning:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;hi
==================
WARNING: DATA RACE
Write at 0x00c000012230 by goroutine 7:
  main.(*text).Set()
      /Users/pro/Documents/apps/cms/cmd/main.go:20 +0x33
  main.getText.func1()
      /Users/pro/Documents/apps/cms/cmd/main.go:10 +0x2e

Previous read at 0x00c000012230 by main goroutine:
  main.(*text).Get()
      /Users/pro/Documents/apps/cms/cmd/main.go:24 +0xda
  main.getText()
      /Users/pro/Documents/apps/cms/cmd/main.go:12 +0xf1
  main.main()
      /Users/pro/Documents/apps/cms/cmd/main.go:28 +0x24

Goroutine 7 (running) created at:
  main.getText()
      /Users/pro/Documents/apps/cms/cmd/main.go:9 +0xd0
  main.main()
      /Users/pro/Documents/apps/cms/cmd/main.go:28 +0x24
==================
Found 1 data race(s)
exit status 66
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Solusi dengan mutex
&lt;/h2&gt;

&lt;p&gt;Mutex gunanya untuk mencegah agar sebuah variabel tidak diakses secara bersamaan.&lt;/p&gt;

&lt;p&gt;Implementasinya sangat mudah. Kita tinggal menempatkan saja method &lt;code&gt;Lock&lt;/code&gt; dan &lt;code&gt;Unlock&lt;/code&gt; di variabel yang terkena data races.&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;"sync"&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;getText&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="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;txt&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"hi"&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="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"hello"&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;i&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="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;text&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;txt&lt;/span&gt;   &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="n"&gt;mutex&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;Mutex&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;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;txt&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;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mutex&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Lock&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;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mutex&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unlock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;txt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;txt&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;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Get&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="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mutex&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Lock&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;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mutex&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unlock&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;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;txt&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;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="n"&gt;getText&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;Jika kita jalankan dengan &lt;code&gt;-race&lt;/code&gt;, hasilnya:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ go run -race main.go                                                     main*
hi
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2Fn3ifoilykk9s9cgu9fsf.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%2Fn3ifoilykk9s9cgu9fsf.png" alt="mutex prevent datarace" width="800" height="342"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Yang menjadi pertanyaan: mengapa hasilnya tetap &lt;code&gt;hi&lt;/code&gt;?&lt;/p&gt;

&lt;p&gt;Jawabannya adalah: karena go routine #1 (main), selesainya lebih dulu dan langsung exit. &lt;/p&gt;

&lt;p&gt;Walaupun go routine ke-2 sedang berjalan, karena go routine #1 sudah exit duluan, ya sudah, program selesai. &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%2Fr2olhrvpmdfdr49llmme.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%2Fr2olhrvpmdfdr49llmme.png" alt="Diagram data races" width="668" height="332"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>datarace</category>
      <category>go</category>
      <category>bahasa</category>
    </item>
    <item>
      <title>Data Races di Golang: Fixing with Channels</title>
      <dc:creator>ynwd</dc:creator>
      <pubDate>Thu, 11 Nov 2021 01:43:17 +0000</pubDate>
      <link>https://dev.to/ynwd/data-races-di-golang-fixing-with-channels-4ign</link>
      <guid>https://dev.to/ynwd/data-races-di-golang-fixing-with-channels-4ign</guid>
      <description>&lt;p&gt;Pada &lt;a href="https://dev.to/ynwd/data-races-di-golang-fixing-with-waitgroup-1agc"&gt;artikel sebelumnya&lt;/a&gt;, kita telah memperbaiki data race dengan &lt;code&gt;WaitGroup&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Kali ini kita akan mencegah data race menggunakan channel.&lt;/p&gt;

&lt;p&gt;Caranya sangat mudah.&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="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;getText&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="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;"hi"&lt;/span&gt;
    &lt;span class="n"&gt;done&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// go routine #2&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;t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"hello"&lt;/span&gt;
        &lt;span class="n"&gt;done&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
    &lt;span class="p"&gt;}()&lt;/span&gt;

    &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;done&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// go routine #1&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;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="n"&gt;getText&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;Source code: &lt;a href="https://play.golang.org/p/INwBrA67cCu" rel="noopener noreferrer"&gt;https://play.golang.org/p/INwBrA67cCu&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Jalankan dengan &lt;code&gt;-race&lt;/code&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 run -race main.go                                                                                 
hello
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Dan warning &lt;code&gt;DATA RACE&lt;/code&gt; pun tidak muncul lagi.&lt;/p&gt;

</description>
      <category>go</category>
      <category>dataraces</category>
      <category>bahasa</category>
    </item>
    <item>
      <title>Data Races di Golang: Fixing with WaitGroup</title>
      <dc:creator>ynwd</dc:creator>
      <pubDate>Thu, 11 Nov 2021 01:14:18 +0000</pubDate>
      <link>https://dev.to/ynwd/data-races-di-golang-fixing-with-waitgroup-1agc</link>
      <guid>https://dev.to/ynwd/data-races-di-golang-fixing-with-waitgroup-1agc</guid>
      <description>&lt;p&gt;Pada &lt;a href="https://dev.to/ynwd/data-races-di-golang-5b90"&gt;artikel sebelumnya&lt;/a&gt;, telah kita bahas data races di golang. Kali ini kita akan mencegahnya agar tidak terjadi menggunakan &lt;code&gt;sync.WaitGroup&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Caranya cukup mudah.&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;"sync"&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;getText&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="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;"hi"&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;waitgroup&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="n"&gt;waitgroup&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;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// go routine #2&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;t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"hello"&lt;/span&gt;
        &lt;span class="n"&gt;waitgroup&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="p"&gt;}()&lt;/span&gt;

    &lt;span class="n"&gt;waitgroup&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;return&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// go routine #1&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;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="n"&gt;getText&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;Source code: &lt;a href="https://play.golang.org/p/lYasbbWmB0j" rel="noopener noreferrer"&gt;https://play.golang.org/p/lYasbbWmB0j&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Jalankan dengan &lt;code&gt;-race&lt;/code&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 run -race main.go                                                                                  main*
hello
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Dan warning &lt;code&gt;DATA RACE&lt;/code&gt; pun tidak muncul lagi.&lt;/p&gt;

</description>
      <category>go</category>
      <category>datarace</category>
      <category>bahasa</category>
    </item>
    <item>
      <title>Data Races di Golang</title>
      <dc:creator>ynwd</dc:creator>
      <pubDate>Wed, 10 Nov 2021 06:48:22 +0000</pubDate>
      <link>https://dev.to/ynwd/data-races-di-golang-5b90</link>
      <guid>https://dev.to/ynwd/data-races-di-golang-5b90</guid>
      <description>&lt;p&gt;&lt;em&gt;Data race&lt;/em&gt; adalah kondisi ketika sebuah variable diakses oleh dua &lt;em&gt;go routine&lt;/em&gt; yang berjalan secara bersamaan &lt;em&gt;(concurrent)&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Mari kita lihat contohnya.&lt;br&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%2Fj37a07h02km51ilt80z8.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%2Fj37a07h02km51ilt80z8.png" alt="code" width="800" height="621"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Source code: &lt;a href="https://play.golang.org/p/4uWsRaxBs79" rel="noopener noreferrer"&gt;https://play.golang.org/p/4uWsRaxBs79&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Jika kode diatas kita jalankan secara biasa, hasilnya "hi". Seolah-olah tidak terjadi masalah.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ go run main.go
hi  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2Fr2olhrvpmdfdr49llmme.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%2Fr2olhrvpmdfdr49llmme.png" alt="Diagram data races" width="668" height="332"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Lalu, bagaimana cara melakukan simulasi agar terjadi race condition?&lt;/p&gt;

&lt;h2&gt;
  
  
  Simulasi data race
&lt;/h2&gt;

&lt;p&gt;Untungnya, go sudah menyediakan cara agar kita melakukan simulasi data race.&lt;/p&gt;

&lt;p&gt;Jalankan program dengan &lt;code&gt;-race&lt;/code&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 run -race main.go
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hasilnya:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;hi
==================
WARNING: DATA RACE
Write at 0x00c000118210 by goroutine 7:
  main.getText.func1()
      /Users/pro/Documents/apps/cms/cmd/main.go:9 +0x30

Previous read at 0x00c000118210 by main goroutine:
  main.getText()
      /Users/pro/Documents/apps/cms/cmd/main.go:12 +0xda
  main.main()
      /Users/pro/Documents/apps/cms/cmd/main.go:17 +0x24

Goroutine 7 (running) created at:
  main.getText()
      /Users/pro/Documents/apps/cms/cmd/main.go:8 +0xd0
  main.main()
      /Users/pro/Documents/apps/cms/cmd/main.go:17 +0x24
==================
Found 1 data race(s)
exit status 66
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Pembahasan error
&lt;/h2&gt;

&lt;p&gt;Mari kita bahas satu persatu&lt;/p&gt;

&lt;h3&gt;
  
  
  Blok #1
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;WARNING: DATA RACE
Write at 0x00c000118210 by goroutine 7:
  main.getText.func1()
      /Users/pro/Documents/apps/cms/cmd/main.go:9 +0x30
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Menjelaskan di mana data race terjadi: line ke-9.&lt;/p&gt;

&lt;h3&gt;
  
  
  Blok #2
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Previous read at 0x00c000118210 by main goroutine:
  main.getText()
      /Users/pro/Documents/apps/cms/cmd/main.go:12 +0xda
  main.main()
      /Users/pro/Documents/apps/cms/cmd/main.go:17 +0x24
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Menjelaskan di mana variable tersebut sudah terpanggil: line ke-12.&lt;/p&gt;

&lt;h3&gt;
  
  
  Blok #3
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Goroutine 7 (running) created at:
  main.getText()
      /Users/pro/Documents/apps/cms/cmd/main.go:8 +0xd0
  main.main()
      /Users/pro/Documents/apps/cms/cmd/main.go:17 +0x24
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Menjelaskan di mana go routine tersebut dibuat: line ke-8.&lt;/p&gt;

</description>
      <category>go</category>
      <category>datarace</category>
      <category>bahasa</category>
    </item>
  </channel>
</rss>
