<?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: Insight 105</title>
    <description>The latest articles on DEV Community by Insight 105 (@insight105).</description>
    <link>https://dev.to/insight105</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3682132%2F4c1bd658-43c8-4a58-bc53-2bb4d2e7142b.png</url>
      <title>DEV Community: Insight 105</title>
      <link>https://dev.to/insight105</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/insight105"/>
    <language>en</language>
    <item>
      <title>Stop Hitting Rate Limits: The Ultimate Antigravity &amp; OpenCode Workflow for 10x Developers</title>
      <dc:creator>Insight 105</dc:creator>
      <pubDate>Wed, 22 Apr 2026 01:16:12 +0000</pubDate>
      <link>https://dev.to/insight105/stop-hitting-rate-limits-the-ultimate-antigravity-opencode-workflow-for-10x-developers-3iie</link>
      <guid>https://dev.to/insight105/stop-hitting-rate-limits-the-ultimate-antigravity-opencode-workflow-for-10x-developers-3iie</guid>
      <description>&lt;p&gt;We've all been there. You're completely in the zone, building out an impressive new feature with Antigravity, and then—&lt;em&gt;bam&lt;/em&gt;—you hit a rate limit. Suddenly, your flow is dead, and you're staring at a timer telling you to come back tomorrow. Or worse, you ask the AI to tweak one tiny component, and it decides to regenerate the &lt;em&gt;entire&lt;/em&gt; codebase, chewing through your tokens and breaking something else in the process.&lt;/p&gt;

&lt;p&gt;If you’re leaning solely on a web-based AI IDE for large-scale projects, you’re probably doing it the hard way. It’s expensive, prone to rate limits, and honestly, a bit chaotic when your project scales past a few files.&lt;/p&gt;

&lt;p&gt;Enter the game-changer: &lt;strong&gt;The Antigravity + OpenCode Hybrid Workflow.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;By combining the big-picture brilliance of Antigravity with the surgical, file-aware precision of OpenCode (a CLI agent), you can effectively bypass rate limit frustrations, slash your token costs by up to 70%, and build complex apps in a fraction of the time. &lt;/p&gt;

&lt;p&gt;Here is exactly how to pull it off.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Core Problem: Why the "All-in-One" Approach Fails
&lt;/h2&gt;

&lt;p&gt;Let's get one thing straight: &lt;strong&gt;Antigravity&lt;/strong&gt; is an absolute cheat code. Why? &lt;strong&gt;Because you no longer need to buy separate API tokens.&lt;/strong&gt; Instead of paying top dollar directly for Anthropic or Google API credits, Antigravity hands you built-in, out-of-the-box access to the world's most bleeding-edge models: &lt;strong&gt;Gemini 3.1 Pro&lt;/strong&gt;, &lt;strong&gt;Gemini 3 Flash&lt;/strong&gt;, &lt;strong&gt;Claude Sonnet 4.6&lt;/strong&gt;, and &lt;strong&gt;Claude Opus 4.6&lt;/strong&gt;. You get all this premium firepower without the separate billing nightmare! For throwing together a quick script or prototyping, it's practically magic. &lt;/p&gt;

&lt;p&gt;But when you're building a massive project—say, a 30+ file architecture over several weeks—the cracks start to show:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The Monolith Trap:&lt;/strong&gt; You have to cram everything into one giant conversation. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Token Bleed:&lt;/strong&gt; Every small bug fix means re-sending massive amounts of context. It's expensive.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The "Domino Effect":&lt;/strong&gt; Regenerating code often breaks unrelated parts of your app. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Idle Time:&lt;/strong&gt; Hitting a rate limit means your work stops entirely for 24 to 48 hours.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;OpenCode&lt;/strong&gt;, on the other hand, is a terminal-based AI agent that lives &lt;em&gt;inside&lt;/em&gt; your project. It reads your actual file structure, understands your context, and writes code directly to your disk. &lt;/p&gt;

&lt;p&gt;When you pair them together, you get the absolute best of both worlds.&lt;/p&gt;




&lt;h2&gt;
  
  
  When to Reach for Which Tool
&lt;/h2&gt;

&lt;p&gt;Think of Antigravity as your &lt;strong&gt;Lead Architect&lt;/strong&gt;, and OpenCode as your &lt;strong&gt;Senior Developer&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reach for Antigravity when:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You are exploring ideas and need a quick prototype (&amp;lt; 1 hour).&lt;/li&gt;
&lt;li&gt;You are designing the initial architecture, database schemas, and folder structures. &lt;/li&gt;
&lt;li&gt;You need comprehensive "blueprints" for how a complex app should work.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Reach for OpenCode when:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You are executing a multi-week project.&lt;/li&gt;
&lt;li&gt;You need to implement complex features file-by-file.&lt;/li&gt;
&lt;li&gt;You need to fix a highly specific bug without messing up the rest of the app.&lt;/li&gt;
&lt;li&gt;You want to keep token usage incredibly lean.&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%2F755mezv63lyqlcnnj906.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%2F755mezv63lyqlcnnj906.png" alt=" " width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The "Sandwich" Workflow: How We Build Apps Fast
&lt;/h2&gt;

&lt;p&gt;After months of tweaking, here is the exact step-by-step methodology we use. It works flawlessly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 0: Quick Setup &amp;amp; Installation
&lt;/h3&gt;

&lt;p&gt;Before we start making the "sandwich", you need to have OpenCode installed and configured to connect with the Antigravity provider. It takes less than two minutes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 1. Install OpenCode globally via npm&lt;/span&gt;
npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; @opencode/cli

&lt;span class="c"&gt;# 2. Install the Antigravity Auth Plugin (This bridges OpenCode to your Antigravity quotas)&lt;/span&gt;
npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; opencode-plugin-antigravity-auth

&lt;span class="c"&gt;# 3. Initialize your project folder &lt;/span&gt;
&lt;span class="nb"&gt;mkdir &lt;/span&gt;my-awesome-app
&lt;span class="nb"&gt;cd &lt;/span&gt;my-awesome-app

&lt;span class="c"&gt;# 4. Tell OpenCode to use the Antigravity models by creating an .opencode.json file:&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'{
  "provider": {
    "google": {
      "models": {
        "antigravity-claude-opus-4-6": {},
        "antigravity-claude-sonnet-4-6": {},
        "antigravity-gemini-3-1-pro": {},
        "antigravity-gemini-3-flash": {}
      }
    }
  }
}'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; .opencode.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the CLI and plugin installed, you're ready to authenticate and start building.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: The Master Blueprint (Using Antigravity)
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;Time: 1-2 hours | Cost: 50k-100k tokens (Worth every penny)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;First, fire up Antigravity. Your goal here isn't to write functional code yet. Your goal is to write a &lt;strong&gt;comprehensive technical specification&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;Prompt Antigravity like this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"You are the lead architect for [Project Name]. Create a comprehensive blueprint with a phase-by-phase structure. I need markdown files (like PHASE_1_ARCHITECTURE.md, PHASE_2_AUTH.md). For each file, detail the exact file paths to create, function signatures, database schemas, integration points, and error handling strategies."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Antigravity will output incredibly detailed markdown files. You just saved yourself days of planning.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: The Systematic Build (Using OpenCode)
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;Time: Days/Weeks | Cost: Extremely lean&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Now, drop into your terminal. OpenCode is going to execute the blueprint step-by-step. &lt;/p&gt;

&lt;p&gt;First, the absolute secret weapon: &lt;strong&gt;Multi-Account Auto-Switching&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;The biggest bottleneck in AI coding is hitting that brutal API rate limit. OpenCode has a brilliant built-in solution for this. You can authenticate multiple Google accounts in your CLI. When your primary account hits its quota, OpenCode literally catches the rate limit error and &lt;strong&gt;automatically and seamlessly switches to the next available account&lt;/strong&gt; in the background. Your code generation doesn't stop, the task doesn't crash, and you don't even have to lift a finger.&lt;/p&gt;

&lt;p&gt;To set this up, you simply execute the login command multiple times, choosing a different Google account each time:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Run this once and login with your main Google account&lt;/span&gt;
opencode auth login 

&lt;span class="c"&gt;# Run it again to add your first backup account&lt;/span&gt;
opencode auth login 

&lt;span class="c"&gt;# Add a third one, just to safely guarantee zero downtime&lt;/span&gt;
opencode auth login 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By having 3 or 4 accounts pooled together, you effectively multipy your token quota by 4x. When Account A is exhausted, Account B takes over automatically. By the time you loop back to your first account the next day, the rate limit has already refreshed. It is the ultimate hack to keep your flow unbroken.&lt;/p&gt;

&lt;p&gt;Now, tell OpenCode to build your app using the blueprints Antigravity created:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Execute Phase 1&lt;/span&gt;
opencode run &lt;span class="s2"&gt;"Implement exactly everything in PHASE_1_ARCHITECTURE.md according to the specs"&lt;/span&gt; &lt;span class="nt"&gt;--model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;google/antigravity-claude-sonnet-4-6

&lt;span class="c"&gt;# Execute Phase 2&lt;/span&gt;
opencode run &lt;span class="s2"&gt;"Implement all files from PHASE_2_AUTH.md. Match signatures perfectly."&lt;/span&gt; &lt;span class="nt"&gt;--model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;google/antigravity-claude-sonnet-4-6

&lt;span class="c"&gt;# Fix a specific bug (Surgically!)&lt;/span&gt;
opencode run &lt;span class="s2"&gt;"Fix the JWT expiration error in src/auth.ts. Do not touch other files."&lt;/span&gt; &lt;span class="nt"&gt;--model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;google/antigravity-gemini-3-flash
&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%2F5283wbgjiv0jb9sr2iw8.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%2F5283wbgjiv0jb9sr2iw8.png" alt=" " width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Why This is Magical 🪄
&lt;/h3&gt;

&lt;p&gt;Because OpenCode is only looking at the specific markdown blueprint and the few files it needs to create, your prompts are tiny. You avoid sending 100k context windows for a 10-line bug fix. If one phase breaks, you just fix that phase. &lt;/p&gt;




&lt;h2&gt;
  
  
  Real-World Proof: Building VelosCMS
&lt;/h2&gt;

&lt;p&gt;Let’s look at a real example: building a headless CMS from scratch (30+ files, estimated 4 weeks). &lt;/p&gt;

&lt;p&gt;If we used &lt;strong&gt;Antigravity only&lt;/strong&gt;: We'd blow 150k tokens just trying to get the initial codebase up. Every single bug fix would require the AI to re-read the entire massive CMS, costing 80k-120k tokens per prompt. We'd hit a rate limit by lunch on day two. Total cost: ~450k tokens and immense frustration.&lt;/p&gt;

&lt;p&gt;With the &lt;strong&gt;Hybrid Workflow&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Antigravity&lt;/strong&gt; spent 2 hours writing &lt;code&gt;PHASE_1&lt;/code&gt; through &lt;code&gt;PHASE_5&lt;/code&gt; markdown files (50k tokens).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OpenCode&lt;/strong&gt; spent the next 3 weeks building the database adapter, the auth system, and the content manager, working solely off the markdown files. Each command only used 10k-15k tokens. &lt;/li&gt;
&lt;li&gt;When bugs happened, a quick OpenCode command fixed them using only 6k tokens.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;The result?&lt;/strong&gt; A 66% drop in token usage, literally zero rate limits intercepted our flow thanks to load balancing, and the codebase was cleaner because the AI wasn't overwhelmed.&lt;/p&gt;




&lt;h2&gt;
  
  
  5 Pro-Tips to Perfect This Workflow
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Be Pedantic With Your Blueprints:&lt;/strong&gt; Garbage in, garbage out. A vague blueprint (&lt;code&gt;- Make an auth system&lt;/code&gt;) will fail in OpenCode. A good blueprint details the exact file paths (&lt;code&gt;src/services/auth.ts&lt;/code&gt;), the error handling (&lt;code&gt;UserPermissionError&lt;/code&gt;), and the dependencies.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pick the Right Brain for the Job:&lt;/strong&gt; 

