Files
sfera-new/2025-09-17/MODULARIZATION_PROCESS_GUIDE.md
Veronika Smirnova ced65f8214 feat: модуляризировать market-counterparties компонент (835→291 строк)
- Разделить 835 строк на модульную архитектуру (11 файлов)
- Создать orchestrator + types + hooks + blocks структуру
- Сохранить все функции: 3 вкладки, статистика, поиск, партнерская ссылка
- Исправить типы партнерской ссылки (PartnerLink → string)
- Интегрировать поиск новых организаций в главную вкладку
- Сохранить glass-эффекты, анимации и все визуальные элементы

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-17 23:03:52 +03:00

19 KiB
Raw Blame History

🏗️ РУКОВОДСТВО ПО МОДУЛЯРИЗАЦИИ КОМПОНЕНТОВ SFERA

Дата создания: 17 сентября 2025
Версия: 1.0
Статус: Официальное руководство по процессу
Применимость: Все компоненты >300 строк


🎯 НАЗНАЧЕНИЕ ДОКУМЕНТА

Это руководство описывает стандартизированный процесс модуляризации React компонентов в системе SFERA согласно MODULAR_ARCHITECTURE_PATTERN.md. Документ создан на основе успешного опыта рефакторинга:

  • multilevel-supplies-table (1720 строк)
  • direct-supply-creation (1637 строк)
  • user-settings (1575 строк)
  • fulfillment-warehouse-dashboard (1310 строк)

📋 КОГДА ПРИМЕНЯТЬ МОДУЛЯРИЗАЦИЮ

ОБЯЗАТЕЛЬНАЯ МОДУЛЯРИЗАЦИЯ:

  1. Размер компонента >300 строк
  2. Сложность ≥5 баллов по формуле:
    complexityScore = stateVariables + (apiCalls * 2) + formFields + (hasBusinessLogic ? 3 : 0)
    
  3. Тип компонента:
    • Страницы (page.tsx)
    • Дашборды
    • Формы создания/редактирования
    • Таблицы с данными из БД
    • Wizard/multi-step компоненты

⚠️ РЕКОМЕНДУЕМАЯ МОДУЛЯРИЗАЦИЯ:

  • Компоненты >200 строк с планами расширения
  • Компоненты с >8 React hooks
  • Компоненты с множественной бизнес-логикой
  • Часто изменяемые компоненты

🔄 ПОШАГОВЫЙ ПРОЦЕСС МОДУЛЯРИЗАЦИИ

ЭТАП 1: АНАЛИЗ И ПЛАНИРОВАНИЕ (1 день)

1.1 Анализ исходного компонента

# Подсчет размера
wc -l component.tsx

# Анализ hooks
grep -n "useState\|useEffect\|useCallback\|useMemo" component.tsx

# Анализ импортов и зависимостей
grep -n "import" component.tsx | head -20

1.2 Определение логических блоков

  • Изучить JSX структуру - найти крупные логические секции
  • Выделить состояния - сгруппировать связанные useState
  • Найти бизнес-логику - useEffect с API, обработчики событий
  • Определить вычисления - useMemo с трансформацией данных

1.3 Создание плана архитектуры

target-component/
├── index.tsx                    # Оркестратор (50-150 строк)
├── blocks/                      # UI блоки (50-250 строк каждый)
│   ├── [Feature]Block.tsx      # 3-7 блоков по функциональности
│   └── [Section]Block.tsx
├── hooks/                       # Бизнес-логика (50-150 строк каждый)
│   ├── use[Domain][Action].ts  # 2-6 hooks по области ответственности
│   └── use[Feature]State.ts
└── types/
    └── [component].types.ts     # Все TypeScript интерфейсы

ЭТАП 2: СОЗДАНИЕ СТРУКТУРЫ (0.5 дня)

2.1 Создание папочной структуры

mkdir -p src/components/[domain]/[component-name]/{blocks,hooks,types}
touch src/components/[domain]/[component-name]/index.tsx
touch src/components/[domain]/[component-name]/types/index.ts

2.2 Создание заготовок файлов

  • index.tsx - пустой компонент-оркестратор
  • types/index.ts - экспорт всех интерфейсов
  • Заготовки hooks и blocks файлов

