1. Введение
Когда вы только начинаете программировать, можно спокойно писать весь код в одном файле. Но стоит проекту вырасти хотя бы до пары сотен строк — и всё, здравствуй, хаос! Найти нужную функцию становится сложнее, ошибки начинают прятаться в самых неожиданных местах, а добавление новых фич превращается в мини-квест.
Структурирование кода — это как уборка в комнате: сначала кажется, что и так всё на месте, но потом понимаешь, что без порядка не обойтись.
Аналогия из жизни
Представьте, что вы открываете кухонный шкаф, а там: ложки, кастрюли, специи, макароны и даже старый айфон — всё в одной куче. Готовить можно, но удовольствие — так себе. Если же всё разложено по полочкам, то и готовить, и убираться, и даже искать пропавший носок — одно удовольствие!
Так же и с кодом: разделение на модули и папки позволяет быстро находить нужные части, легко исправлять ошибки и добавлять новые возможности.
2. Основные принципы структурирования проекта
Модульность
Модуль — это самостоятельная часть программы, которая отвечает за определённую задачу. Например, у вас может быть модуль для работы с пользователями, модуль для отправки писем, модуль для работы с базой данных.
Преимущества модульности:
- Легко тестировать отдельные части кода.
- Можно переиспользовать модули в других проектах.
- Проще искать и исправлять ошибки.
- Несколько разработчиков могут работать параллельно, не мешая друг другу.
Разделение по ответственности (Separation of Concerns)
Каждый файл, класс или функция должны отвечать только за одну задачу. Это правило называют принципом единой ответственности (Single Responsibility Principle, SRP).
Например:
- Один класс отвечает за хранение данных пользователя.
- Другой — за отправку уведомлений.
- Третий — за обработку HTTP-запросов.
Ясная структура папок и файлов
Структура проекта должна быть понятна не только вам, но и любому человеку, который откроет ваш проект через год (или даже через неделю — если вы, как и большинство программистов, быстро забываете, что писали сами).
Типичная структура проекта:
my-app/
├── controllers/
├── models/
├── routes/
├── services/
├── utils/
├── app.js
├── package.json
└── README.md
3. Как делить проект на части: подходы и примеры
Разделение по слоям (Layered Architecture)
Один из самых популярных способов структурирования — разделение на слои:
- Контроллеры (controllers): принимают запросы, вызывают нужные сервисы, формируют ответы.
- Сервисы (services): бизнес-логика приложения (например, расчёт скидки, проверка прав доступа).
- Модели (models): работа с данными (например, структура пользователя, взаимодействие с базой данных).
- Утилиты (utils): вспомогательные функции, которые не зависят от бизнес-логики.
Пример (Node.js/Express):
// controllers/userController.js
const userService = require('../services/userService');
exports.createUser = (req, res) => {
userService.createUser(req.body)
.then(user => res.json(user))
.catch(err => res.status(500).json({ error: err.message }));
};
// services/userService.js
const User = require('../models/User');
exports.createUser = async (userData) => {
const user = new User(userData);
return await user.save();
};
// models/User.js
const mongoose = require('mongoose');
const UserSchema = new mongoose.Schema({ name: String, email: String });
module.exports = mongoose.model('User', UserSchema);
В чём смысл?
Контроллеры не знают, как именно работает модель или сервис — они просто вызывают нужные методы. Это позволяет легко менять реализацию, не трогая остальные части кода.
Разделение по функциональным областям (Feature-based)
Вместо того, чтобы делить код по слоям, можно делить его по функциональным областям.
Пример структуры:
features/
├── users/
│ ├── userController.js
│ ├── userService.js
│ └── userModel.js
├── posts/
│ ├── postController.js
│ ├── postService.js
│ └── postModel.js
Такой подход удобен в больших проектах, где много разных сущностей. Вы всегда знаете, где искать код, связанный с пользователями или постами.
4. Практические советы по структурированию проекта
- Не бойтесь создавать папки и файлы
Лучше сделать один маленький файл, чем один большой на 2000 строк. Не бойтесь дробить код — это не признак лени, а профессионализма! - Используйте говорящие имена
Названия папок и файлов должны быть понятны без дополнительных объяснений. userService.js лучше, чем us.js или blabla.js. - Документируйте структуру
Добавьте файл README.md с кратким описанием структуры проекта. Это поможет новым участникам команды (и вам самим через месяц) быстро разобраться, что где лежит. - Не усложняйте без необходимости
Если проект маленький, не стоит сразу строить архитектуру уровня космического корабля. Начните с простого — усложняйте по мере роста проекта.
5. Пример: Структурируем мини-проект "ToDo-список"
Описание приложения
- Пользователь может добавлять, удалять и отмечать задачи как выполненные.
- Все задачи хранятся в памяти (без базы данных).
Возможная структура
todo-app/
├── controllers/
│ └── taskController.js
├── models/
│ └── task.js
├── routes/
│ └── taskRoutes.js
├── services/
│ └── taskService.js
├── app.js
└── package.json
Пример кода
// models/task.js
class Task {
constructor(title) {
this.title = title;
this.completed = false;
}
}
module.exports = Task;
// services/taskService.js
const tasks = [];
const Task = require('../models/task');
exports.addTask = (title) => {
const task = new Task(title);
tasks.push(task);
return task;
};
exports.getAllTasks = () => tasks;
exports.completeTask = (index) => {
if (tasks[index]) tasks[index].completed = true;
};
// controllers/taskController.js
const taskService = require('../services/taskService');
exports.listTasks = (req, res) => res.json(taskService.getAllTasks());
exports.createTask = (req, res) => {
const task = taskService.addTask(req.body.title);
res.status(201).json(task);
};
exports.completeTask = (req, res) => {
taskService.completeTask(req.params.index);
res.status(200).json({ status: 'ok' });
};
// routes/taskRoutes.js
const express = require('express');
const router = express.Router();
const taskController = require('../controllers/taskController');
router.get('/', taskController.listTasks);
router.post('/', taskController.createTask);
router.post('/:index/complete', taskController.completeTask);
module.exports = router;
// app.js
const express = require('express');
const app = express();
app.use(express.json());
const taskRoutes = require('./routes/taskRoutes');
app.use('/tasks', taskRoutes);
app.listen(3000, () => console.log('Сервер запущен на порту 3000'));
В чём кайф такой структуры?
- Вы легко можете заменить хранение задач в памяти на базу данных, не меняя контроллеры и роуты.
- Любой разработчик быстро найдёт нужный кусок кода.
- Добавление новых фич (например, фильтрация задач по статусу) не превращается в головную боль.
6. Как структурировать проекты на фронтенде (React, Angular, Next.js)
React/Next.js
В современных фронтенд-проектах популярна структура по функциональным областям (feature-based):
src/
├── components/
│ ├── TodoList.jsx
│ └── TodoItem.jsx
├── features/
│ └── tasks/
│ ├── TaskList.js
│ ├── TaskForm.js
│ └── taskSlice.js
├── pages/
│ └── index.js
└── utils/
└── api.js
- components/ — переиспользуемые компоненты.
- features/ — бизнес-логика, связанная с конкретной сущностью.
- pages/ — страницы приложения (Next.js).
- utils/ — вспомогательные функции.
Angular
Angular любит делить проект на модули и компоненты:
src/
├── app/
│ ├── tasks/
│ │ ├── tasks.component.ts
│ │ ├── tasks.service.ts
│ │ └── task.model.ts
│ ├── shared/
│ └── app.module.ts
- tasks/ — всё, что связано с задачами.
- shared/ — переиспользуемые компоненты и сервисы.
7. Как проектировать структуру: пошаговая стратегия
- Определите основные сущности проекта (пользователь, задача, товар и т.д.).
- Разделите код по слоям (контроллеры, сервисы, модели) или по функциональным областям.
- Создайте отдельные папки для каждой крупной части.
- Разделяйте бизнес-логику и вспомогательные функции.
- Пишите документацию по структуре (README.md).
- Периодически делайте "рефакторинг" структуры по мере роста проекта.
8. Типичные ошибки при структурировании проектов
Ошибка №1: Весь код в одном файле.
Да, иногда хочется быстро "накидать" приложение, но потом вы сами себя проклянёте, когда придёт время что-то менять. Лучше сразу разбивать на модули.
Ошибка №2: Слишком глубокая вложенность папок.
Если путь до файла выглядит как src/features/users/controllers/api/v1/internal/helpers/utils/validate.js, пора остановиться. Старайтесь не делать структуру глубже 3-4 уровней.
Ошибка №3: Неочевидные названия файлов и папок.
Файл a.js или папка temp/ — это зло. Через месяц вы не вспомните, что там лежит.
Ошибка №4: Смешение бизнес-логики и утилит.
Не стоит хранить функции для расчёта скидки и функцию для форматирования даты в одном файле.
Ошибка №5: Преждевременная оптимизация структуры.
Не стоит сразу строить сложные архитектуры для маленьких проектов. Начните просто, усложняйте по мере необходимости.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