&lt;ul&gt;
&lt;li&gt;Formatting or simple fixes? Use &lt;code&gt;--model=google/antigravity-gemini-3-flash&lt;/code&gt; (it's lightning fast).&lt;/li&gt;
&lt;li&gt;Core feature work? Use &lt;code&gt;--model=google/antigravity-claude-sonnet-4-6&lt;/code&gt; (the workhorse).&lt;/li&gt;
&lt;li&gt;Complex architecture routing? Drop back to Antigravity and use Claude Opus.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Commit Your Blueprints to Git:&lt;/strong&gt; Treat your &lt;code&gt;PHASE_X.md&lt;/code&gt; files as your living documentation. It keeps you sane, and it helps your team know exactly what the app is supposed to look like.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use &lt;code&gt;.opencodeignore&lt;/code&gt;:&lt;/strong&gt; Prevent context-bloat by creating an ignore file for &lt;code&gt;node_modules&lt;/code&gt;, &lt;code&gt;dist&lt;/code&gt;, and &lt;code&gt;.next&lt;/code&gt; folders. Keep OpenCode focused only on the code that matters.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep Commands Atomic:&lt;/strong&gt; Never ask OpenCode to "build the entire login, registration, and 2FA system" in one go. Ask it to build the login endpoint. Then run a new command for registration. Small, atomic commands are easier to debug if they fail.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Wrap Up
&lt;/h2&gt;

&lt;p&gt;Stop fighting your AI tools. Antigravity and OpenCode aren't competitors; they are the ultimate pair-programming duo. Use Antigravity for the vision, and let OpenCode handle the heavy lifting in your terminal. &lt;/p&gt;

&lt;p&gt;Try this sandwich workflow on your next project. You’ll write better code, you’ll never see a rate limit screen again, and your token budget will thank you.&lt;/p&gt;

&lt;p&gt;Happy building! &lt;/p&gt;

</description>
      <category>opencode</category>
      <category>antigravity</category>
      <category>ai</category>
      <category>programming</category>
    </item>
    <item>
      <title>Every AI Meeting Tool Wants a Monthly Fee. So I Built My Own</title>
      <dc:creator>Insight 105</dc:creator>
      <pubDate>Thu, 09 Apr 2026 05:32:20 +0000</pubDate>
      <link>https://dev.to/insight105/every-ai-meeting-tool-wants-a-monthly-fee-so-i-built-my-own-2ep2</link>
      <guid>https://dev.to/insight105/every-ai-meeting-tool-wants-a-monthly-fee-so-i-built-my-own-2ep2</guid>
      <description>&lt;p&gt;Somewhere along the way, productivity software stopped being something you buy and started being something you rent.&lt;/p&gt;

&lt;p&gt;You want an AI note-taker for your meetings? That's $18/month. You want it to also generate action items? Upgrade to Pro. Need it to work across more than one device? That's another tier. Oh, and by the way — if you ever cancel your subscription, your notes are still "in our cloud," but good luck accessing them.&lt;/p&gt;

&lt;p&gt;I got fed up with it.&lt;/p&gt;

&lt;p&gt;Not just mildly annoyed — genuinely, properly fed up. I work in enough back-to-back meetings that an AI meeting assistant would be legitimately useful to me. But I wasn't willing to hand over a recurring fee for something my laptop is already capable of doing by itself.&lt;/p&gt;

&lt;p&gt;So I built &lt;strong&gt;Oats AI&lt;/strong&gt; — a free, local, open-source AI meeting assistant. No subscription. No cloud. No paywalls.&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%2Fdofy5f74vpcv3h8gre7g.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%2Fdofy5f74vpcv3h8gre7g.png" alt="Oats AI Desktop Interface - Live Transcription and AI Action Items Generation Demo" width="800" height="413"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Oats AI in action: live transcription and AI-generated action items, running entirely on your machine.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  What Oats AI Actually Does
&lt;/h2&gt;

&lt;p&gt;It sits quietly in the corner of your screen while your meeting runs.&lt;/p&gt;

&lt;p&gt;It captures your system audio — no virtual cable driver, no admin rights required — and transcribes everything in real time. Under the hood, it taps directly into native OS audio APIs (WASAPI Loopback on Windows, ScreenCaptureKit on macOS), so there's nothing extra to install and no elevated permissions needed. The entire app ships as a single binary built with Rust and Tauri, which means it's fast, small, and doesn't quietly eat your RAM in the background.&lt;/p&gt;

&lt;p&gt;You also get a side panel where you can jot down your own notes manually, the old-fashioned way, alongside the live transcript.&lt;/p&gt;

&lt;p&gt;When the meeting's over, you hit summarize. Oats AI processes the transcript and pulls out the key points and action items — the stuff you actually need to remember. Clean, readable, ready to copy into your Notion or email thread.&lt;/p&gt;

&lt;p&gt;That's it. No setup wizard. No onboarding flow. No "invite your team to unlock this feature."&lt;/p&gt;




&lt;h2&gt;
  
  
  The Part That Actually Matters: It's All Local
&lt;/h2&gt;

&lt;p&gt;Here's what separates Oats AI from everything else in this space.&lt;/p&gt;

&lt;p&gt;Most AI meeting tools work by recording your meeting audio and sending it to their servers for processing. That's how they can offer such a polished experience. It's also how they justify the monthly fee, because their infrastructure isn't free.&lt;/p&gt;

&lt;p&gt;Oats AI doesn't do any of that.&lt;/p&gt;

&lt;p&gt;The transcription runs on-device using &lt;strong&gt;whisper.cpp&lt;/strong&gt; — an optimized port of OpenAI's Whisper model that runs efficiently on your CPU or GPU without needing an internet connection. Your meeting notes and transcripts are stored in a local SQLite database, relative to the app folder. No account to create, no "sync with cloud" toggle to worry about, and no vendor who could theoretically read your meeting recordings if they wanted to.&lt;/p&gt;

&lt;p&gt;For anyone working in a corporate environment where sensitive conversations happen daily, this matters a lot more than most tools acknowledge.&lt;/p&gt;




&lt;h2&gt;
  
  
  Free. And Not "Free with Asterisk" Free.
&lt;/h2&gt;

&lt;p&gt;Let's be specific about what free means here, because the word has been corrupted beyond recognition by modern SaaS.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No trial period that expires in 14 days&lt;/li&gt;
&lt;li&gt;No feature limits in a "free tier"&lt;/li&gt;
&lt;li&gt;No "free for personal use, paid for teams"&lt;/li&gt;
&lt;li&gt;No credit card required. Ever.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The app is fully open-source. For the AI summarization feature, Oats AI uses &lt;strong&gt;OpenRouter&lt;/strong&gt; — a platform that provides access to genuinely free AI models, including models like &lt;code&gt;mistralai/mistral-7b-instruct&lt;/code&gt; and &lt;code&gt;google/gemma-3-4b-it&lt;/code&gt;, among others. You register your own account (via Google or GitHub), generate a free API key, and paste it in once. No billing info, no balance to top up, no usage fees. We don't even see your key.&lt;/p&gt;

&lt;p&gt;And if the OpenRouter free tier ever gets slow or overloaded mid-meeting? Oats AI automatically falls back to a built-in local summarizer that works without any internet connection. Your notes are never held hostage by an external service.&lt;/p&gt;

&lt;p&gt;One binary. Your machine. No recurring charges.&lt;/p&gt;




&lt;h2&gt;
  
  
  Built for the Zen-Minimalist Workflow
&lt;/h2&gt;

&lt;p&gt;The design is intentionally simple — what we internally call a "Zen-Minimalist" approach. There are two panels: your manual notes on the left, the live transcript on the right. A small pulsing indicator called the "Grain Pulse" lets you know the app is actively listening.&lt;/p&gt;

&lt;p&gt;There are no dashboards, no analytics, no "insights about your meeting habits." Just the tools you need to capture what happened and move on with your day.&lt;/p&gt;

&lt;p&gt;The name comes from the idea of &lt;em&gt;information nutrition&lt;/em&gt;. Oats aren't flashy, but they're exactly what you need. That's the experience we were aiming for.&lt;/p&gt;




&lt;h2&gt;
  
  
  If You Know WicaraAI, Think of This as the Next Chapter
&lt;/h2&gt;

&lt;p&gt;Some of you might be familiar with &lt;strong&gt;&lt;a href="https://dev.to/insight105/building-a-desktop-transcriber-with-whisper-ai-unlimited-free-3hel"&gt;WicaraAI&lt;/a&gt;&lt;/strong&gt;, a desktop transcription tool we released earlier — also free, also local, also open-source.&lt;/p&gt;

&lt;p&gt;WicaraAI does one thing really well: it takes an audio or video file, runs it through Whisper, and gives you a clean, formatted transcript. That's it. It's a sharp, focused tool and it still works great for that specific use case.&lt;/p&gt;

&lt;p&gt;But a transcript is only half the story.&lt;/p&gt;

&lt;p&gt;After a two-hour meeting, you don't want to read two hours worth of text. You want to know: &lt;em&gt;what did we actually decide? Who is doing what by when?&lt;/em&gt; That's the gap Oats AI was built to fill.&lt;/p&gt;

&lt;p&gt;Oats AI moves beyond transcription into &lt;strong&gt;understanding&lt;/strong&gt;. It listens to your meeting live, captures the transcript in real time, and when you're done — it reads that transcript and pulls out the action items that actually matter. It's WicaraAI's core capability, taken further.&lt;/p&gt;

&lt;p&gt;Same philosophy. Same commitment to local-first and free. Just more useful for the meeting context specifically.&lt;/p&gt;




&lt;h2&gt;
  
  
  Get It
&lt;/h2&gt;

&lt;p&gt;Oats AI is open-source and free. Download the latest release or build it yourself from the source code:&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;&lt;a href="https://github.com/insight105-studio/oat-ai" rel="noopener noreferrer"&gt;insight105-studio/oat-ai on GitHub&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you're tired of paying monthly for something your computer can handle on its own — this one's for you.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>rust</category>
    </item>
    <item>
      <title>Breaking the "Browser Black Box": The Foculing Hybrid Architecture</title>
      <dc:creator>Insight 105</dc:creator>
      <pubDate>Tue, 10 Mar 2026 08:33:17 +0000</pubDate>
      <link>https://dev.to/insight105/breaking-the-browser-black-box-the-foculing-hybrid-architecture-14fh</link>
      <guid>https://dev.to/insight105/breaking-the-browser-black-box-the-foculing-hybrid-architecture-14fh</guid>
      <description>&lt;p&gt;If you've ever built or used a conventional time tracking application to measure productivity—like Time Doctor, Hubstaff, or ActivTrak—you've likely noticed a fundamental flaw.&lt;/p&gt;

&lt;p&gt;As an engineer who often stares at lines of code, I looked at activity logs and found a recurring, useless pattern of raw data without actionable truth:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;10:00 - 16:45: Google Chrome&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For nearly seven hours, the tracker simply reported a single application name. Was that 7 hours of deep work writing reports in Google Docs, solving bugs on GitHub, sketching interfaces in Figma, or... hours of watching irrelevant tutorials on YouTube?&lt;/p&gt;

&lt;p&gt;Traditional monitoring tools fail because their underlying technology is outdated: they only read the &lt;strong&gt;OS Window Title&lt;/strong&gt;. In the modern era where the browser has essentially evolved into a "mini operating system," that approach is obsolete.&lt;/p&gt;

&lt;p&gt;That was the starting point for designing &lt;strong&gt;Foculing TimeTracker&lt;/strong&gt;—a research prototype I built to answer a specific challenge: &lt;em&gt;How do we pierce the "Browser Black Box" without compromising privacy or local machine capabilities?&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The Problem: Why Electron and OS-APIs Aren't Enough
&lt;/h2&gt;

&lt;p&gt;Initially, the most straightforward solution seemed to be building an Electron-based application that hooks into the operating system API (like Windows API &lt;code&gt;GetLastInputInfo&lt;/code&gt;). However, this introduced two new problems:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Electron is a Memory Hog.&lt;/strong&gt; For an application that lives in the background 24/7, consuming hundreds of Megabytes of RAM just to log time is an architectural "sin."&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Context Blindness in Modern Browsers.&lt;/strong&gt; Pure OS APIs cannot dive into browser tabs. Modern browsers, especially &lt;strong&gt;Microsoft Edge&lt;/strong&gt; and newer builds of Chrome, intentionally hide active tab titles from the OS-level workspace for security and performance reasons. When the OS asks "What is the user looking at?", Edge simply replies with its own process name, rendering OS-only trackers completely blind.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I needed a radical approach. I needed a &lt;em&gt;Hybrid&lt;/em&gt; architecture.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Solution: The Hybrid Architecture
&lt;/h2&gt;

&lt;p&gt;To achieve pixel-level precision matching how we work today, I designed Foculing around three distinct, communicating components:&lt;/p&gt;

&lt;h3&gt;
  
  
  The Core Engine: Golang-based Background Service
&lt;/h3&gt;

&lt;p&gt;I chose &lt;strong&gt;Golang&lt;/strong&gt; as the heart of the system (Foculing Core Service). The goal was clear: the footprint had to be as minimal as possible.&lt;br&gt;
Golang handles all the heavy lifting asynchronously (headless):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Capturing running process names at the OS level every 1 second.&lt;/li&gt;
&lt;li&gt;Managing Idle Detection without a UI.&lt;/li&gt;
&lt;li&gt;Handling Offline Buffering using aggressively encrypted &lt;strong&gt;SQLite&lt;/strong&gt; with &lt;strong&gt;SQLCipher&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;The result? This core engine consumes an average of just ~11 MB of RAM with CPU utilization under 1%.&lt;/em&gt; Incredibly lightweight.&lt;/p&gt;
&lt;h3&gt;
  
  
  The Browser Agent: Piercing the Limits of Chrome
&lt;/h3&gt;

&lt;p&gt;To solve the stagnant "Google Chrome" issue, I injected a &lt;strong&gt;Browser Extension (Manifest V3)&lt;/strong&gt; using JavaScript. This extension isn't just a logger; it's an active agent that knows exactly what URL is currently open.&lt;br&gt;
This agent has built-in privacy filters (stripping query parameters, blocking sensitive sites like banking portals), and then whispers directly to the &lt;em&gt;Golang Core Service&lt;/em&gt; via a &lt;em&gt;localhost socket connection&lt;/em&gt;—no internet required.&lt;/p&gt;
&lt;h3&gt;
  
  
  The Desktop UI: Replacing Electron with Wails
&lt;/h3&gt;

&lt;p&gt;Instead of using Electron to render the user dashboard, I pivoted to &lt;strong&gt;Wails (Go + Web Frontend)&lt;/strong&gt;. We get the beauty and flexibility of web-tech (React/HTML/Tailwind), but the main binary runs incredibly light as a native app without the Chromium rendering overhead characteristic of Electron.&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%2Fvzu6azzolz2x3hzi6fiv.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%2Fvzu6azzolz2x3hzi6fiv.png" alt="Foculing Desktop App" width="800" height="660"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Looking at the current build of the dashboard, you can see how this architecture translates into real, actionable UX for the user:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;The Productivity Donut:&lt;/strong&gt; A clean visualization separating &lt;em&gt;Active Time&lt;/em&gt; (e.g., 2h 16m) from &lt;em&gt;Idle Time&lt;/em&gt; (1h 8m).&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Workforce Health Engine:&lt;/strong&gt; Right beside it, there's a real-time monitor for &lt;em&gt;Burnout Risk&lt;/em&gt; and &lt;em&gt;Underutilization&lt;/em&gt;. If an employee is overworked, the system knows.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Granular 'Top Applications':&lt;/strong&gt; Because of the Hybrid Architecture, the "Top Applications" list doesn't just show &lt;code&gt;chrome.exe&lt;/code&gt;. It breaks it down: &lt;code&gt;gemini.google.com&lt;/code&gt; (7 minutes), &lt;code&gt;google.com&lt;/code&gt;, alongside native apps like &lt;code&gt;Explorer.EXE&lt;/code&gt; and &lt;code&gt;WhatsApp.Root.exe&lt;/code&gt;. Each with an automated tag (PRODUCTIVE, NEUTRAL, DISTRACTION).&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  The Biggest Challenge: Synchronizing the Data (Real-time Orchestration)
&lt;/h2&gt;

&lt;p&gt;The hardest part of this development wasn't building the applications themselves; it was &lt;strong&gt;Data Orchestration&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;When a user switches from "VS Code" to a "Jira" tab in Chrome, the &lt;em&gt;Golang Core&lt;/em&gt; logs &lt;code&gt;chrome.exe&lt;/code&gt;, and at the exact same heartbeat, the &lt;em&gt;Browser Agent&lt;/em&gt; sends a URL event for &lt;code&gt;jira.atlassian.net&lt;/code&gt;. Foculing has to intelligently merge these two data streams with precise timestamps, store them in the local encrypted database, and eventually compress them into a &lt;em&gt;Daily Summary Payload&lt;/em&gt; sent to the Server (requiring only ~12 KB bandwidth per day per user!).&lt;/p&gt;

&lt;p&gt;Previously, our productivity metrics looked dull:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;10:00 - 10:30: Google Chrome
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the Foculing architecture, that data pipeline transforms into a smart matrix structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;10:00 - 10:05: VS Code (Productive)
10:05 - 10:10: YouTube - "React Tutorial" (Distraction)
10:10 - 10:15: Jira - Sprint Planning (Productive)
10:15 - 10:30: GitHub.com - Code Review (Productive)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  What's Next?
&lt;/h2&gt;

&lt;p&gt;The research and initial release of this hybrid architecture serve as a proof-of-concept that transparency and privacy &lt;em&gt;can&lt;/em&gt; coexist if engineered with the right programming language and an Offline-First system.&lt;/p&gt;

&lt;p&gt;Employee data is now 100% shielded by AES-256 encryption, productivity metrics are no longer easily manipulated by tab hijackers, and for me as a developer, seeing the Golang and Wails services run stably with minimal RAM is intensely satisfying technically.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Keep an eye on the Foculing project — because your time tracker should be an analytics tool, not just a blind OS stopwatch.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>programming</category>
      <category>go</category>
      <category>wails</category>
      <category>tooling</category>
    </item>
    <item>
      <title>Building a Desktop Transcriber with Whisper AI: Unlimited &amp; Free</title>
      <dc:creator>Insight 105</dc:creator>
      <pubDate>Mon, 26 Jan 2026 14:01:21 +0000</pubDate>
      <link>https://dev.to/insight105/building-a-desktop-transcriber-with-whisper-ai-unlimited-free-3hel</link>
      <guid>https://dev.to/insight105/building-a-desktop-transcriber-with-whisper-ai-unlimited-free-3hel</guid>
      <description>&lt;p&gt;We’ve all been there. You have a one-hour interview recording, a podcast episode, or a lecture video that needs to be turned into text.&lt;/p&gt;

&lt;p&gt;You usually have three bad options:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Type it yourself&lt;/strong&gt; (and lose your sanity).&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Use free online tools&lt;/strong&gt; (and risk your data privacy).&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Pay for premium services&lt;/strong&gt; (and watch your wallet bleed).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;It’s time to stop counting minutes.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Meet &lt;strong&gt;WicaraAI&lt;/strong&gt;, a desktop tool we built at Insight Labs to solve this exact problem.&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%2Fxyd2l8ui5b6r8cp3c5n2.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%2Fxyd2l8ui5b6r8cp3c5n2.png" alt="WicaraAI Interface" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Unlimited. Free. Yours.
&lt;/h2&gt;

&lt;p&gt;WicaraAI isn't a subscription service. It’s a tool you own.&lt;/p&gt;

&lt;p&gt;Once you download it, &lt;strong&gt;you can transcribe as many files as you want.&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  10-minute video? Done.&lt;/li&gt;
&lt;li&gt;  5-hour meeting recording? Go ahead.&lt;/li&gt;
&lt;li&gt;  100 different audio files? The only limit is your hard drive space.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;It is 100% Free.&lt;/strong&gt; No credit systems, no "Pro" tiers, no hidden fees. You can use it forever.&lt;/p&gt;

&lt;h2&gt;
  
  
  ⚡ Real-Time "Live" Transcription (New!)
&lt;/h2&gt;

&lt;p&gt;Forget waiting for a progress bar to hit 100%.&lt;br&gt;
WicaraAI v1.1 introduces &lt;strong&gt;Real-Time Streaming&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Drag your file, click start, and watch the text appear on your screen instantly, sentence by sentence—just like watching a ghost type on your keyboard. It feels magic, and it saves you time because you can start reading immediately.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Choose Your Model:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Base&lt;/strong&gt;: Lightning-fast for English and casual use&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Small/Medium&lt;/strong&gt;: Better accuracy for Indonesian and non-English languages&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Large&lt;/strong&gt;: Maximum accuracy (slower, but worth it for critical work)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🎬 Any Format, Any File
&lt;/h2&gt;

&lt;p&gt;WicaraAI supports all major audio and video formats:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  🎥 &lt;strong&gt;Video&lt;/strong&gt;: MP4, MKV, AVI, MOV&lt;/li&gt;
&lt;li&gt;  🎵 &lt;strong&gt;Audio&lt;/strong&gt;: MP3, WAV, M4A, FLAC&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No need to convert your files first—just drag and drop.&lt;/p&gt;

&lt;h2&gt;
  
  
  Your Secrets Stay Safe
&lt;/h2&gt;

&lt;p&gt;The scariest part about online transcribers isn't the price—it's the privacy risk. When you upload a sensitive interview to the cloud, you lose control over who sees (or hears) it.&lt;/p&gt;

&lt;p&gt;WicaraAI runs &lt;strong&gt;completely offline&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It uses your computer's own processing power (CPU/GPU) via the &lt;strong&gt;Whisper AI&lt;/strong&gt; engine. You could pull the ethernet cable out of your PC, and WicaraAI would still work perfectly. Your files never leave your machine.&lt;/p&gt;

&lt;h2&gt;
  
  
  Now on Windows &amp;amp; macOS
&lt;/h2&gt;

&lt;p&gt;Whether you are a Windows power user or a Mac creative, we've got you covered.&lt;br&gt;
WicaraAI is now available as a native app for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  💻 &lt;strong&gt;Windows 10/11&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;  🍎 &lt;strong&gt;macOS (via MacCatalyst)&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Formatted for Humans
&lt;/h2&gt;

&lt;p&gt;Raw transcriptions are often ugly—just one giant block of endless text.&lt;br&gt;
WicaraAI is smarter. It listens to the natural flow of speech and automatically breaks the text into &lt;strong&gt;paragraphs and sentences&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;When you're done:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  📋 &lt;strong&gt;Copy to Clipboard&lt;/strong&gt; with one click&lt;/li&gt;
&lt;li&gt;  💾 &lt;strong&gt;Export to .txt&lt;/strong&gt; (auto-saved to your Desktop)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The result is readable text, ready to be pasted into your article, script, or documentation immediately.&lt;/p&gt;

&lt;h2&gt;
  
  
  Get It Now
&lt;/h2&gt;

&lt;p&gt;Why pay for something that your computer can do for free?&lt;/p&gt;

&lt;p&gt;Download the latest release from our GitHub below.&lt;br&gt;
Take back control of your transcriptions.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 &lt;strong&gt;First-time setup&lt;/strong&gt;: WicaraAI will download FFmpeg (~70MB) on first run to handle multi-format support. After that, it's 100% offline forever.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://github.com/insight105-studio/tools-wicara-ai/tags" rel="noopener noreferrer"&gt;&lt;strong&gt;Download WicaraAI&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Built with ❤️ by Insight Labs.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>whisper</category>
      <category>opensource</category>
      <category>dotnet</category>
      <category>ai</category>
    </item>
    <item>
      <title>C# 14: The Update That Finally Respects Your Time</title>
      <dc:creator>Insight 105</dc:creator>
      <pubDate>Wed, 21 Jan 2026 02:10:48 +0000</pubDate>
      <link>https://dev.to/insight105/c-14-the-update-that-finally-respects-your-time-1576</link>
      <guid>https://dev.to/insight105/c-14-the-update-that-finally-respects-your-time-1576</guid>
      <description>&lt;p&gt;&lt;strong&gt;Or: How Microsoft learned to stop worrying and let us write less code&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Let's be honest—C# has always been that friend who's brilliant but won't stop talking. You ask a simple question, and fifteen minutes later you're still nodding politely while they explain the historical context, the philosophical implications, and the seventeen different ways to approach the problem.&lt;/p&gt;

&lt;p&gt;For years, C# developers have been stuck writing the same ceremonial code over and over. Setting up dependency injection? That'll be thirteen lines of constructor boilerplate, thank you very much. Want to validate a property? Better create a private backing field. Need to combine two lists? Hope you remember whether to use &lt;code&gt;AddRange&lt;/code&gt;, &lt;code&gt;Concat&lt;/code&gt;, or just loop through manually.&lt;/p&gt;

&lt;p&gt;But something changed with C# 14 (shipping with .NET 10). It feels like the language team finally sat down, looked at what we &lt;em&gt;actually do&lt;/em&gt; all day, and asked: "Why are we making people type this much?"&lt;/p&gt;

&lt;p&gt;The result is a language that's starting to feel less like filling out paperwork in triplicate and more like... well, like writing code should feel.&lt;/p&gt;

&lt;h2&gt;
  
  
  Primary Constructors: Because Life's Too Short for Boilerplate
&lt;/h2&gt;

&lt;p&gt;Here's a pattern every .NET developer has written at least a hundred times (probably closer to a thousand if we're being honest):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserService&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;IUserRepository&lt;/span&gt; &lt;span class="n"&gt;_repository&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;ILogger&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;UserService&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_logger&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;IEmailService&lt;/span&gt; &lt;span class="n"&gt;_emailService&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;UserService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;IUserRepository&lt;/span&gt; &lt;span class="n"&gt;repository&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;ILogger&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;UserService&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;IEmailService&lt;/span&gt; &lt;span class="n"&gt;emailService&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;_repository&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;repository&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;_logger&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;_emailService&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;emailService&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Your actual business logic can finally start here...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Thirteen lines just to wire up three dependencies. And this is the &lt;em&gt;simple&lt;/em&gt; version—I've seen constructors with eight or ten dependencies that scroll off the screen.&lt;/p&gt;