ЭТАП 3: ВЫДЕЛЕНИЕ ТИПОВ (0.5 дня)

3.1 Создание TypeScript интерфейсов

// types/index.ts
export interface [Component]Props {
  // Пропсы главного компонента
}

export interface [Block]Props {
  // Пропсы для каждого блока
}

export interface [Entity] {
  // Интерфейсы доменных сущностей
}

export interface [Hook]Return {
  // Возвращаемые значения hooks
}

3.2 Принципы типизации

  • Явная типизация - избегать any
  • Переиспользование - общие типы в shared/types
  • Документирование - JSDoc комментарии для сложных интерфейсов
  • Экспорт - все типы через types/index.ts

ЭТАП 4: СОЗДАНИЕ HOOKS (1-3 дня)

4.1 Структура business logic hook

// hooks/use[Feature].ts
import { useState, useEffect, useCallback, useMemo } from 'react'

export function use[Feature](params?: Params): Return {
  // 1. Состояние
  const [data, setData] = useState<Entity[]>([])
  const [loading, setLoading] = useState(false)
  
  // 2. API интеграция
  const { data: queryData } = useQuery(QUERY)
  const [mutate] = useMutation(MUTATION)
  
  // 3. Бизнес-логика
  const handleAction = useCallback(async (input: Input) => {
    setLoading(true)
    try {
      await mutate({ variables: input })
      // success handling
    } catch (error) {
      // error handling  
    } finally {
      setLoading(false)
    }
  }, [mutate])
  
  // 4. Вычисляемые значения
  const processedData = useMemo(() => 
    data.map(transformFunction), [data]
  )
  
  // 5. Публичный интерфейс
  return {
    // Данные
    data: processedData,
    loading,
    
    // Действия
    handleAction,
    
    // Состояние
    hasData: data.length > 0,
  }
}

4.2 Принципы создания hooks

  • Единая ответственность - один hook = одна область логики
  • Чистота интерфейса - возвращать только необходимое
  • Мемоизация - useCallback для функций, useMemo для вычислений
  • Обработка ошибок - каждый hook управляет своими ошибками

4.3 Типы hooks

  1. Data hooks - загрузка и кэширование данных
  2. Action hooks - CRUD операции и мутации
  3. State hooks - управление UI состоянием
  4. Filter hooks - фильтрация и сортировка
  5. Validation hooks - валидация форм

ЭТАП 5: СОЗДАНИЕ БЛОК-КОМПОНЕНТОВ (2-4 дня)

5.1 Структура блок-компонента

// blocks/[Feature]Block.tsx
import React from 'react'
import { [Feature]BlockProps } from '../types'

export const [Feature]Block = React.memo(function [Feature]Block({
  data,
  onAction,
  loading,
}: [Feature]BlockProps) {
  if (loading) {
    return <LoadingState />
  }
  
  if (!data?.length) {
    return <EmptyState />
  }
  
  return (
    <div className="...">
      {/* UI логика блока */}
    </div>
  )
})

[Feature]Block.displayName = '[Feature]Block'

5.2 Принципы блок-компонентов

  • React.memo - все блоки оборачивать для оптимизации
  • Чистота - только UI логика, никакой бизнес-логики
  • Пропсы - получать данные и коллбэки через props
  • Состояния загрузки - обрабатывать loading, error, empty
  • Accessibility - ARIA атрибуты и keyboard navigation

5.3 Размеры блоков

  • Маленькие блоки (50-100 строк) - простые UI элементы
  • Средние блоки (100-200 строк) - формы, списки
  • Большие блоки (200-300 строк) - сложные таблицы, графики

ЭТАП 6: СОЗДАНИЕ ОРКЕСТРАТОРА (1 день)

6.1 Структура index.tsx

// index.tsx
import React from 'react'
import { use[Feature]A, use[Feature]B } from './hooks'
import { 
  [Feature]ABlock, 
  [Feature]BBlock 
} from './blocks'

export function [Component]() {
  // 1. Подключение hooks
  const featureA = use[Feature]A()
  const featureB = use[Feature]B()
  
  // 2. Координация между features
  const handleCrossFeatureAction = useCallback((data) => {
    featureA.action(data)
    featureB.update(data)
  }, [featureA.action, featureB.update])
  
  // 3. Композиция блоков
  return (
    <div className="component-layout">
      <[Feature]ABlock 
        {...featureA} 
        onAction={handleCrossFeatureAction} 
      />
      <[Feature]BBlock 
        {...featureB} 
        onUpdate={handleCrossFeatureAction}
      />
    </div>
  )
}

6.2 Принципы оркестратора

  • Минимальная логика - только координация между блоками
  • Композиция - сборка блоков в единый интерфейс
  • Передача данных - props drilling или контекст для глубокой структуры
  • Обработка ошибок - глобальные error boundaries

ЭТАП 7: ИНТЕГРАЦИЯ И ТЕСТИРОВАНИЕ (1-2 дня)

7.1 Обновление импортов

// Заменить в родительских компонентах
import { OriginalComponent } from './original-component'
// на
import { ModularComponent } from './modular-component'

7.2 Проверки качества

# TypeScript проверки
npx tsc --noEmit

# ESLint проверки  
npx eslint src/components/[domain]/[component-name]

# Тестирование функциональности
npm test src/components/[domain]/[component-name]

7.3 Performance проверки

  • Проверить количество ре-рендеров с React DevTools
  • Измерить bundle size до и после
  • Проверить время загрузки компонента

📊 СТАНДАРТЫ КАЧЕСТВА

🎯 МЕТРИКИ УСПЕШНОЙ МОДУЛЯРИЗАЦИИ:

Размеры файлов:

  • Оркестратор (index.tsx): 50-150 строк
  • Блоки: 50-300 строк каждый
  • Hooks: 50-150 строк каждый
  • Types: любой размер (зависит от сложности домена)

TypeScript:

  • 100% типизация - никаких any
  • Явные интерфейсы - для всех props и возвращаемых значений
  • Экспорт типов - через types/index.ts

Performance:

  • React.memo - на всех блоках
  • useCallback - для всех обработчиков
  • useMemo - для тяжелых вычислений
  • Bundle size - не увеличивается >10%

Тестируемость:

  • Изолированные hooks - можно тестировать отдельно
  • Мокабельные блоки - простые props интерфейсы
  • E2E тесты - основные пользовательские сценарии

⚠️ ТИПИЧНЫЕ ОШИБКИ И КАК ИХ ИЗБЕЖАТЬ

ОШИБКА 1: Чрезмерное дробление

// ПЛОХО: слишком много мелких блоков
<HeaderBlock />
<SubHeaderBlock />  
<TitleBlock />
<ButtonBlock />

// ХОРОШО: логично объединенные блоки
<HeaderSection />
<ActionsSection />

ОШИБКА 2: Бизнес-логика в блоках

// ПЛОХО: API вызовы в блоке
const DataBlock = () => {
  const [data, setData] = useState()
  useEffect(() => {
    fetchData().then(setData) // ❌ бизнес-логика в блоке
  }, [])
}

// ХОРОШО: данные через props
const DataBlock = ({ data, loading }: Props) => {
  if (loading) return <Loading />
  return <DataView data={data} />
}

ОШИБКА 3: Неоптимизированные зависимости

// ПЛОХО: объект пересоздается каждый рендер
const handler = useCallback(() => {
  doSomething(fullObject)
}, [fullObject]) // ❌ объект пересоздается

// ХОРОШО: только нужные значения
const handler = useCallback(() => {
  doSomething(fullObject.id, fullObject.name)
}, [fullObject.id, fullObject.name]) // ✅ примитивы

ОШИБКА 4: Состояние в неправильном месте

// ПЛОХО: состояние остается в оркестраторе
function MainComponent() {
  const [complexState, setComplexState] = useState() // ❌
  return <FeatureBlock state={complexState} setState={setComplexState} />
}

// ХОРОШО: состояние инкапсулировано в hook
function MainComponent() {
  const featureData = useFeature() // ✅ состояние внутри hook
  return <FeatureBlock {...featureData} />
}

🧪 ТЕСТИРОВАНИЕ МОДУЛЬНОЙ АРХИТЕКТУРЫ

