DEV Community

Cover image for Your-Projects-a-Mess-Its-Not-You-Its-Your-Frameworks-Fault
member_40446303
member_40446303

Posted on

Your-Projects-a-Mess-Its-Not-You-Its-Your-Frameworks-Fault

GitHub Home

Your Project's a Mess? It's Not You, It's Your Framework's Fault! πŸ“‚βž‘οΈπŸ›οΈ

Every programmer has had that moment. You join a new project, or you open up a project you wrote yourself six months ago, and then you feel itβ€”that familiar, suffocating chaos. πŸŒͺ️ The utils folder is stuffed with hundreds of disorganized functions, a massive services.js file mixes database queries, business logic, and third-party API calls, and route definitions are scattered throughout the codebase. You want to add a small feature, but you don't know where to put the code. You want to fix a bug, but you have to trace a variable's journey through a tangled mess of "spaghetti code." 🍝

We call this phenomenon "software entropy," or more colloquially, "project rot." How does that clean, elegant, and hopeful little project at the beginning turn, step by step, into a "big ball of mud" that no one wants to touch?

We often blame ourselves, our team, or tight deadlines. But as an old-timer who has seen too many projects succeed and fail, I want to offer a perspective that might surprise you: much of the time, it's not your fault. It's the framework you chose that set you up for failure from the very beginning.

The "Two Extremes" of Frameworks: The Endless Desert and the Gilded Cage

On the issue of project structure, I've seen two mainstream, yet flawed, framework philosophies.

Extreme 1: The Endless Desert (Unopinionated Frameworks)

Represented by micro-frameworks like Express.js or Flask. They are very flexible, small, and let you get a "Hello World" running in minutes. I love their simplicity. But when the project grows, this "freedom" becomes a disaster.

They provide almost no rules for your project structure. In theory, you could stuff all your code into a single server.js file. When your team starts to grow, the problems begin:

  • Developer A thinks database models should go in the models/ directory.
  • Developer B is used to putting them in data/entities/.
  • Developer C just defines all user-related logic and data structures directly in routes/user.js.

Everyone follows their own understanding. The result is that the project becomes a hodgepodge of competing ideas. Without a unified standard, there is no predictability. New employees need weeks or even months to figure out the project's "unwritten rules." This kind of framework is like dropping you in an endless desert. It gives you maximum freedom, but it also makes you lose your way. 🏜️

Extreme 2: The Gilded Cage (Opinionated Frameworks)

Represented by classics like Ruby on Rails or Django. They are the epitome of the "convention over configuration" philosophy. They prescribe everything for you: where models must go, where views must go, and how controllers should be named. As long as you follow their conventions, your development efficiency will be astonishingly high. πŸš€

But this is a "parental" kind of love. When you encounter a special requirement that doesn't fit its conventions, you'll find that "fighting" the framework is extremely painful. Its internal mechanisms are highly coupled, and to change a small default behavior, you might need to read its arcane source code and use various "monkey-patching" black magic. It's like a gilded cage; although comfortable, your every move is restricted. ⛓️

The Hyperlane Blueprint: A Professional Architectural Guide

So, what should an ideal framework be like? It should be like an experienced architect. It won't decide every detail of the house for you, but it will provide you with a solid, reasonable, and proven architectural blueprint. It points you in the right direction but leaves you enough creative space.

The directory structure showcased by the hyperlane-quick-start project is just such an excellent blueprint. It's not mandatory, but it strongly "suggests" a professional, scalable way of organization.

Let's take a "tour" of this well-designed structure:

β”œβ”€β”€ app                      # Core Application Layer
β”‚   β”œβ”€β”€ controller           # Interface Control Layer (Handles HTTP)
β”‚   β”œβ”€β”€ service              # Business Logic Layer (Core Business)
β”‚   β”œβ”€β”€ mapper               # Data Access Layer (Handles Database)
β”‚   β”œβ”€β”€ model                # Data Model Layer (All data structures)
β”‚   β”œβ”€β”€ middleware           # Middleware Layer
β”‚   └── ...                  # Other auxiliary layers
β”œβ”€β”€ config                   # Configuration Directory
β”œβ”€β”€ init                     # Initialization Directory
β”œβ”€β”€ plugin                   # Plugin Directory
└── resources                # Resources Directory
Enter fullscreen mode Exit fullscreen mode

The core idea of this structure is Separation of Concerns. Each layer does one thing and does it well.

  • controller: Its sole responsibility is to handle HTTP requests and responses. It's like a "front desk receptionist." It receives a guest's request (Request), passes it to the professional business department (Service) for processing, and then politely returns the result to the guest (Response). It shouldn't know any details about the database or complex business logic.
  • service: This is the true "business core." User registration, order creation, article publishing... all core business logic happens here. It doesn't care if the data comes from HTTP or a CLI, nor does it care which database the data is ultimately stored in. It is pure, reusable business logic.
  • mapper: Its responsibility is to interact with the database. It's responsible for retrieving the data the service layer needs from the database, or saving it. It decouples the business logic from data storage.

The Soul of the Blueprint: The Finely-Grained model Layer

If the layering is the skeleton of this blueprint, then the fine-grained division of the model layer is its soul. Many projects have only one models directory, filled with all sorts of "models," which is a huge mistake. The Hyperlane blueprint tells us that data should have different "forms" at different stages of the application.

Directory Name (EN) Responsibility Why is this needed? πŸ€”
param Parameter Object Encapsulates HTTP request parameters received by the controller. Keeps your route function signatures clean, instead of a long list of loose parameters. Can also be used for request validation.
persistent Persistence Object Precisely maps to the database table structure. Your database table might have fields like created_at or updated_by that the business logic and API consumers don't care about.
domain / bean Domain / Entity Object Represents core business domain objects, containing business behavior. This is your business core! An Order object not only has data but should also have behaviors like cancel().
dto Data Transfer Object A data structure specifically for transport in the API. Extremely important! It helps you hide internal implementations and prevent sensitive data (like user password hashes) from leaking into API responses. It is the guarantee of your API contract.
view View Object A data structure specifically for rendering front-end pages. Your API might return JSON, but the data structure needed for your server-rendered pages could be completely different. Clear separation makes life easier for both frontend and backend.

This fine-grained division might seem a bit tedious at first. But trust me, as your project grows, you will be grateful for this clear demarcation. It acts like a series of firewalls, preventing implementation details from different layers from leaking into each other, ensuring the long-term health of the entire system. Fireproof! πŸ”₯

Good Frameworks Build Good Habits

If a framework only provides a bunch of APIs, it's only doing 50% of the job. The other 50% is the "philosophy" and "best practices" it advocates. A good framework will, through its suggested patterns, subtly cultivate good architectural habits in developers.

The Hyperlane blueprint is a perfect embodiment of this philosophy. It doesn't force you to do things this way, but it shows you a clear path to success. It tells you what a professional web application should look like. It's teaching you "how to fish," not just giving you a "fish." 🎣

So, the next time you start a new project, don't just be satisfied with how quickly the framework lets you get "Hello World" running. Check if it provides a similar "architectural blueprint." Because a good start is truly half the battle. A good architecture can ensure that your project remains elegant, robust, and easy to maintain after the test of time, like a well-designed, timeless building, not a code swamp that no one dares to touch. πŸ›οΈβœ¨

GitHub Home

Top comments (0)