&lt;p&gt;Here's the same thing in C# 14:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;IUserRepository&lt;/span&gt; &lt;span class="n"&gt;repository&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;ILogger&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;UserService&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;IEmailService&lt;/span&gt; &lt;span class="n"&gt;emailService&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetUserAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;repository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FindAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;??&lt;/span&gt; 
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;NotFoundException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"User &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt; not found"&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;That's it. The constructor parameters are automatically available throughout your class—no field declarations, no manual assignments, no ceremony. Just declare what you need and start using it.&lt;/p&gt;

&lt;p&gt;The first time I tried this, I kept scrolling down looking for the "real" constructor. Surely there had to be more to it? Nope. This is genuinely all you need.&lt;/p&gt;

&lt;h2&gt;
  
  
  Collection Expressions: Admitting Python Had a Point
&lt;/h2&gt;

&lt;p&gt;Okay, I'm just going to say what we're all thinking: Python's list syntax has always been cleaner than C#'s. There. I said it.&lt;/p&gt;

&lt;p&gt;For years, we C# developers have been doing this dance:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;numbers&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&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="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;combined&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;combined&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddRange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="m"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;8&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It works, but it feels like we're assembling IKEA furniture when all we wanted was to put some numbers in a box and add a few more.&lt;/p&gt;

