← Назад к вопросам

Какую архитектуру выберешь при написании проекта с нуля?

2.0 Middle🔥 151 комментариев
#Архитектура и паттерны

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Какую архитектуру выберешь при написании проекта с нуля?

Я выбрал бы модульную архитектуру на основе признаков приложения (Feature-based Architecture) с послойной организацией (Layered Architecture). Это оптимальный баланс между масштабируемостью, поддерживаемостью и простотой на ранних этапах.

Рекомендуемая структура проекта

src/
  app/                          # Точка входа, App-уровень
    App.tsx
    root.tsx
  
  features/                     # Признаки приложения
    auth/
      components/
        LoginForm.tsx
        SignupForm.tsx
      hooks/
        useAuth.ts
        useLogin.ts
      services/
        authService.ts
      types/
        auth.ts
      pages/
        LoginPage.tsx
        SignupPage.tsx
    
    posts/
      components/
        PostCard.tsx
        PostList.tsx
      hooks/
        usePosts.ts
      services/
        postService.ts
      types/
        post.ts
      pages/
        PostsPage.tsx
    
    comments/
      components/
        CommentForm.tsx
      hooks/
        useComments.ts
      services/
        commentService.ts
      types/
        comment.ts
  
  shared/                       # Переиспользуемый код
    components/
      Button.tsx
      Card.tsx
      Modal.tsx
    hooks/
      useApi.ts
      useLocalStorage.ts
    utils/
      formatDate.ts
      cn.ts
    types/
      index.ts
    constants/
      api.ts
  
  lib/                          # Низкоуровневые утилиты
    api.ts
    store.ts
    logger.ts

Почему Feature-based архитектура

Плюсы:

  • Масштабируемость: легко добавлять новые фичи
  • Инкапсуляция: всё связанное в одной папке
  • Параллельная работа: разные команды работают над разными фичами
  • Легче удалять: удаляешь папку фичи — всё готово
  • Организованно: ясная структура и иерархия

Минусы:

  • Может быть оверинжиниринг для маленьких приложений
  • Требует дисциплины в организации кода

Послойная организация внутри фичи

feature-name/
  types/          # TypeScript типы (domain слой)
    index.ts
  
  services/       # Бизнес-логика (application слой)
    featureService.ts
  
  hooks/          # React логика (infrastructure слой)
    useFeature.ts
  
  components/     # UI (presentation слой)
    FeatureComponent.tsx
  
  pages/          # Страницы (presentation слой)
    FeaturePage.tsx

Зависимости только вниз (типы -> сервисы -> компоненты):

  • Компоненты -> Хуки -> Сервисы -> Типы
  • Никогда: Типы -> Компоненты (это плохо)

Практический пример: фича постов

// types/post.ts (domain слой)
export interface Post {
  id: string;
  title: string;
  content: string;
  authorId: string;
  createdAt: Date;
  updatedAt: Date;
}

export interface CreatePostDto {
  title: string;
  content: string;
}

// services/postService.ts (application слой)
import { Post, CreatePostDto } from '../types/post';

export class PostService {
  async getPosts(): Promise<Post[]> {
    const response = await fetch('/api/posts');
    return response.json();
  }

  async createPost(data: CreatePostDto): Promise<Post> {
    const response = await fetch('/api/posts', {
      method: 'POST',
      body: JSON.stringify(data)
    });
    return response.json();
  }

  async updatePost(id: string, data: Partial<Post>): Promise<Post> {
    const response = await fetch(`/api/posts/${id}`, {
      method: 'PUT',
      body: JSON.stringify(data)
    });
    return response.json();
  }

  async deletePost(id: string): Promise<void> {
    await fetch(`/api/posts/${id}`, {
      method: 'DELETE'
    });
  }
}

// hooks/usePosts.ts (infrastructure слой)
import { useState, useEffect } from 'react';
import { PostService } from '../services/postService';
import { Post } from '../types/post';

const postService = new PostService();

export function usePosts() {
  const [posts, setPosts] = useState<Post[]>([]);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<Error | null>(null);

  useEffect(() => {
    const fetchPosts = async () => {
      setLoading(true);
      try {
        const data = await postService.getPosts();
        setPosts(data);
      } catch (err) {
        setError(err instanceof Error ? err : new Error('Unknown error'));
      } finally {
        setLoading(false);
      }
    };

    fetchPosts();
  }, []);

  return { posts, loading, error };
}

// components/PostList.tsx (presentation слой)
import { usePosts } from '../hooks/usePosts';

export function PostList() {
  const { posts, loading, error } = usePosts();

  if (loading) return <div>Загружается...</div>;
  if (error) return <div>Ошибка: {error.message}</div>;

  return (
    <ul>
      {posts.map(post => (
        <li key={post.id}>
          <h2>{post.title}</h2>
          <p>{post.content}</p>
        </li>
      ))}
    </ul>
  );
}

// pages/PostsPage.tsx
import { PostList } from '../components/PostList';

export default function PostsPage() {
  return (
    <main>
      <h1>Посты</h1>
      <PostList />
    </main>
  );
}

Общая структура приложения

// app/App.tsx
import { Outlet } from 'react-router-dom';
import { Header } from '@/shared/components/Header';
import { Footer } from '@/shared/components/Footer';

export default function App() {
  return (
    <div className="app">
      <Header />
      <main>
        <Outlet /> {/* Роуты здесь */}
      </main>
      <Footer />
    </div>
  );
}

// Маршруты
const routes = [
  {
    path: '/',
    element: <App />,
    children: [
      {
        path: '/posts',
        lazy: () => import('@/features/posts/pages/PostsPage')
      },
      {
        path: '/posts/:id',
        lazy: () => import('@/features/posts/pages/PostDetailPage')
      },
      {
        path: '/login',
        lazy: () => import('@/features/auth/pages/LoginPage')
      }
    ]
  }
];

Когда масштабируется

Если проект растёт, добавляй слои:

  • Domain слой: бизнес-правила, domain модели
  • Application слой: use cases, сервисы
  • Infrastructure слой: API, БД, кеширование
  • Presentation слой: компоненты, страницы

Альтернативы и когда их использовать

1. Плоская структура (для очень маленьких проектов):

src/
  components/
  pages/
  hooks/
  styles/

Простая, но быстро становится хаотичной.

2. Слоевая архитектура (для сложных приложений):

src/
  domain/          # Бизнес-логика
  application/     # Use cases
  infrastructure/  # API, БД
  presentation/    # UI

Мощная, но может быть оверинжиниринг для новых проектов.

3. Модули по функциям (my choice):

src/
  features/        # Фичи
  shared/          # Переиспользуемое
  app/             # Конфиг

Оптимальный баланс.

Ключевые принципы архитектуры

  • SOLID: один класс — одна ответственность
  • DRY: не повторяй код
  • Инкапсуляция: каждый модуль независим
  • Зависимости вниз: никогда вверх
  • Легко тестировать: юнит-тесты без моков

Ключевые выводы

  • Feature-based архитектура — лучший выбор для роста
  • Послойная организация — контролирует сложность
  • Типы -> Сервисы -> Компоненты — правильное направление зависимостей
  • Shared и lib — для переиспользуемого кода
  • Масштабируется — легко добавлять фичи и разработчиков

Эта архитектура оптимальна для 90% проектов и растёт вместе с приложением.

Какую архитектуру выберешь при написании проекта с нуля? | PrepBro