Skip to content

Instantly share code, notes, and snippets.

@SeLub
Created February 8, 2025 09:59
Show Gist options
  • Save SeLub/49d41a3c72b0a9cdfa4a038b912d169f to your computer and use it in GitHub Desktop.
Save SeLub/49d41a3c72b0a9cdfa4a038b912d169f to your computer and use it in GitHub Desktop.
How to structure project

How to structure NodeJS project

Possible structures:

File structure

1. Domain-Driven Structure:

src/
├── domains/
│ ├── subscriptions/
│ │ ├── subscription.controller.ts
│ │ ├── subscription.service.ts
│ │ ├── subscription.repository.ts
│ │ ├── subscription.model.ts
│ │ ├── subscription.schema.ts # validation schemas
│ │ └── subscription.types.ts # interfaces/types
│ ├── channels/
│ ├── bots/
│ ├── posts/
│ └── postlines/
├── shared/
│ ├── middleware/
│ ├── utils/
│ └── types/
└── server.ts

2. Layer-First Structure:

src/
├── controllers/
│ ├── subscription.controller.ts
│ ├── channel.controller.ts
│ └── ...
├── services/
├── repositories/
├── models/
├── schemas/
├── types/
└── server.ts

Pros and Cons

1. Domain-Driven Design (DDD)

Overview:

  • Focus: Emphasizes understanding the business domain to design software that closely aligns with the business logic.
  • Core Concepts: Ubiquitous Language, Bounded Contexts, Aggregate Roots, Entity Framework, Value Objects, and Repositories.

Structure:

  1. Ubiquitous Language (Domain Language):
    • A shared language used across all stakeholders (developers, product managers, domain experts) to describe the system's functionality and business rules.
  2. Bounded Contexts:
    • Divides a large complex domain into smaller, manageable pieces where each piece has its own context and rules.
    • Helps in managing complexity by allowing different teams or parts of an organization to independently develop their part without conflicts.
  3. Aggregates and Aggregate Roots:
    • Aggregates are collections of objects that are treated as a single unit.
    • An Aggregate Root is the entry point for any operation within an aggregate, ensuring consistency.
  4. Entities:
    • Objects with identity (e.g., User, Order), which means two instances with different IDs are considered distinct even if their properties match.
  5. Value Objects:
    • Objects that represent immutable data (e.g., Address, Money). They are compared by value rather than reference and are typically used as parts of entities or other value objects.
  6. Repositories:
    • Interfaces for accessing domain objects without exposing the underlying storage mechanisms.
    • Abstracts how data is persisted, allowing changes to be made in one place.

Key Benefits:

  • Strong Focus on Business Rules: Aligns code more closely with business logic, making it easier to understand and evolve.
  • Scalability and Maintainability: Easier to manage large systems by breaking them down into bounded contexts.
  • Collaboration: Promotes better communication between teams through a shared language.

2. Layered Architecture

Overview:

  • Focus: Organizes the application into distinct layers, each responsible for specific functions.
  • Core Layers: Presentation Layer (UI), Business Logic Layer (Domain Services, Application Services), and Data Access Layer (Persistence).

Structure:

  1. Presentation Layer:
    • Handles user interaction, routing, controllers, and HTTP endpoints.
    • Acts as an interface between the outside world and the application.
  2. Business Logic Layer:
    • Contains the core business rules and logic of the application.
    • Includes domain models, services, and use cases.
  3. Data Access Layer:
    • Manages data storage and retrieval, interfacing with databases or external systems.
    • Abstracts database operations to provide a clean interface for the business layer.

Key Benefits:

  • Separation of Concerns: Clear distinction between different responsibilities, making the code easier to maintain and extend.
  • Testability: Layers can be tested independently, which simplifies unit testing.
  • Scalability: Easier to scale as each layer can be developed or upgraded without affecting others.

Comparison and Use Cases

DDD vs. Layered Architecture:

Aspect DDD Layered Architecture
Focus Business logic Separation of concerns
Project Structure Domains, Aggregates, Entities Presentation, Application, Infrastructure
Flexibility High (supports complex domain models) Moderate
Complexity Higher Lower
Use Cases Large-scale enterprise applications with complex business logic General-purpose web applications
Testing Domain-driven testing Layered testing

When to Use DDD:

  • Applications with highly complex and dynamic domain models.
  • Projects that require a deep understanding of business rules and need to evolve over time.
  • Teams aiming for high maintainability and scalability in large-scale systems.

When to Use Layered Architecture:

  • Simpler applications where clear separation of concerns is sufficient.
  • Projects requiring rapid development or iteration with minimal overhead.
  • Applications where the domain model is relatively straightforward.

Conclusion

Choosing between DDD and a layered architecture depends on the complexity of your application, the importance of aligning code with business logic, and your team's familiarity with these architectural styles. While DDD offers more flexibility and alignment with business requirements, it may introduce additional overhead for simpler projects. On the other hand, a layered architecture provides a clear separation of concerns and is generally easier to implement but might not capture all nuances of complex domain interactions.

Both approaches aim to enhance code organization and maintainability, so consider your project's specific needs and constraints when selecting an architectural pattern.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment