Проблемы больших проектов: сопровождение компонентов и фанатичность принципу DRY
Рассмотрим типичный сценарий разработки фронтенд-приложений. Бизнес выдвигает требования, которые постепенно усложняют компоненты. Это приводит к проблемам сопровождения, особенно в больших проектах.
Пример: компонент для вывода суммы двух чисел
Первое требование: сумма двух чисел в кавычках
const SumComponent = (a, b) => `"${a + b}"`;
Второе требование: добавить вывод знака в конце
const SumComponent = (a, b, tag) => `"${a + b}"-${tag}`;
Третье требование: добавить умножение
const SumComponent = (a, b, tag, isMultiple) =>
`${isMultiple ? a * b : ''}-"${a + b}"-${tag}`;
Проблема
Компонент превращается в "монстра" с кучей аргументов. Новые пропсы зависят от старых, что усложняет сопровождение. В больших проектах это становится критичным.
Выход из ситуации: простое решение (но с дублированием)
Один из подходов — создавать отдельные компоненты для каждого кейса. Это противоречит принципу DRY, но упрощает сопровождение.
// Простая сумма
const SumComponent = (a, b) => `"${a + b}"`;
// Сумма с тегом
const SumComponentAndTag = (a, b, tag) => `"${a + b}"-${tag}`;
// Сумма с тегом и умножением
const SumComponentAndTagAndMultiple = (a, b, tag, isMultiple) =>
`${isMultiple ? a * b : ''}-"${a + b}"-${tag}`;
Проблема этого подхода
Дублирование кода. Если логика суммы изменится, придется вносить изменения во всех компонентах.
Модульный подход: композиция функций (лучшая практика функционального программирования)
Чтобы избежать дублирования и сохранить гибкость, можно использовать композицию функций. Каждая функция отвечает за одну задачу, а затем они комбинируются.
Базовые функции
// Базовая логика суммы
const sum = (a, b) => a + b;
// Добавление кавычек
const withQuotes = (fn) => (a, b) => `"${fn(a, b)}"`;
// Добавление тега
const withTag = (fn) => (a, b, tag) => `${fn(a, b)}-${tag}`;
// Добавление умножения
const withMultiplication = (fn) => (a, b, isMultiple) =>
isMultiple ? `${a * b}-${fn(a, b)}` : fn(a, b);
Комбинирование функций
// Простая сумма с кавычками
const SumComponent = withQuotes(sum);
// Сумма с кавычками и тегом
const SumComponentAndTag = (a, b, tag) => withTag(withQuotes(sum))(a, b, tag);
// Сумма с кавычками, тегом и умножением
const SumComponentAndTagAndMultiple = (a, b, tag, isMultiple) =>
withMultiplication(withTag(withQuotes(sum)))(a, b, isMultiple) + `-${tag}`;
Преимущества
Модульность: каждая функция отвечает за одну задачу.
Переиспользование: функции можно комбинировать в любом порядке.
Сопровождение: изменения в базовой логике автоматически применяются ко всем комбинациям.
Практика на Vue.js
Composition API
1. Создаем композаблы (composables)
Каждая логика будет вынесена в отдельный композабл, чтобы обеспечить переиспользование и модульность.
useSum.js — логика суммы
import { computed } from 'vue';
export function useSum(a, b) {
const sum = computed(() => a + b);
return { sum };
}
useQuotes.js — добавление кавычек
import { computed } from 'vue';
export function useQuotes(value) {
const quotedValue = computed(() => `"${value.value}"`);
return { quotedValue };
}
useTag.js — добавление тега
import { computed } from 'vue';
export function useTag(value, tag) {
const taggedValue = computed(() => `${value.value}-${tag}`);
return { taggedValue };
}
useMultiplication.js — добавление умножения
import { computed } from 'vue';
export function useMultiplication(a, b, value, isMultiple) {
const multipliedValue = computed(() =>
isMultiple.value ? `${a.value * b.value}-${value.value}` : value.value
);
return { multipliedValue };
}
2. Создаем компоненты с использованием композаблов
Базовый компонент SumComponent
<script setup>
import { useSum, useQuotes } from './composables';
const props = defineProps({
a: Number,
b: Number,
});
const { sum } = useSum(props.a, props.b);
const { quotedValue } = useQuotes(sum);
</script>
<template>
<span>{{ quotedValue }}</span>
</template>
Компонент SumComponentAndTag
<script setup>
import { useSum, useQuotes, useTag } from './composables';
const props = defineProps({
a: Number,
b: Number,
tag: String,
});
const { sum } = useSum(props.a, props.b);
const { quotedValue } = useQuotes(sum);
const { taggedValue } = useTag(quotedValue, props.tag);
</script>
<template>
<span>{{ taggedValue }}</span>
</template>
3. Преимущества подхода
Модульность: Каждая логика изолирована в отдельном композабле.
Переиспользование: Композаблы можно использовать в разных компонентах.
Реактивность: Все значения автоматически обновляются при изменении пропсов.
Сопровождение: Легко вносить изменения, так как логика разделена на мелкие части.
Тестируемость: Каждый композабл можно тестировать независимо.
4. Пример использования компонентов
<template>
<div>
<!-- Простая сумма -->
<SumComponent :a="2" :b="3" />
<!-- Сумма с тегом -->
<SumComponentAndTag :a="2" :b="3" tag="result" />
</div>
</template>
<script setup>
import SumComponent from './components/SumComponent.vue';
import SumComponentAndTag from './components/SumComponentAndTag.vue';
</script>
5. Итог
Использование useComposable во Vue 3 позволяет:
Создавать гибкие и модульные компоненты.
Избегать дублирования кода.
Упрощать сопровождение и тестирование.
Легко адаптироваться к изменениям требований.
Options API
Проблемы
Слоты: сложно сопровождать в больших проектах.
Миксины: могут вызывать конфликты и неявные зависимости.
Обычные функции с замыканиями: отсутствие автоматической реактивности.
Модульный подход позволяет соблюдать DRY и упрощает сопровождение.
Композиция функций делает код гибким и переиспользуемым.
Composition API во Vue — современный и удобный способ организации кода.
Избегайте монолитных компонентов: разделяйте логику на мелкие, независимые части.
Этот подход особенно полезен в больших проектах, где важно поддерживать баланс между гибкостью и читаемостью кода.