&lt;p&gt;C# 14 introduces collection expressions that just... make sense:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;numbers&lt;/span&gt; &lt;span class="p"&gt;=&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="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;combined&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[..&lt;/span&gt;&lt;span class="n"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;8&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;..&lt;/code&gt; spread operator does exactly what you'd expect—takes the elements from one collection and splats them into another. No more remembering which method to call or which collection type supports which initialization pattern. It just works the way your brain expects it to work.&lt;/p&gt;

&lt;h2&gt;
  
  
  The &lt;code&gt;field&lt;/code&gt; Keyword: A Small Addition That Changes Everything
&lt;/h2&gt;

&lt;p&gt;Here's a problem that's bugged me for years: properties with simple validation logic require way too much code.&lt;/p&gt;

&lt;p&gt;Traditionally, if you wanted to trim whitespace from a name property (pretty basic stuff), you'd need:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;string&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;public&lt;/span&gt; &lt;span class="kt"&gt;string&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;get&lt;/span&gt; &lt;span class="p"&gt;=&amp;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;set&lt;/span&gt; &lt;span class="p"&gt;=&amp;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;value&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;Trim&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;??&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ArgumentNullException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;nameof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;value&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;Not terrible, but you're declaring the backing field manually just to add one line of logic.&lt;/p&gt;

&lt;p&gt;C# 14 introduces the &lt;code&gt;field&lt;/code&gt; keyword:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&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;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;set&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;field&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;Trim&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;??&lt;/span&gt; 
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ArgumentNullException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;nameof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The compiler automatically creates the backing field for you. You just write the validation that actually matters. It's such a simple change, but it removes a surprising amount of friction from everyday coding.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Things I'm Not Covering (But Should Mention)
&lt;/h2&gt;

&lt;p&gt;Look, there's more—&lt;code&gt;params&lt;/code&gt; now works with &lt;code&gt;Span&amp;lt;T&amp;gt;&lt;/code&gt; for zero-allocation variadic methods, you can write extension properties that feel natural, there are improvements to pattern matching—but honestly, cramming all of that into a blog post doesn't do these features justice.&lt;/p&gt;

&lt;p&gt;What matters more than the individual features is what they represent collectively.&lt;/p&gt;

&lt;h2&gt;
  
  
  What This Really Means: A Philosophy Shift
&lt;/h2&gt;

&lt;p&gt;Here's the thing: none of these features are revolutionary on their own. Kotlin has had primary constructors for years. Python's had clean collection syntax forever. Other languages figured out implicit backing fields ages ago.&lt;/p&gt;

&lt;p&gt;What's significant is that C# is &lt;em&gt;finally&lt;/em&gt; catching up—and doing it thoughtfully. They're not just copying syntax from other languages; they're integrating these patterns into C#'s type system in ways that actually make sense.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What I haven't covered in this article&lt;/strong&gt; (but the full book goes deep on):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How primary constructors interact with inheritance hierarchies (it's trickier than you'd think)&lt;/li&gt;
&lt;li&gt;Performance characteristics of collection expressions compared to traditional initialization&lt;/li&gt;
&lt;li&gt;Advanced extension scenarios like extension operators and static members&lt;/li&gt;
&lt;li&gt;How all of this plays with nullable reference types&lt;/li&gt;
&lt;li&gt;Practical migration strategies if you're coming from C# 7 or 8&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Microsoft language team seems to have realized something important: verbosity isn't a feature. Making developers type less boilerplate isn't "dumbing down" the language—it's &lt;strong&gt;respecting their time and cognitive load&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Every line of boilerplate is mental overhead. It's something you have to read, maintain, and potentially get wrong. When you remove that overhead, developers can focus on the logic that actually matters—the business rules, the algorithms, the architecture decisions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Worth Another Look
&lt;/h2&gt;

&lt;p&gt;If you haven't worked with C# since version 7 or 8, it's genuinely worth taking another look. The language has quietly evolved into something surprisingly pleasant to work with. It's still statically typed, still compiles to fast native code, still has an incredible ecosystem—but now it doesn't make you type everything three times.&lt;/p&gt;

&lt;p&gt;Is it perfect? No. Are there still pain points? Absolutely. But the direction is right, and for once, it feels like the language is evolving &lt;em&gt;with&lt;/em&gt; developers rather than at them.&lt;/p&gt;

&lt;p&gt;And honestly? After years of defending why my dependency injection constructor needs to be thirteen lines long, it's nice to finally have an answer that's just "it doesn't anymore."&lt;/p&gt;




&lt;p&gt;👉 &lt;strong&gt;Next up:&lt;/strong&gt; &lt;a href="https://dev.to/insight105/on-web-framework-performance-a-net-10-reality-check-4ep5"&gt;Why your Node.js API might be costing you more than it should →&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;📖 &lt;strong&gt;Want the complete picture?&lt;/strong&gt; Chapter 3 of "Mastering .NET 10" covers C# 14 features with 40+ working examples, migration patterns, performance analysis, and real-world scenarios. &lt;a href="https://www.amazon.com/dp/B0GGRTZ7JG" rel="noopener noreferrer"&gt;Get the book →&lt;/a&gt;&lt;/p&gt;

</description>
      <category>programming</category>
      <category>csharp</category>
      <category>net10</category>
    </item>
    <item>
      <title>Your 12-Month Path to .NET Mastery: A Realistic Roadmap</title>
      <dc:creator>Insight 105</dc:creator>
      <pubDate>Wed, 14 Jan 2026 19:01:37 +0000</pubDate>
      <link>https://dev.to/insight105/your-12-month-path-to-net-mastery-a-realistic-roadmap-2gj9</link>
      <guid>https://dev.to/insight105/your-12-month-path-to-net-mastery-a-realistic-roadmap-2gj9</guid>
      <description>&lt;p&gt;&lt;strong&gt;Or: How to transition from tutorial hell to production competence using a methodology that respects both cognitive science and calendar reality.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The programming education industry operates on two business models: predatory optimism ("Become a Full-Stack Developer in 21 Days!") and profitable ambiguity ("Master the craft through deliberate practice"—conveniently undefined).&lt;/p&gt;

&lt;p&gt;Neither model acknowledges what empirical evidence demonstrates: skill acquisition requires structured curriculum design, spaced repetition, and time-boxed milestones. Not motivation. Not passion. Methodology.&lt;/p&gt;

&lt;p&gt;If you're serious about mastering .NET 10, you need a roadmap that respects both the depth of the platform and the constraints of real life. Here's that roadmap.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Three Learning Profiles
&lt;/h2&gt;

&lt;p&gt;Before diving into timelines, acknowledge who you are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Full-time learner&lt;/strong&gt; (4-6 hours/day): 3-6 months to completion&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Part-time learner&lt;/strong&gt; (2-3 hours/day): 6-9 months to completion
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Weekend warrior&lt;/strong&gt; (10-15 hours/week): 9-12 months to completion&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What matters isn't speed—it's consistency. One hour daily beats marathon weekend sessions that lead to burnout by week three.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Five-Phase Architecture
&lt;/h2&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%2F3wamdy1hdem6pmc8yv1v.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%2F3wamdy1hdem6pmc8yv1v.png" alt=".NET 10 Learning Journey Roadmap" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Visual generated with AI assistance because I code better than I draw. The 'alien language' inside the Clean Architecture circle is just Core/Domain/Infra layers. Trust the text breakdown below more than the pixels!&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The learning path breaks down into five distinct phases, each building on the previous:&lt;/p&gt;

&lt;h3&gt;
  
  
  🌟 Phase 1: Beginner (Months 1-2)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Focus:&lt;/strong&gt; C# fundamentals and .NET foundations&lt;/p&gt;

&lt;p&gt;This phase exposes the fundamental dishonesty of "learn to code in a weekend" bootcamps. They optimize for demo-day deployments, not sustainable engineering competence. The result? Developers who can scaffold a Todo app but experience existential dread when encountering &lt;code&gt;IAsyncEnumerable&amp;lt;T&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Proper foundational work requires mastering C# 14 language features, LINQ composition patterns, and asynchronous programming models. Not superficial familiarity—internalized understanding that persists under production pressure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key milestones:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Construct console applications with JSON serialization/deserialization pipelines&lt;/li&gt;
&lt;li&gt;Demonstrate comprehension of async/await state machines (not just syntactic sugar application)&lt;/li&gt;
&lt;li&gt;Compose LINQ queries without Stack Overflow dependency for basic operations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Time investment:&lt;/strong&gt; 30-40 hours&lt;/p&gt;

&lt;h3&gt;
  
  
  🔵 Phase 2: Intermediate (Months 3-4)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Focus:&lt;/strong&gt; Web APIs, databases, and full-stack architecture&lt;/p&gt;