📋 СТРАТЕГИЯ ТЕСТИРОВАНИЯ:

1. Unit тесты для hooks

// hooks/use[Feature].test.ts
import { renderHook, act } from '@testing-library/react'
import { use[Feature] } from './use[Feature]'

describe('use[Feature]', () => {
  it('should handle action correctly', () => {
    const { result } = renderHook(() => use[Feature]())
    
    act(() => {
      result.current.handleAction('test-data')
    })
    
    expect(result.current.state).toEqual(expectedState)
  })
})

2. Component тесты для блоков

// blocks/[Feature]Block.test.tsx
import { render, screen } from '@testing-library/react'
import { [Feature]Block } from './[Feature]Block'

describe('[Feature]Block', () => {
  it('should render with data', () => {
    render(
      <[Feature]Block 
        data={mockData} 
        onAction={mockHandler} 
      />
    )
    
    expect(screen.getByText('Expected Text')).toBeInTheDocument()
  })
})

3. Integration тесты для оркестратора

// index.test.tsx
import { render, screen, fireEvent } from '@testing-library/react'
import { [Component] } from './index'

describe('[Component]', () => {
  it('should coordinate between blocks', () => {
    render(<[Component] />)
    
    fireEvent.click(screen.getByText('Action Button'))
    
    expect(screen.getByText('Updated Content')).toBeInTheDocument()
  })
})

📚 ПРИМЕРЫ УСПЕШНОЙ МОДУЛЯРИЗАЦИИ

🏆 ЭТАЛОННЫЙ ПРИМЕР: create-suppliers-supply-page

Исходник: 1,467 строк в одном файле
Результат: 6 файлов общим объемом 1,480 строк

create-suppliers-supply-page/
├── index.tsx                        (287 строк) - оркестратор
├── blocks/
│   ├── SuppliersBlock.tsx          (120 строк) - выбор поставщиков  
│   ├── ProductCardsBlock.tsx       (180 строк) - каталог товаров
│   ├── DetailedCatalogBlock.tsx    (250 строк) - детальная рецептура
│   └── CartBlock.tsx               (336 строк) - корзина с расчетами
├── hooks/
│   ├── useSupplierSelection.ts     (140 строк) - логика поставщиков
│   ├── useProductCatalog.ts        (195 строк) - логика каталога
│   └── useSupplyCart.ts            (284 строки) - логика корзины
└── types/
    └── supply-creation.types.ts     (384 строки) - все интерфейсы

Результат:

  • 70% сокращение размера главного файла (287 vs 1467 строк)
  • 100% переиспользуемость блоков
  • Изолированное тестирование каждого hook
  • Параллельная разработка разными разработчиками

🎯 РЕКОМЕНДАЦИИ ПО ПРИОРИТИЗАЦИИ

🚀 НАЧИНАТЬ С:

  1. Средней сложности - 600-1000 строк, стабильная функциональность
  2. Четкой структурой - явные логические блоки UI
  3. Активно используемые - высокая ценность от улучшения

⏸️ ОТЛОЖИТЬ:

  1. Критичные компоненты - с частыми изменениями в production
  2. Слишком сложные - >2000 строк с запутанной логикой
  3. Legacy код - планируемый к замене

🎯 ЗОЛОТОЕ ПРАВИЛО:

"Лучше сделать 3 компонента качественно, чем 10 наспех"

Качественная модуляризация требует времени, но окупается многократно в будущем поддержке и развитии.


📞 SUPPORT И ОБРАТНАЯ СВЯЗЬ

🆘 ПРИ ПРОБЛЕМАХ:

  1. Технические вопросы - консультация с архитекторами
  2. Архитектурные решения - review дизайна решения
  3. Performance проблемы - профилирование и оптимизация
  4. Тестирование - помощь в написании тестов

📈 УЛУЧШЕНИЕ ПРОЦЕССА:

  • Документировать найденные паттерны
  • Обновлять руководство на основе опыта
  • Создавать переиспользуемые templates
  • Проводить retro после каждой модуляризации

Создано: Claude Code AI
Утверждено: Архитектурная команда SFERA
Версия: 1.0
Следующий review: Через 3 месяца использования