feat(blog): 更新博客文章,分享全栈开发者的技术选型反思与经验
This commit is contained in:
@@ -1,78 +1,76 @@
|
||||
---
|
||||
layout: "@/layouts/BlogPostLayout.astro"
|
||||
title: "Stop Being Held Hostage by 'Best Practices': Confessions of a Full-Stack Developer's Tech Stack Struggles"
|
||||
description: "A full-stack developer's honest reflection on getting trapped by chasing 'best practices' while building a simple 30-endpoint project. This article explores the cognitive load of heavy frameworks, the Monorepo trap, and proposes a practical two-tier tech stack selection strategy."
|
||||
date: "2026-01-08"
|
||||
image: "https://images.unsplash.com/photo-1518770660439-4636190af475?q=80&w=1470&auto=format&fit=crop"
|
||||
tags: ["Tech Stack", "Full-Stack Development", "Framework Selection", "Best Practices", "Developer Experience"]
|
||||
tagId: ["tech-stack", "fullstack", "framework", "best-practices", "developer-experience"]
|
||||
category: "Technology"
|
||||
categoryId: "technology"
|
||||
readTime: "6 min read"
|
||||
---
|
||||
# All This Tinkering... For What? Engineering Reflections from a Full-Stack Developer
|
||||
|
||||
> **Foreword:**
|
||||
> I am a developer who transitioned from Frontend to Node.js Full-Stack. This article is simply a summary of my recent experiences and reflections while developing a project. Given my limited knowledge and perspective, the views expressed here may not be universally "correct" or represent industry standards. This is just a personal debrief after stepping into countless pitfalls, shared in the hope of exchanging ideas with the community and providing a reference for those facing similar dilemmas. If there are any inaccuracies, please feel free to correct me in the comments.
|
||||
> *A log of the soul-crushing details I encountered during a recent project setup. This is a summary of my own internal tug-of-war—lessons learned the hard way through endless trial and error. It might not be the "correct" way, but every word was paid for in lost time.*
|
||||
|
||||
Recently, I set out to build a small bookmark-style tool with only about 30 endpoints. I thought it would take two weeks; instead, I spent over a month just "wrestling" with the tech stack.
|
||||
I recently set out to build a simple bookmarking tool. It only needed about 30 endpoints, yet I spent nearly a month agonizing over the tech stack. I felt like I was wandering through a dark forest, sprinting toward every glimmer of light only to find a new pitfall waiting for me.
|
||||
|
||||
I felt like a hunter lost in a technical fog: wherever I saw a light (a new tool or an "expert" opinion), I rushed toward it, only to find a deeper pit hidden behind every glow.
|
||||
### Step 1: Chasing the "Mainstream" and Feeling the Friction
|
||||
|
||||
## 1. Chasing Trends is the Start of Internal Friction
|
||||
It started because I wanted to build a side project. In my day job, I use Vue; it’s second nature to me. But everywhere I looked online, the consensus was: **"Next.js + React + shadcn-ui"** is the gold standard. Great ecosystem, endless components, future-proof.
|
||||
|
||||
I started by following the crowd and chose **Next.js + NestJS + shadcn-ui**. I thought, "Since everyone says this is the 'Full-Stack Gold Standard,' I can't go wrong." The reality, however, gave me a swift wake-up call.
|
||||
I told myself: *Don’t get stuck in your comfort zone. Try something new.* So, I benched Vue and picked up React. I was immediately hit by **choice paralysis.**
|
||||
|
||||
In Next.js, I wasted a whole week just deciding on a data-fetching and state management solution (SWR vs. Zustand?). Once I finally started, I was overwhelmed by the complexity of Server Components (RSC) vs. Client Components—constantly defining `"use client"`, fixing mysterious Hydration errors, and manually managing state dependencies while optimizing endless callback functions.
|
||||
It wasn't just a choice between A and B; it was a choice between five different ways to do everything. I spent more time reading docs and comparisons than writing logic:
|
||||
|
||||
I kept thinking: **I just want to write some simple business logic. Why am I spending 80% of my energy dealing with the overhead of the framework?**
|
||||
* Do I fetch data with **SWR** or **TanStack Query**?
|
||||
* Is global state better in **Zustand**, **Redux**, or **Jotai**?
|
||||
* How do I bridge the gap between server and client data?
|
||||
|
||||
## 2. The Heavier the Framework, the Heavier the Cognitive Load
|
||||
Instead of building features, I was researching "how to build." To make matters worse, I kept hitting those cryptic **"Hydration Errors."** One refresh, one error, and an hour gone trying to find the mismatch.
|
||||
|
||||
Later, I switched the frontend to Nuxt, which was indeed smoother. But on the backend, I stuck with **NestJS**, chasing so-called "standardization" and "enterprise engineering."
|
||||
The most draining part was tagging everything with `"use client"`. I felt less like a developer and more like a clerk labeling boxes. I kept thinking: **"If most of this ends up running on the client anyway, why am I using a framework that splits the stack so aggressively and demands such high mental overhead?"**
|
||||
|
||||
But I only had 30 endpoints. The logic was incredibly simple. In NestJS, I was forced to write Controllers, Services, Modules, DTOs... the amount of code tripled. Even worse was the **ESM compatibility issue**. NestJS still clings to the CommonJS dream, leading to constant configuration errors when I tried to use modern ESM-only libraries. To run a simple TypeScript Worker thread, I had to spend hours researching ESM compilers.
|
||||
### Step 2: Retreating to Comfort—and the Fear of Missing Out
|
||||
|
||||
The most frustrating part was **Swagger integration**. Most people prefer Zod for validation now, but Swagger is deeply coupled with the Class-Validator (Decorator) pattern. To get Swagger to recognize my Zod schemas and generate documentation, I had to manually write adapters and custom decorators.
|
||||
I went back to my familiar Vue ecosystem and fired up Nuxt. Suddenly, I could breathe. My productivity skyrocketed.
|
||||
|
||||
**I felt like I wasn't building a product; I was repairing a broken tractor with incompatible parts.**
|
||||
But the peace didn't last. I’d see another post praising the Next.js ecosystem and start doubting myself: **"Am I choosing the wrong path? Am I falling behind?"** I gave Next.js another shot for a few days, and like clockwork, all those petty, nagging frustrations returned.
|
||||
|
||||
## 3. Monorepo: The "Tender Trap" for Indie Developers
|
||||
That’s when I realized: **Tech isn't about "better" or "worse"; it’s about fit.** Trust your "handfeel." That sense of flow (or lack thereof) doesn't lie.
|
||||
|
||||
To pursue "code reuse," I even set up a **Monorepo**.
|
||||
### Step 3: The "Professionalism" Trap
|
||||
|
||||
I thought: *Front-end and back-end sharing types, enums, and error codes—how elegant!* The reality: trying to get a pure ESM frontend to share a package with a non-pure ESM backend plunged me into a bottomless pit of build configurations. Due to the NestJS environment, I had to compile and export the shared package every time I made a change, making frequent debugging and code modification an absolute nightmare.
|
||||
Once the frontend was settled, I moved to the backend. I chose **NestJS** because it’s billed as the most "Enterprise-grade" option. To make it even more "professional," I forced it into a **Monorepo**. I effectively built myself a prison:
|
||||
|
||||
Code that should have taken one minute to write took ten because I was busy dealing with cross-package debugging, TS type synchronization, and build logic.
|
||||
* **Immense Friction:** Changing a single shared enum or type meant re-building, waiting for workspace syncs, and restarting services. A 10-second change turned into a 1-minute wait.
|
||||
* **Compatibility Hell:** NestJS is still clinging to CommonJS. Trying to use a pure ESM library or running a TS Worker thread resulted in config errors that made me question my career choices.
|
||||
* **Ceremony Over Substance:** For 30 endpoints, I was writing endless Controllers, Services, Modules, and DTOs. The lines of code tripled, but the core logic stayed exactly the same.
|
||||
* **The Swagger Tax:** I wanted to use Zod for validation, but Swagger only recognizes decorators (class-validator). I ended up maintaining two nearly identical data definitions just to have an API doc.
|
||||
|
||||
**I finally realized: Monorepos are built to solve "organizational collaboration." For an indie developer, they are often a productivity killer.**
|
||||
**I traded my immediate efficiency for the "advantages of a large team" that I don't actually have.** I wanted speed; the framework demanded "maintainability" for a scale I'll likely never hit.
|
||||
|
||||
## 4. Returning to Pragmatism: My "Two-Tier Strategy"
|
||||
### Step 4: Stripping it Down and Losing My Way
|
||||
|
||||
At the end of all this exhaustion, I reflected: Is there a perfect framework? The answer is no; there is only the *suitable* one. Consequently, I have simplified my selection logic into two tiers:
|
||||
I ditched the heavy frameworks for **Fastify**, thinking I’d keep it lean. But I quickly discovered that the problem wasn't just "weight"—it was **"the anxiety of absolute freedom."**
|
||||
|
||||
* **Tier A: Rapid Validation (MVP / Personal Projects)**
|
||||
**Stack: Nuxt All-in-One.** Don't even separate the frontend and backend. Nuxt's built-in Server API (Nitro) is more than enough for small to medium businesses. Types are naturally shared, and there are no CORS or build-sync headaches. At the validation stage, **"Speed" is a hundred times more important than "Elegance."**
|
||||
Fastify is liberating, but for someone used to structure, freedom is a burden:
|
||||
|
||||
* **Tier B: Complex Business (Large Projects / Team Collaboration)**
|
||||
**Stack: Nuxt + NestJS (Decoupled) + Monorepo.** Only when the business is complex enough to require strict layering, Dependency Injection (DI) for decoupling, and multi-person collaboration will I endure the "ceremony" and management costs of these heavy frameworks.
|
||||
* "Where should this file go?"
|
||||
* "How do I organize this into a plugin?"
|
||||
* Logging, queues, auth—everything NestJS gave me for free now required me to find, integrate, and debug a third-party library.
|
||||
|
||||
I hated the rules of heavy frameworks, yet I craved their structure. My mindset was completely torn.
|
||||
|
||||
### The Epiphany: Tech is a Tool, Not a Totem
|
||||
|
||||
## 5. A Side Note: A New Hope in AdonisJS
|
||||
One night, working late, I asked myself: **"Why am I doing this? I just wanted to build a simple tool."**
|
||||
|
||||
Just as I was summarizing these strategies, I stumbled upon a new framework—**AdonisJS**. Many developers describe it as the "Laravel of Node.js."
|
||||
Everything clicked. I was applying "Long-term Enterprise Maintenance" standards to a "Solo Rapid Prototype." It was like trying to build an eight-lane highway just to go to the grocery store around the corner.
|
||||
|
||||
I took a quick look at its philosophy, and it seems to precisely hit the pain points I mentioned: it supports ESM natively, has a powerful built-in ORM and Auth solution, and doesn't require jumping through hoops with custom adapters just to get automated Swagger documentation.
|
||||
I set a new, simple rule for myself:
|
||||
|
||||
This "Convention over Configuration" full-stack framework seems to balance development efficiency with engineering quality. I plan to use it in my next project and will share my findings once I have more experience.
|
||||
1. **For Prototypes & Small Tools:** Use **Nuxt (or a monolithic framework) exclusively.** Frontend and backend in one repo, natural type synchronization, no CORS issues, no sync friction. The goal is to *ship*.
|
||||
2. **For Complex Systems & Large Teams:** *Then* consider **Nuxt + NestJS + Monorepo.** The complexity is a fair trade for the architectural guardrails.
|
||||
|
||||
## 6. Conclusion: A Few Words of Advice
|
||||
### A New Contender: AdonisJS
|
||||
|
||||
1. **There is no perfect framework, only the one that fits the moment.** Don't expect any "star" framework to solve all your problems; they all come with a cost.
|
||||
2. **Do not easily try a tech stack you aren't familiar with during indie development or tight deadlines.** Unless you truly have the time and energy to burn. You think you're learning new tech, but you're actually burning your product's lifespan.
|
||||
3. **Be wary of "Big Tech Best Practices."** Many tools built to solve pain points in giant corporations (like Monorepos or extreme layering) only create pain points in personal projects.
|
||||
4. **Familiarity > Modernity.** Even if a framework is called "old school," if it's intuitive to you, lets you finish work early, and helps you write clearer logic with AI assistance, it is your "silver bullet."
|
||||
During this spiral, I stumbled upon **AdonisJS**. It’s often called the "Laravel of Node.js." From a quick look, it seems to hit the sweet spot: it has the structure I crave (ORM and Auth built-in) but feels modern and supports ESM natively. I might give it a spin next time.
|
||||
|
||||
**The best tech stack is the one that allows you to forget the technology itself and focus on creating value.**
|
||||
### Final Thoughts
|
||||
|
||||
Finally, the solutions I've summarized are only what fits my personal habits and current understanding; they may not work for everyone. Everyone's business scenarios and technical backgrounds are different. **If you have better ideas or different solutions, I'd love to hear them in the comments so I can learn from you too.** If I've missed anything, please let me know. Thanks in advance!
|
||||
1. **Don’t blind-follow the hype:** What works for Vercel might not work for your weekend project.
|
||||
2. **Trust your "handfeel":** If a tool makes you feel productive, that's worth more than any "State of JS" ranking.
|
||||
3. **Ship first, optimize later:** For a solo project, an un-launched architecture is just expensive fan fiction.
|
||||
4. **Watch out for "Config Friction":** If you spend more time in `.json` and `.config.js` files than in your logic, your tools are failing you.
|
||||
|
||||
This was my journey through the weeds. **My approach might be "wrong" or even a bit clumsy.** I’d love to hear how you handle the "stack anxiety." **Do you have a go-to setup that just works, or are you still searching for the "perfect" balance?**
|
||||
Reference in New Issue
Block a user