&lt;p&gt;This phase reveals .NET's competitive moat—the integrated ecosystem that JavaScript developers compensate for with 47 npm packages and three build tools:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ASP.NET Core&lt;/strong&gt; for REST API construction with dependency injection that doesn't require a PhD to configure&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Entity Framework Core&lt;/strong&gt; for ORM operations (supplemented by Dapper when EF's abstraction tax becomes prohibitive)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Blazor&lt;/strong&gt; for full-stack development without the cognitive overhead of maintaining separate TypeScript/JavaScript competency&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The architecturally defensible position: in 2026, learning MVC Controllers before Minimal APIs is historical reenactment, not engineering education. The performance differential and reduced ceremony make Controllers a legacy pattern worth understanding &lt;em&gt;after&lt;/em&gt; mastering the modern approach.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key milestones:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CRUD application with Blazor frontend and proper component lifecycle management&lt;/li&gt;
&lt;li&gt;REST API supporting multiple client types (web, mobile, third-party integration)&lt;/li&gt;
&lt;li&gt;Database-backed system with migration strategy and seed data management&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Time investment:&lt;/strong&gt; 50-60 hours&lt;/p&gt;

&lt;h3&gt;
  
  
  🟡 Phase 3: Advanced (Months 5-7)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Focus:&lt;/strong&gt; Performance, testing, and real-time features&lt;/p&gt;

&lt;p&gt;This phase separates hobbyists from professionals. Topics covered:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GraphQL&lt;/strong&gt; for flexible API design&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance optimization&lt;/strong&gt; with &lt;code&gt;Span&amp;lt;T&amp;gt;&lt;/code&gt;, memory allocation patterns, and AOT compilation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Testing strategies&lt;/strong&gt; that actually prevent bugs (not just checkbox TDD)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SignalR&lt;/strong&gt; for real-time features without reinventing WebSocket infrastructure&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The reality check: performance optimization requires understanding memory models and allocation patterns. If that sounds intimidating, good—it should. This is expert-level work that justifies senior developer salaries.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key milestones:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;API handling 50,000+ requests/second&lt;/li&gt;
&lt;li&gt;Test suite with 80%+ meaningful coverage&lt;/li&gt;
&lt;li&gt;Real-time dashboard with SignalR&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Time investment:&lt;/strong&gt; 60-70 hours&lt;/p&gt;

&lt;h3&gt;
  
  
  🟠 Phase 4: Expert (Months 8-9)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Focus:&lt;/strong&gt; Cloud deployment, security, and microservices&lt;/p&gt;

&lt;p&gt;Enterprise-grade application development requires:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Microservices architecture&lt;/strong&gt; with gRPC and Dapr&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Kubernetes deployment&lt;/strong&gt; strategies&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security implementation&lt;/strong&gt; following OWASP guidelines&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CI/CD pipelines&lt;/strong&gt; with GitHub Actions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is where "works on my machine" stops being acceptable. Production deployment requires understanding container orchestration, secret management, and automated testing pipelines.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key milestones:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Multi-service application deployed to cloud&lt;/li&gt;
&lt;li&gt;Zero-trust security implementation&lt;/li&gt;
&lt;li&gt;Automated deployment pipeline&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Time investment:&lt;/strong&gt; 50-60 hours&lt;/p&gt;

&lt;h3&gt;
  
  
  👑 Phase 5: Legend (Months 10-12)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Focus:&lt;/strong&gt; Software architecture and capstone project&lt;/p&gt;

&lt;p&gt;The final phase isn't about learning new frameworks—it's about architectural thinking:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Clean Architecture&lt;/strong&gt; patterns that actually improve maintainability&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CQRS and Event Sourcing&lt;/strong&gt; for complex domain logic&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Multi-tenant SaaS architecture&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The capstone project: a production-ready Cloud POS (Point of Sale) system with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Multi-tenant isolation&lt;/li&gt;
&lt;li&gt;Role-based access control&lt;/li&gt;
&lt;li&gt;Real-time inventory updates&lt;/li&gt;
&lt;li&gt;Payment processing integration&lt;/li&gt;
&lt;li&gt;Kubernetes deployment&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Time investment:&lt;/strong&gt; 80-100 hours&lt;/p&gt;

&lt;h2&gt;
  
  
  The Honest Time Estimate
&lt;/h2&gt;

&lt;p&gt;Total time from zero to production-capable: &lt;strong&gt;~250 hours of focused learning.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That's not "become an expert"—that's "employable as a mid-level .NET developer with portfolio projects that prove competence."&lt;/p&gt;

&lt;p&gt;Breaking that down:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;30% reading/watching tutorials&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;70% writing code&lt;/strong&gt; (this ratio is non-negotiable)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Rules That Actually Matter
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Consistency beats intensity
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;✅ 1 hour daily for 6 months = 180 hours
❌ 8 hours/day for 1 week = burnout by day 4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Build projects, not just tutorials
&lt;/h3&gt;

&lt;p&gt;After each chapter, ask: "How can I build something slightly different using these concepts?" &lt;/p&gt;

&lt;p&gt;Following tutorials creates the illusion of competence. Building original projects exposes what you actually understand.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Teach what you learn
&lt;/h3&gt;

&lt;p&gt;Blog posts, YouTube videos, or mentoring junior developers forces you to understand concepts deeply enough to explain them. If you can't explain it simply, you don't understand it well enough.&lt;/p&gt;

&lt;h2&gt;
  
  
  Progress Tracking
&lt;/h2&gt;

&lt;p&gt;Here's a pragmatic checklist approach:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Month 1-2:&lt;/strong&gt; Console applications, C# fundamentals&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Month 3-4:&lt;/strong&gt; Web APIs, databases, Blazor&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Month 5-7:&lt;/strong&gt; GraphQL, performance, testing, SignalR&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Month 8-9:&lt;/strong&gt; Cloud deployment, microservices, security&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Month 10-12:&lt;/strong&gt; Architecture patterns, capstone project  &lt;/p&gt;

&lt;p&gt;Mark chapters complete only when you've built something original using those concepts—not just completed the example code.&lt;/p&gt;

&lt;h2&gt;
  
  
  After Completion: What You're Actually Ready For
&lt;/h2&gt;

&lt;p&gt;No exaggeration, no marketing fluff—here's what's realistic:&lt;/p&gt;

&lt;p&gt;✅ &lt;strong&gt;Junior to mid-level .NET developer positions&lt;/strong&gt; at product companies&lt;br&gt;&lt;br&gt;
✅ &lt;strong&gt;Freelance .NET projects&lt;/strong&gt; with confidence in delivery&lt;br&gt;&lt;br&gt;
✅ &lt;strong&gt;Build and deploy your own SaaS product&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
✅ &lt;strong&gt;Contribute meaningfully to open source .NET projects&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
❌ &lt;strong&gt;Senior architect positions&lt;/strong&gt; (that requires 3-5 years production experience)&lt;br&gt;&lt;br&gt;
❌ &lt;strong&gt;Expert in every .NET framework&lt;/strong&gt; (250 hours covers breadth, not mastery)&lt;/p&gt;

&lt;h2&gt;
  
  
  The Uncomfortable Reality
&lt;/h2&gt;

&lt;p&gt;The educational completion rate for self-directed technical curricula hovers around 8-12%. Not due to content difficulty, but systematic execution failure:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Timeline delusion&lt;/strong&gt;: Believing 250 hours of deliberate practice compresses into two-week sprints (it doesn't)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Premature optimization&lt;/strong&gt;: Skipping foundational chapters to build "portfolio projects" that collapse under architectural scrutiny&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Inconsistent application&lt;/strong&gt;: Alternating between manic 12-hour sessions and week-long absences, wondering why retention fails&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This roadmap functions &lt;em&gt;exclusively&lt;/em&gt; when followed sequentially. Attempt to skip phases, rush milestones, or engage in passive consumption (reading without implementation)—and you'll contribute to that 90% attrition statistic.&lt;/p&gt;

&lt;p&gt;The methodology is empirically validated. The variable is whether you possess the discipline to execute against a 6-12 month timeline when the industry promises shortcuts.&lt;/p&gt;




&lt;h2&gt;
  
  
  What This Article Doesn't Cover
&lt;/h2&gt;

&lt;p&gt;This roadmap is condensed from &lt;strong&gt;Appendix A of "Mastering .NET 10"&lt;/strong&gt;, which includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Week-by-week breakdown for each phase&lt;/li&gt;
&lt;li&gt;Detailed hour estimates per chapter&lt;/li&gt;
&lt;li&gt;Milestone checkpoints to validate progress&lt;/li&gt;
&lt;li&gt;Troubleshooting guide for common learning roadblocks&lt;/li&gt;
&lt;li&gt;Community resources for each learning phase&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The full book provides 20 chapters of implementation details, architectural patterns, and production-ready code examples that this roadmap references.&lt;/p&gt;




&lt;p&gt;📘 &lt;strong&gt;Want the complete learning timeline with chapter-by-chapter breakdowns?&lt;/strong&gt; See Appendix A in &lt;a href="https://www.amazon.com/dp/B0GGRTZ7JG" rel="noopener noreferrer"&gt;"Mastering .NET 10"&lt;/a&gt; for the full 12-month roadmap with milestone validations.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;"The journey of a thousand miles begins with a single step—but only if you know where you're going."&lt;/em&gt;&lt;/p&gt;

</description>
      <category>programming</category>
      <category>architecture</category>
      <category>books</category>
      <category>roadmap</category>
    </item>
    <item>
      <title>On Web Framework Performance: A .NET 10 Reality Check</title>
      <dc:creator>Insight 105</dc:creator>
      <pubDate>Wed, 14 Jan 2026 05:24:37 +0000</pubDate>
      <link>https://dev.to/insight105/on-web-framework-performance-a-net-10-reality-check-4ep5</link>
      <guid>https://dev.to/insight105/on-web-framework-performance-a-net-10-reality-check-4ep5</guid>
      <description>&lt;p&gt;&lt;strong&gt;What TechEmpower's Round 23 benchmarks reveal about choosing the right framework for scale.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Quick thought experiment: you're building a microservice that needs to handle 100,000 requests per second with sub-10ms P99 latency. Your options are Express.js on Node.js, or ASP.NET Core Minimal APIs on .NET 10.&lt;/p&gt;

&lt;p&gt;If you picked Express purely based on "that's what we know"—well, I've got some news about your infrastructure costs.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Minimal API Value Proposition
&lt;/h2&gt;

&lt;p&gt;.NET historically suffered from what I'll politely call "ceremony addiction." Building a simple HTTP endpoint required Controllers, Action attributes, dependency injection configuration files, and enough boilerplate to make enterprise Java developers feel right at home.&lt;/p&gt;

&lt;p&gt;ASP.NET Core Minimal APIs threw that entire pattern out the window. Here's a complete, production-viable API:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;WebApplication&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MapGet&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="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"Hello, World"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MapGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/users/{id}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DbContext&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; 
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FindAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="n"&gt;User&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;Results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Ok&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;span class="n"&gt;Results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;NotFound&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Done. No controllers, no startup configuration sprawl, no architectural astronautics. It reads like Express, except—and here's where it gets interesting—it's meaningfully faster.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Benchmark Situation
&lt;/h2&gt;

&lt;p&gt;TechEmpower's Round 23 benchmarks (February 2025) show a performance gap that's grown substantially with .NET 9[1]:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Plaintext Test (Synthetic Maximum Throughput):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ASP.NET Core (.NET 9):&lt;/strong&gt; 27,530,836 requests/second&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fastify (Node.js):&lt;/strong&gt; 1,175,038 requests/second&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Express (Node.js):&lt;/strong&gt; 279,922 requests/second&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's a &lt;strong&gt;23.4x performance difference&lt;/strong&gt; in raw throughput. But here's the nuance: this is a synthetic benchmark designed to stress-test frameworks at their theoretical limits.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;JSON Serialization (More Realistic):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ASP.NET Core:&lt;/strong&gt; 2,546,481 req/s&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fastify:&lt;/strong&gt; 844,960 req/s&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gap: 3.0x&lt;/strong&gt; — still significant, but the margin narrows with real work.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Single Database Query:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ASP.NET Core:&lt;/strong&gt; 844,156 req/s&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fastify:&lt;/strong&gt; 437,129 req/s&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gap: 1.9x&lt;/strong&gt; — real-world I/O scenarios show smaller but meaningful advantages.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The pattern emerges: .NET's advantage is most dramatic in compute-intensive scenarios. In database-bound applications, the gap narrows—but one .NET server still replaces two Node servers. That operational cost difference compounds, especially when you're paying cloud provider bills quarterly.&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%2Fs4fn2anhoj88gmospe6g.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%2Fs4fn2anhoj88gmospe6g.png" alt="TechEmpower Round 23 Benchmark Comparison showing .NET 9 vs Node.js performance across Plaintext, JSON, and Database tests" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, before the Node.js community arrives with pitchforks: yes, Node is "fast enough" for most applications. Absolutely true. But "fast enough" and "optimal" diverge significantly at scale—and .NET 10 (released November 2025) widens the gap further with 49% faster API response times and 67% faster cold starts[2][3].&lt;/p&gt;

&lt;h2&gt;
  
  
  Vertical Slicing: The Organizational Benefit Nobody Mentions
&lt;/h2&gt;

&lt;p&gt;Traditional Controller-based APIs encourage this structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/Controllers/UserController.cs
/Services/UserService.cs  
/Repositories/UserRepository.cs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Looks organized, right? Until you realize implementing one feature requires editing three files across three directories. When requirements change, you're context-switching between folders like you're playing architectural whack-a-mole.&lt;/p&gt;

&lt;p&gt;Minimal APIs naturally encourage organizing by feature:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/Features/
  /Users/
    CreateUser.cs       // Complete feature: endpoint + logic
    GetUser.cs          // Self-contained
    DeleteUser.cs       // Everything in one place
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Code that changes together lives together. It's not revolutionary—it's just common sense that wasn't previously convenient.&lt;/p&gt;

&lt;h2&gt;
  
  
  Type Safety Without the TypeScript Tax
&lt;/h2&gt;

&lt;p&gt;JavaScript developers adopt TypeScript to get compile-time type checking, which means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Configuring &lt;code&gt;tsconfig.json&lt;/code&gt; (and debugging it when it inevitably breaks)&lt;/li&gt;
&lt;li&gt;Installing &lt;code&gt;@types/&lt;/code&gt; packages for every dependency&lt;/li&gt;
&lt;li&gt;Transpiling before runtime&lt;/li&gt;
&lt;li&gt;Debugging type errors that only exist at build time&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;C# &lt;em&gt;has&lt;/em&gt; type safety. It's native. Nullable reference types prevent null dereferencing at compile time. Generic constraints ensure type compatibility before your code ever runs. Your IDE knows what methods exist without runtime reflection magic.&lt;/p&gt;

&lt;p&gt;This isn't superficial tooling—it's a fundamental difference in how errors are prevented.&lt;/p&gt;




&lt;h2&gt;
  
  
  What This Article Doesn't Tell You
&lt;/h2&gt;

&lt;p&gt;Here's the thing: this is maybe 10% of the Minimal APIs story. &lt;strong&gt;Chapter 10 of "Mastering .NET 10"&lt;/strong&gt; covers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Complete Minimal API architecture with Vertical Slice pattern implementation&lt;/li&gt;
&lt;li&gt;Performance optimization techniques (including the dreaded N+1 query problem)&lt;/li&gt;
&lt;li&gt;Authentication, authorization, and middleware configuration&lt;/li&gt;
&lt;li&gt;Production deployment strategies for Kubernetes and Azure&lt;/li&gt;
&lt;li&gt;A full working NanoLink URL shortener with benchmarks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'm not saying .NET is always the right choice. Different contexts have different constraints. But if you're starting a new microservice and choosing Node.js primarily because "it's what everyone uses"—that's cargo cult engineering, not architecture.&lt;/p&gt;

&lt;p&gt;The benchmarks are public. The numbers are reproducible. What you do with that information is your decision.&lt;/p&gt;




&lt;p&gt;👉 &lt;strong&gt;Next up:&lt;/strong&gt; &lt;a href="//Series-04-Blazor-United.md"&gt;Full-stack development with a single language—or why maintaining two ecosystems might be optional →&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Want the implementation guide? Chapter 10 covers Minimal APIs with a complete NanoLink URL shortener example. &lt;a href="https://www.amazon.com/dp/B0GGRTZ7JG" rel="noopener noreferrer"&gt;Get "Mastering .NET 10" →&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;p&gt;[1] TechEmpower. "Web Framework Benchmarks - Round 23." February 2025. &lt;a href="https://www.techempower.com/benchmarks/#section=data-r23" rel="noopener noreferrer"&gt;https://www.techempower.com/benchmarks/#section=data-r23&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;em&gt;Round 23 benchmarks show .NET 9 performance reaching 27.5M requests/second in plaintext tests, with real-world JSON serialization showing 3.0x advantage over Node.js frameworks.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;[2] Microsoft. "Native AOT deployment overview." Official Documentation. &lt;a href="https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/" rel="noopener noreferrer"&gt;https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;em&gt;Native AOT compilation in .NET provides 67% faster cold starts, critical for serverless and containerized workloads.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;[3] Toub, Stephen. "Performance Improvements in .NET" series. Microsoft DevBlogs. &lt;a href="https://devblogs.microsoft.com/dotnet/" rel="noopener noreferrer"&gt;https://devblogs.microsoft.com/dotnet/&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;em&gt;Annual deep-dive series documenting .NET runtime optimizations, including JIT improvements, PGO (Profile-Guided Optimization), and zero-allocation patterns.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>javascript</category>
      <category>discuss</category>
      <category>performance</category>
    </item>
    <item>
      <title>React Application Architecture</title>
      <dc:creator>Insight 105</dc:creator>
      <pubDate>Tue, 06 Jan 2026 09:30:42 +0000</pubDate>
      <link>https://dev.to/insight105/react-application-architecture-4cb8</link>
      <guid>https://dev.to/insight105/react-application-architecture-4cb8</guid>
      <description>&lt;p&gt;After completing the entire backend foundation, we shift our focus to the &lt;strong&gt;frontend&lt;/strong&gt; side. Unlike a typical informational website, an online exam interface must be designed to handle:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Intense and rapid user interactions&lt;/li&gt;
&lt;li&gt;  Frequent state changes&lt;/li&gt;
&lt;li&gt;  Unstable network connections&lt;/li&gt;
&lt;li&gt;  Risk of refresh, tab switching, or browser crashes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Therefore, the Academic Suite frontend architecture is designed with a focus on &lt;strong&gt;resilience, state clarity, and separation of concerns&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  7.1 Modern React Setup with Vite
&lt;/h2&gt;

&lt;p&gt;Academic Suite uses &lt;strong&gt;Vite&lt;/strong&gt; as the primary build tool for the React application.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Vite?
&lt;/h3&gt;

&lt;p&gt;Compared to Create React App (CRA), Vite offers several significant advantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Extremely Fast Dev Server Startup&lt;/strong&gt;&lt;br&gt;
Vite leverages native browser ES Modules, making startup time nearly instant (&amp;lt; 300ms).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Efficient Production Build&lt;/strong&gt;&lt;br&gt;
For production builds, Vite uses Rollup which is proven to be stable and optimal.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This approach increases developer productivity, especially on medium to large-scale projects.&lt;/p&gt;




&lt;h3&gt;
  
  
  Frontend Folder Structure
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;src/&lt;/code&gt; folder structure is organized to clearly separate responsibilities:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;src/
├── components/         # Reusable UI components
│   ├── ui/             # shadcn/ui primitives
│   └── ...             # Custom components
├── pages/              # Page-level components (routing targets)
├── lib/                # Utilities &amp;amp; configuration (Axios, helpers)
├── stores/             # Global client state (Zustand)
└── hooks/              # Custom hooks (useCountdown, useExamTimer)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This structure makes it easy to scale the application without making the code difficult to maintain.&lt;/p&gt;




&lt;h2&gt;
  
  
  7.2 State Management Strategy
&lt;/h2&gt;

&lt;p&gt;One common mistake in React applications is &lt;strong&gt;treating all state the same way&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In Academic Suite, state is separated into three main categories based on its nature and lifecycle.&lt;/p&gt;




&lt;h3&gt;
  
  
  A. Server State (Data from API)
&lt;/h3&gt;

&lt;p&gt;For data originating from the backend such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Quiz lists&lt;/li&gt;
&lt;li&gt;  User profiles&lt;/li&gt;
&lt;li&gt;  Grade history&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Academic Suite uses &lt;strong&gt;TanStack Query (React Query)&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;isLoading&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useQuery&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;queryKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;quizzes&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;queryFn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;fetchQuizzes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Advantages of React Query
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Automatic Caching&lt;/strong&gt;&lt;br&gt;
Data doesn't need to be fetched repeatedly when the user switches pages.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Background Refetching&lt;/strong&gt;&lt;br&gt;
Data is automatically updated when the window becomes active again.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Built-in Loading &amp;amp; Error State&lt;/strong&gt;&lt;br&gt;
Reduces the need for manual state.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This approach makes the frontend more efficient and consistent with the backend.&lt;/p&gt;




&lt;h3&gt;
  
  
  B. Global Client State (Session &amp;amp; User Identity)
&lt;/h3&gt;

&lt;p&gt;For global data that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Is needed on many pages&lt;/li&gt;
&lt;li&gt;  Rarely changes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;such as logged-in user information, Academic Suite uses &lt;strong&gt;Zustand&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;File: &lt;code&gt;stores/authStore.ts&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;AuthState&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
  &lt;span class="nx"&gt;login&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;
  &lt;span class="nx"&gt;logout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;useAuthStore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;create&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;AuthState&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="kd"&gt;set&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;login&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Decode JWT and set user&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;logout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&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;Zustand was chosen because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Simple API&lt;/li&gt;
&lt;li&gt;  Minimal boilerplate&lt;/li&gt;
&lt;li&gt;  Easy to understand and maintain&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  C. Local UI State
&lt;/h3&gt;

&lt;p&gt;For state relevant only to a single component, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Modal open or closed&lt;/li&gt;
&lt;li&gt;  Form input values&lt;/li&gt;
&lt;li&gt;  Small UI toggles&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;simply use local &lt;code&gt;useState&lt;/code&gt; or &lt;code&gt;useReducer&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This approach keeps state close to the components that need it.&lt;/p&gt;




&lt;h2&gt;
  
  
  7.3 Routing &amp;amp; Access Protection
&lt;/h2&gt;

&lt;p&gt;Academic Suite uses a routing system with &lt;strong&gt;role-based protection&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;At the routing level, page access is restricted using the &lt;code&gt;ProtectedRoute&lt;/code&gt; wrapper component.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Route&lt;/span&gt;
  &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/quizzes/new"&lt;/span&gt;
  &lt;span class="na"&gt;element&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ProtectedRoute&lt;/span&gt; &lt;span class="na"&gt;allowedRoles&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;admin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;teacher&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;QuizBuilderPage&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;ProtectedRoute&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="si"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Responsibility of &lt;code&gt;ProtectedRoute&lt;/code&gt;
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt; Check user login status&lt;/li&gt;
&lt;li&gt; Retrieve role from global state&lt;/li&gt;
&lt;li&gt; Ensure role matches &lt;code&gt;allowedRoles&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt; Redirect to login page or unauthorized if failed&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This approach aligns frontend authorization with RBAC on the backend.&lt;/p&gt;




&lt;h2&gt;
  
  
  7.4 UI Framework: shadcn/ui &amp;amp; Tailwind CSS
&lt;/h2&gt;

&lt;p&gt;Academic Suite does not use heavy dependency-based UI libraries like MUI.&lt;/p&gt;

&lt;p&gt;Instead, it uses &lt;strong&gt;shadcn/ui&lt;/strong&gt; combined with &lt;strong&gt;Tailwind CSS&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Uniqueness of shadcn/ui:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Not an npm library&lt;/li&gt;
&lt;li&gt;  Component code is &lt;em&gt;copied&lt;/em&gt; directly into the project&lt;/li&gt;
&lt;li&gt;  Fully modifiable&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With this approach:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  The team has full control over the UI&lt;/li&gt;
&lt;li&gt;  Not tied to external library updates&lt;/li&gt;
&lt;li&gt;  Easy to make small adjustments without hacks&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Chapter Summary
&lt;/h2&gt;

&lt;p&gt;In this chapter, we built the foundation of the Academic Suite &lt;strong&gt;frontend architecture&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;We discussed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Modern React setup with Vite&lt;/li&gt;
&lt;li&gt;  Separated and clear state management strategies&lt;/li&gt;
&lt;li&gt;  Role-based routing protection&lt;/li&gt;
&lt;li&gt;  Flexible and controlled UI approach&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With this architecture, the frontend is ready to face high interaction loads and real-world exam scenarios.&lt;/p&gt;

&lt;p&gt;In &lt;strong&gt;Chapter 8&lt;/strong&gt;, we will enter the most complex part of the frontend: the &lt;strong&gt;exam execution page&lt;/strong&gt;, including timers, autosave, and crash handling.&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>frontend</category>
      <category>javascript</category>
      <category>react</category>
    </item>
    <item>
      <title>Data Integrity &amp; Anti-Cheating</title>
      <dc:creator>Insight 105</dc:creator>
      <pubDate>Fri, 02 Jan 2026 10:31:12 +0000</pubDate>
      <link>https://dev.to/insight105/data-integrity-anti-cheating-36gp</link>
      <guid>https://dev.to/insight105/data-integrity-anti-cheating-36gp</guid>
      <description>&lt;p&gt;Online exam systems almost always face two main enemies:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Creative cheating behavior&lt;/strong&gt; from test-takers&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Unreliable network conditions&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Therefore, the exam system backend must be designed with a &lt;strong&gt;paranoid by design&lt;/strong&gt; mindset:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Never trust data from the client&lt;/li&gt;
&lt;li&gt;  Assume the connection can drop at any time&lt;/li&gt;
&lt;li&gt;  Ensure the system remains consistent even if partial failures occur&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this chapter, we will discuss the Academic Suite strategy in maintaining &lt;strong&gt;exam data integrity&lt;/strong&gt; whilst minimizing opportunities for cheating.&lt;/p&gt;




&lt;h2&gt;
  
  
  6.1 Async Logging for Performance and Scalability
&lt;/h2&gt;

&lt;p&gt;Most anti-cheating mechanisms are &lt;strong&gt;observational&lt;/strong&gt;, such as detecting tab switching or loss of browser focus.&lt;/p&gt;

&lt;p&gt;Every time a student switches tabs (e.g. using &lt;em&gt;Alt + Tab&lt;/em&gt;), the frontend sends a &lt;code&gt;FOCUS_LOST&lt;/code&gt; event to the backend.&lt;/p&gt;

&lt;p&gt;The problem is, these events can occur &lt;strong&gt;massively and simultaneously&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Imagine:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  1,000 students&lt;/li&gt;
&lt;li&gt;  1 exam&lt;/li&gt;
&lt;li&gt;  Alt-tabbing at nearly the same time&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the backend processes this logging synchronously, the database can become a bottleneck and slow down main requests.&lt;/p&gt;

&lt;h3&gt;
  
  
  Solution: Asynchronous Logging with Goroutines
&lt;/h3&gt;

&lt;p&gt;Academic Suite uses &lt;strong&gt;goroutines&lt;/strong&gt; to record events in a &lt;em&gt;fire-and-forget&lt;/em&gt; manner.&lt;/p&gt;

&lt;p&gt;Implementation in &lt;code&gt;handlers/log.go&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;LogEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;eventType&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&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;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;database&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DB&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;log&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;With this approach:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  HTTP requests can be completed immediately&lt;/li&gt;
&lt;li&gt;  Logging does not hinder main system performance&lt;/li&gt;
&lt;li&gt;  The system remains responsive even if there is a surge in events&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This approach is highly effective for non-critical data that serves as an audit trail.&lt;/p&gt;




&lt;h2&gt;
  
  
  6.2 Answer Integrity (Autosave &amp;amp; Idempotency)
&lt;/h2&gt;

&lt;p&gt;A question that almost always arises from students is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"If the internet goes down, will my answers be lost?"&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Academic Suite addresses this concern with two main mechanisms.&lt;/p&gt;

&lt;h3&gt;
  
  
  Autosave per Question
&lt;/h3&gt;

&lt;p&gt;Every time a student selects or changes an answer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  The frontend sends a request to the backend immediately&lt;/li&gt;
&lt;li&gt;  The &lt;code&gt;/api/attempts/:id/answers&lt;/code&gt; endpoint saves the change&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this way, every answer is saved almost in real-time.&lt;/p&gt;

&lt;h3&gt;
  
  
  Idempotency
&lt;/h3&gt;

&lt;p&gt;Slow or unstable connections can cause:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Requests to be sent repeatedly&lt;/li&gt;
&lt;li&gt;  Buttons to be clicked multiple times&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The backend must ensure that this condition &lt;strong&gt;does not cause data duplication&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Idempotency implementation is done with an &lt;em&gt;upsert&lt;/em&gt; pattern:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// handlers/attempt.go&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;database&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DB&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"attempt_id = ? AND question_id = ?"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;First&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;existing&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="n"&gt;existing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SelectedOptionID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;newValue&lt;/span&gt;
    &lt;span class="n"&gt;database&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DB&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;existing&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;With this approach:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Only the latest answer is saved&lt;/li&gt;
&lt;li&gt;  Data remains consistent even if requests are sent repeatedly&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  6.3 Force Submit as Fail-Safe Mechanism
&lt;/h2&gt;

&lt;p&gt;The worst-case scenario in an online exam is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Exam time runs out&lt;/li&gt;
&lt;li&gt;  Student's browser crashes or closes&lt;/li&gt;
&lt;li&gt;  Submit request is never sent&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Without additional mechanisms, the student's attempt can remain stuck in &lt;code&gt;Active&lt;/code&gt; status forever.&lt;/p&gt;

&lt;h3&gt;
  
  
  Solution: Force Submit
&lt;/h3&gt;

&lt;p&gt;Academic Suite provides a special endpoint for teachers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;POST /api/attempts/:id/force-submit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This endpoint will:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Retrieve all saved answers&lt;/li&gt;
&lt;li&gt; Calculate the score based on that data&lt;/li&gt;
&lt;li&gt; Change the attempt status to &lt;code&gt;Submitted&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Thus:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  No attempt is stuck in an invalid status&lt;/li&gt;
&lt;li&gt;  Teachers have full control over exam completion&lt;/li&gt;
&lt;li&gt;  The system remains consistent even if client-side failure occurs&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  6.4 Client Action Restrictions (Disable Right Click &amp;amp; Copy)
&lt;/h2&gt;

&lt;p&gt;As an &lt;strong&gt;additional anti-cheating layer&lt;/strong&gt;, Academic Suite also restricts several client-side actions during the exam, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Right Click&lt;/li&gt;
&lt;li&gt;  Copy text (Ctrl+C / Cmd+C)&lt;/li&gt;
&lt;li&gt;  Select text in the question area&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The goal is &lt;strong&gt;not for absolute security&lt;/strong&gt;, but to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Reduce casual cheating&lt;/li&gt;
&lt;li&gt;  Increase friction for participants intending to copy questions&lt;/li&gt;
&lt;li&gt;  Support behavior-based monitoring&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Frontend Implementation
&lt;/h3&gt;

&lt;p&gt;This restriction is applied &lt;strong&gt;only when exam status is active&lt;/strong&gt;, and is automatically removed after the exam finishes.&lt;/p&gt;

&lt;p&gt;Example implementation in React:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;prevent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;contextmenu&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;prevent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;copy&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;prevent&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;removeEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;contextmenu&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;prevent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;removeEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;copy&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;prevent&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="p"&gt;[])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Important Note
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  These restrictions are &lt;strong&gt;easy to bypass by experienced users&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;  Therefore, this feature &lt;strong&gt;does not stand alone&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Its main value is as an &lt;strong&gt;additional layer (defense in depth)&lt;/strong&gt; combined with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Behavior logging&lt;/li&gt;
&lt;li&gt;  Server-side authority&lt;/li&gt;
&lt;li&gt;  Post-exam analysis&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;This approach aligns with modern exam system principles: &lt;em&gt;make cheating difficult, don't claim it's impossible&lt;/em&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Chapter Summary
&lt;/h2&gt;

&lt;p&gt;In this chapter, we close the entire discussion of the Academic Suite backend with a focus on &lt;strong&gt;system resilience&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;We discussed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Asynchronous logging for performance&lt;/li&gt;
&lt;li&gt;  Autosave and idempotency for answer integrity&lt;/li&gt;
&lt;li&gt;  Fail-safe mechanisms through force submit&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With this approach, the exam system becomes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Secure&lt;/li&gt;
&lt;li&gt;  Resilient to network disruptions&lt;/li&gt;
&lt;li&gt;  Difficult to manipulate&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the next section, we will switch to &lt;strong&gt;frontend implementation&lt;/strong&gt; and start building the user interface.&lt;/p&gt;

&lt;p&gt;Part 3 begins with &lt;strong&gt;Chapter 7: React Application Architecture&lt;/strong&gt;.&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>backend</category>
      <category>security</category>
      <category>performance</category>
    </item>
    <item>
      <title>The Exam Engine</title>
      <dc:creator>Insight 105</dc:creator>
      <pubDate>Wed, 31 Dec 2025 18:44:13 +0000</pubDate>
      <link>https://dev.to/insight105/the-exam-engine-206c</link>
      <guid>https://dev.to/insight105/the-exam-engine-206c</guid>
      <description>&lt;h2&gt;
  
  
  Chapter 5: The Exam Engine
&lt;/h2&gt;

&lt;p&gt;This chapter is the &lt;strong&gt;most crucial core&lt;/strong&gt; of the entire LMS system. At this stage, Academic Suite no longer just manages static data, but begins to handle &lt;strong&gt;time, status, and user behavior in real-time&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The exam engine is responsible for ensuring that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Exams can only be accessed at the specified time&lt;/li&gt;
&lt;li&gt;  Every student receives a fair time allocation&lt;/li&gt;
&lt;li&gt;  Exam status remains consistent even in the event of a refresh, reconnect, or network disruption&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Small errors in this part can result in &lt;strong&gt;grading unfairness&lt;/strong&gt; or even &lt;strong&gt;exam system leaks&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  5.1 Design Philosophy: Quiz vs ExamBatch
&lt;/h2&gt;

&lt;p&gt;A common mistake in online exam systems is mixing &lt;strong&gt;question content&lt;/strong&gt; and &lt;strong&gt;exam schedules&lt;/strong&gt; into a single entity.&lt;/p&gt;

&lt;p&gt;Academic Suite explicitly separates the two:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Quiz&lt;/strong&gt;&lt;br&gt;
A collection of questions and answer options. It is &lt;em&gt;static&lt;/em&gt; and reusable.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;ExamBatch&lt;/strong&gt;&lt;br&gt;
A representation of an exam administration for a specific context (class, time, token). It is &lt;em&gt;dynamic&lt;/em&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Benefits of This Separation
&lt;/h3&gt;

&lt;p&gt;With this separation, a single quiz can be used multiple times without data duplication:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Quiz "Basic Math" → Class A Batch (Monday 08:00)&lt;/li&gt;
&lt;li&gt;  Same Quiz → Class B Batch (Tuesday 10:00)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This approach makes the system:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  More flexible&lt;/li&gt;
&lt;li&gt;  Easier to scale&lt;/li&gt;
&lt;li&gt;   safer against schedule changes&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  5.2 Exam State Machine
&lt;/h2&gt;

&lt;p&gt;An exam is a &lt;strong&gt;time-based&lt;/strong&gt; process, so its status must change automatically:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;scheduled&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;active&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;finished&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instead of using a &lt;em&gt;cron job&lt;/em&gt; to periodically update batch status, Academic Suite uses a &lt;strong&gt;Lazy State Update&lt;/strong&gt; approach.&lt;/p&gt;

&lt;h3&gt;
  
  
  Lazy State Update
&lt;/h3&gt;

&lt;p&gt;Exam status is evaluated &lt;strong&gt;every time there is a request&lt;/strong&gt;, based on the current server time.&lt;/p&gt;

&lt;p&gt;This implementation is found in &lt;code&gt;handlers/batch.go&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;GetBatches&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;fiber&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;now&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Now&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;now&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;After&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;batch&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StartTime&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Before&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;batch&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EndTime&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;batch&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"active"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;After&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;batch&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EndTime&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;batch&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"finished"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Benefits of This Approach
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  Does not require a background worker&lt;/li&gt;
&lt;li&gt;  No risk of out-of-sync status&lt;/li&gt;
&lt;li&gt;  Logic is simple and easy to test&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The exam status is always consistent with the actual server time.&lt;/p&gt;




&lt;h2&gt;
  
  
  5.3 Secure Timer: Server-Side Time Authority
&lt;/h2&gt;

&lt;p&gt;One fatal mistake in online exam systems is &lt;strong&gt;trusting the time on the client side&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The clock on a student's browser or operating system can be manipulated, so a JavaScript-based timer cannot be used as a source of truth.&lt;/p&gt;

&lt;h3&gt;
  
  
  Solution: Server-Side Time Authority
&lt;/h3&gt;

&lt;p&gt;Academic Suite makes the &lt;strong&gt;server the sole source of truth for time&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The frontend periodically calls the endpoint:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET /api/attempts/:id/time
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The backend then calculates the remaining time based on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Exam start time&lt;/li&gt;
&lt;li&gt;  Total pause time&lt;/li&gt;
&lt;li&gt;  Batch duration
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;elapsed&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;attempt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StartedAt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;effectiveElapsed&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;elapsed&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;attempt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TotalPausedTime&lt;/span&gt;
&lt;span class="n"&gt;remaining&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;batch&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Duration&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;effectiveElapsed&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If &lt;code&gt;remaining &amp;lt;= 0&lt;/code&gt;, the backend decisively:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Rejects new answers&lt;/li&gt;
&lt;li&gt;  Automatically ends the attempt&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With this approach, time manipulation on the client side becomes irrelevant.&lt;/p&gt;




&lt;h2&gt;
  
  
  5.4 Exam Pause &amp;amp; Resume Features
&lt;/h2&gt;

&lt;p&gt;In real-world conditions, exams can be interrupted by external factors such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Power outages&lt;/li&gt;
&lt;li&gt;  Mass network disruptions&lt;/li&gt;
&lt;li&gt;  Emergencies&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Academic Suite provides a &lt;strong&gt;Freeze / Resume Batch&lt;/strong&gt; feature.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pause Mechanism
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  When a batch is &lt;em&gt;paused&lt;/em&gt;, the backend records &lt;code&gt;PausedAt&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  While the pause status is active, student time does not decrease&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Resume Mechanism
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  When the batch is resumed, the time difference between &lt;code&gt;PausedAt&lt;/code&gt; and the current time is calculated&lt;/li&gt;
&lt;li&gt;  This difference is added to &lt;code&gt;TotalPausedTime&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This approach ensures that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  All students receive fair time treatment&lt;/li&gt;
&lt;li&gt;  No attempts are disadvantaged due to conditions outside the system's control&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  5.5 Exam Token
&lt;/h2&gt;

&lt;p&gt;As an additional security layer, each ExamBatch can be protected with an &lt;strong&gt;exam token&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Even if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  The student is logged in&lt;/li&gt;
&lt;li&gt;  Exam time is active&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They &lt;strong&gt;cannot start an attempt&lt;/strong&gt; without entering a valid token.&lt;/p&gt;

&lt;h3&gt;
  
  
  Benefits of Exam Tokens
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  Prevents students from entering early&lt;/li&gt;
&lt;li&gt;  Reduces the risk of exams being accessed by unauthorized parties&lt;/li&gt;
&lt;li&gt;  Gives full control to exam proctors&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These tokens are optional but highly recommended for formal exams.&lt;/p&gt;




&lt;h2&gt;
  
  
  Chapter Summary
&lt;/h2&gt;

&lt;p&gt;In this chapter, we built the &lt;strong&gt;exam engine&lt;/strong&gt; which serves as the heart of Academic Suite.&lt;/p&gt;

&lt;p&gt;We discussed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Separation of exam content and context&lt;/li&gt;
&lt;li&gt;  Time-based state machine&lt;/li&gt;
&lt;li&gt;  Timer secure from manipulation&lt;/li&gt;
&lt;li&gt;  Pause and resume mechanisms&lt;/li&gt;
&lt;li&gt;  Additional security layer through exam tokens&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;However, the exam system is not fully secure without protecting &lt;strong&gt;data integrity and exam participant behavior&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In &lt;strong&gt;Chapter 6&lt;/strong&gt;, we will discuss &lt;strong&gt;Data Integrity &amp;amp; Anti-Cheating&lt;/strong&gt; strategies, including handling reconnects, multi-tabs, and other cheating attempts.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
    </item>
    <item>
      <title>Don’t Wait for the Smoke: Why Your Database Needs a Regular ‘Service’</title>
      <dc:creator>Insight 105</dc:creator>
      <pubDate>Wed, 31 Dec 2025 05:00:32 +0000</pubDate>
      <link>https://dev.to/insight105/why-your-database-needs-regular-service-the-car-analogy-for-developers-33ie</link>
      <guid>https://dev.to/insight105/why-your-database-needs-regular-service-the-car-analogy-for-developers-33ie</guid>
      <description>&lt;p&gt;Let’s be real for a second. You wouldn’t drive your car for five years without changing the oil, right? That would be stupid. You know the engine would eventually seize up, probably in the middle of a highway, leaving you stranded and smelling like burnt rubber.&lt;/p&gt;

&lt;p&gt;Yet, I see developers treating their production databases like they’re magic black boxes that run on hopes and dreams. They deploy, dump data, and walk away. Then, when the app crawls to a halt on a Saturday night, they act surprised. "But it worked on my machine!" ...yeah, congratulations.&lt;/p&gt;

&lt;p&gt;Here is the cold, hard truth: Your database is a high-maintenance machine. Treat it like a Ferrari, or it will treat you like a junker.&lt;/p&gt;

&lt;p&gt;"But Software Doesn't Have Moving Parts"&lt;br&gt;
"But surely," I hear you ask, "it's just software. It doesn't have friction or pistons."&lt;/p&gt;

&lt;p&gt;Wrong.&lt;/p&gt;

&lt;p&gt;Your database has "moving parts"—pages, mismatched statistics, fragmented indexes, and bloated logs. Every time you INSERT, UPDATE, or DELETE, you are creating dirty oil. If you don't clean it (vacuum, reindex, update stats), the gears start to grind. The query planner—the brain of the operation—starts making bad decisions because it’s working with outdated information.&lt;/p&gt;

&lt;p&gt;The "Ghost Job" Incident&lt;br&gt;
I’ll save you the lecture and give you a real-world example instead.&lt;/p&gt;

&lt;p&gt;We once had a job in production. Simple background task. It wasn't crashing. It didn't throw a single error. But it was... stagnant. The job just wouldn't finish. We tracked it for hours. The process was alive, but it was moving at a glacial pace.&lt;/p&gt;

&lt;p&gt;We dug into the metrics. No CPU spikes. No memory leaks. Just silence.&lt;/p&gt;

&lt;p&gt;Finally, we isolated a specific query hitting a logs table. You know, that table you dump valid info into and never look at?&lt;/p&gt;

&lt;p&gt;Boom.&lt;/p&gt;

&lt;p&gt;The table had grown to millions of rows and zero indexes.&lt;/p&gt;

&lt;p&gt;What should have been a millisecond lookup was triggering a full table scan for every single iteration of the loop. The process wasn't dead; it was just trying to drink the ocean through a straw. We added one simple index, and the job that had been stuck for 24 hours finished in 10 minutes.&lt;/p&gt;

&lt;p&gt;That is why you service your database. To catch the "missing index" before it turns your production environment into a parking lot.&lt;/p&gt;

&lt;p&gt;The Bare Minimum You Should Be Doing&lt;br&gt;
If you want to sleep through the night without PagerDuty waking you up, here is your maintenance schedule:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Stop Flying Blind (Metrics)&lt;br&gt;
The Rookie Move: Waiting for a user to email you saying "the site is slow." The Pro Move: Automating your intuition. Just as you check the dipstick, look at your metrics. If you aren't tracking CPU, IOPS, and connection pools in real-time (Grafana, Datadog, I don't care what you use), you are driving blindfolded. Insight: If you don't know what your baseline 'normal' looks like, you won't know when you're overheating.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Tune Your Queries (Or They Will kill You)&lt;br&gt;
The Rookie Move: SELECT * and hoping for the best. The Pro Move: EXPLAIN ANALYZE is your best friend. Your engine needs calibration. Indexes get fragmented. Queries that worked fine with 100 rows will choke on 10 million. If you see a "Seq Scan" on a large table, that's the database screaming for help. Fix your queries, or upgrading the server won't save you.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Test Your Recovey (Backups Are For Cowards, Restores Are For Pros)&lt;br&gt;
The Rookie Move: "My cloud provider handles it." The Pro Move: Trust, but verify. Driving on bald tires is a death wish. Running a DB without a tested restore strategy is career suicide. A "snapshot" is nice, but have you ever tried to restore it? If it takes 4 hours to restore your backup, your RTO (Recovery Time Objective) is garbage. Test your brakes before you need them.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Final Words&lt;br&gt;
A neglected database is a ticking time bomb. It doesn't matter how pretty your frontend code is if the engine underneath is seizing up.&lt;/p&gt;

&lt;p&gt;Stop treating your database like a dumping ground. Service it. Tune it. Respect it. Because unlike a car, you can't just call an Uber when your production server goes down.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>horrorstory</category>
      <category>database</category>
    </item>
    <item>
      <title>Quiz Management &amp; Question Bank</title>
      <dc:creator>Insight 105</dc:creator>
      <pubDate>Tue, 30 Dec 2025 10:06:16 +0000</pubDate>
      <link>https://dev.to/insight105/quiz-management-question-bank-28p3</link>
      <guid>https://dev.to/insight105/quiz-management-question-bank-28p3</guid>
      <description>&lt;p&gt;After the authentication and authorization system is implemented, the primary activity in a Learning Management System (LMS) is &lt;strong&gt;creating and managing exam content&lt;/strong&gt;. At this stage, the system begins to handle complex and interrelated data.&lt;/p&gt;

&lt;p&gt;In this chapter, we will discuss how Academic Suite manages &lt;strong&gt;quizzes, questions, and answer options&lt;/strong&gt; on the backend, including advanced CRUD design challenges often encountered in real-world applications.&lt;/p&gt;




&lt;h2&gt;
  
  
  4.1 Relationship Model of Quiz, Question, and Option
&lt;/h2&gt;

&lt;p&gt;Conceptually, the quiz data structure can be described as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  One &lt;strong&gt;Quiz&lt;/strong&gt; has many &lt;strong&gt;Questions&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;  One &lt;strong&gt;Question&lt;/strong&gt; has many &lt;strong&gt;Options&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;  One &lt;strong&gt;Option&lt;/strong&gt; can be marked as the correct answer&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These &lt;em&gt;nested relations&lt;/em&gt; appear simple during initial data creation but become significantly more complex when entering the &lt;strong&gt;editing&lt;/strong&gt; process.&lt;/p&gt;




&lt;h2&gt;
  
  
  4.2 Main Challenge: Nested Updates
&lt;/h2&gt;

&lt;p&gt;One of the biggest challenges in CRUD applications is handling &lt;strong&gt;Complex Data Editing&lt;/strong&gt; features.&lt;/p&gt;

&lt;p&gt;Imagine the following scenario:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  A teacher opens the quiz editor&lt;/li&gt;
&lt;li&gt;  Changes the quiz title&lt;/li&gt;
&lt;li&gt;  Deletes question number 2&lt;/li&gt;
&lt;li&gt;  Edits the text of question number 5&lt;/li&gt;
&lt;li&gt;  Adds a new question at the end&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All these changes are sent to the backend in a single click of the &lt;strong&gt;Save&lt;/strong&gt; button.&lt;/p&gt;

&lt;p&gt;The question is: &lt;em&gt;how should the backend handle this condition?&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Two Common Approaches
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Partial Update (Diffing)&lt;/strong&gt;
The backend tries to compare the old data and new data, then only updates the changed parts.&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;*   Complex
*   Hard to maintain
*   Prone to bugs in nested relations
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Full Replacement&lt;/strong&gt;
The backend deletes all old data and then re-inserts the new data.&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;*   Simple implementation
*   Risk of losing data references
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;h2&gt;
  
  
  4.3 Academic Suite Strategy: Modified Full Replacement
&lt;/h2&gt;

&lt;p&gt;Academic Suite uses a &lt;strong&gt;Modified Full Replacement&lt;/strong&gt; approach wrapped in a &lt;strong&gt;database transaction&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The goal is to maintain a balance between:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Implementation simplicity&lt;/li&gt;
&lt;li&gt;  Data consistency&lt;/li&gt;
&lt;li&gt;  Safe saving process&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The entire update process is performed &lt;strong&gt;atomically&lt;/strong&gt;: if one step fails, all changes are rolled back.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;UpdateQuiz&lt;/code&gt; Implementation
&lt;/h3&gt;

&lt;p&gt;This logic is implemented in &lt;code&gt;handlers/quiz.go&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;database&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DB&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Transaction&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;tx&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;gorm&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DB&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// 1. Update main quiz data (title, duration, etc.)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;tx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quiz&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// 2. Delete all old questions&lt;/span&gt;
    &lt;span class="n"&gt;tx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Question&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt; &lt;span class="s"&gt;"quiz_id = ?"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// 3. Re-insert questions from request&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Questions&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QuizID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;
        &lt;span class="n"&gt;tx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;q&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="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This approach ensures that the stored quiz structure is always consistent with the data sent by the frontend.&lt;/p&gt;




&lt;h3&gt;
  
  
  Critical Note: Risk of Question Deletion
&lt;/h3&gt;

&lt;p&gt;The &lt;em&gt;delete and recreate&lt;/em&gt; approach has important consequences:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Question IDs will change&lt;/strong&gt; every time the quiz is edited&lt;/li&gt;
&lt;li&gt;  If the &lt;code&gt;answers&lt;/code&gt; or &lt;code&gt;attempts&lt;/code&gt; tables reference &lt;code&gt;question_id&lt;/code&gt;, student grade data can be corrupted&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Best Practice
&lt;/h3&gt;

&lt;p&gt;In a production system:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Quizzes that are already &lt;code&gt;Active&lt;/code&gt; or have &lt;code&gt;Attempts&lt;/code&gt; should be &lt;strong&gt;locked (frozen)&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;  Another alternative is to use &lt;strong&gt;soft delete&lt;/strong&gt; or &lt;strong&gt;versioning&lt;/strong&gt; for questions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This approach prevents changes to the quiz structure that could damage exam history.&lt;/p&gt;




&lt;h2&gt;
  
  
  4.4 Question Import Feature from Excel
&lt;/h2&gt;

&lt;p&gt;To increase teacher productivity, Academic Suite provides a &lt;strong&gt;question import feature from Excel files&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Typing dozens of questions via a web form is inefficient, so the &lt;code&gt;.xlsx&lt;/code&gt; format becomes a practical solution.&lt;/p&gt;

&lt;p&gt;Library used:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;github.com/xuri/excelize/v2&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Excel Data Validation Challenges
&lt;/h3&gt;

&lt;p&gt;Excel files are very free-form:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Columns can be empty&lt;/li&gt;
&lt;li&gt;  Formatting can be inconsistent&lt;/li&gt;
&lt;li&gt;  Correct answers can be in the wrong position&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Therefore, the backend performs validation &lt;strong&gt;row by row&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;rows&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;7&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;errors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;errors&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;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="s"&gt;"Row %d: Incomplete columns"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="k"&gt;continue&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// Further parsing and validation&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This approach allows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Valid rows to still be saved&lt;/li&gt;
&lt;li&gt;  Problematic rows to be reported specifically to the user&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The user experience becomes better without sacrificing data consistency.&lt;/p&gt;




&lt;h2&gt;
  
  
  4.5 Data Fetching with Eager Loading
&lt;/h2&gt;

&lt;p&gt;To display a quiz along with all questions and answer options, Academic Suite uses the &lt;strong&gt;eager loading&lt;/strong&gt; feature from GORM.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// Fetch Quiz + Questions + Options in a single query&lt;/span&gt;
&lt;span class="n"&gt;database&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DB&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
    &lt;span class="n"&gt;Preload&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Questions"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
    &lt;span class="n"&gt;Preload&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Questions.Options"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
    &lt;span class="n"&gt;First&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quiz&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"id = ?"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This approach prevents the &lt;strong&gt;N+1 Query Problem&lt;/strong&gt;, where the application has to run many additional queries for interrelated data.&lt;/p&gt;

&lt;p&gt;With eager loading, application performance remains stable even if the number of questions in the quiz is quite large.&lt;/p&gt;




&lt;h2&gt;
  
  
  Chapter Summary
&lt;/h2&gt;

&lt;p&gt;In this chapter, we built the foundation of a stable and scalable &lt;strong&gt;Question Bank and Quiz Management&lt;/strong&gt; system.&lt;/p&gt;

&lt;p&gt;We discussed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Challenges of nested updates&lt;/li&gt;
&lt;li&gt;  Transaction strategies to maintain data consistency&lt;/li&gt;
&lt;li&gt;  Risks of editing active quizzes&lt;/li&gt;
&lt;li&gt;  User-friendly Excel import features&lt;/li&gt;
&lt;li&gt;  Eager loading techniques for optimal performance&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In &lt;strong&gt;Chapter 5&lt;/strong&gt;, we will enter the heart of the online exam system: the &lt;strong&gt;Exam Engine&lt;/strong&gt;, including timer settings, exam status, and precise grading mechanisms.&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>backend</category>
      <category>database</category>
    </item>
  </channel>
</rss>
