2.6Kпросмотров
91.5%от подписчиков
1 октября 2025 г.
Score: 2.8K
Cohesion и Coupling 🧩🔗 Здарова, работяги! Если очень коротко: хорошая архитектура — это высокая связность внутри модулей (cohesion) и низкая связанность между ними (coupling). Эти два термина отлично объясняют, почему код либо живёт годами, либо рассыпается от каждого чиха. В оригинале различить их достаточно просто, но вот в переводе… связанность и связность… Если у вас есть дефекты речи или вы просто устали к концу дня, то готовьтесь к сумбуру. Поэтому я обычно использую другой перевод:
— Cohesion — Связность
— Coupling — Сцепленность Связность (Cohesion) 🧲
— Насколько сильно и «по делу» связаны части внутри модуля/компонента.
— Высокая связность = модуль делает одну понятную вещь.
— Сигнал проблемы: описываете модуль через «и-и-и» — «карточка товара грузит, форматирует цену, читает локаль и отправляет аналитику». Сцепленность (Coupling) 🔗
— Насколько сильно модуль зависит от других.
— Низкая сцепленность = модуль знает только минимально необходимое о внешнем мире.
— Сигнал проблемы: изменение структуры store/API ломает полприложения. Пример 🍿 Плохо: низкая связность + высокая сцепленность function ProductCard({ id }: { id: string }) { const [product, setProduct] = React.useState<any>(null); React.useEffect(() => { fetch(/api/products/${id}) .then(r => r.json()) .then(setProduct); window.analytics.track('view_product', { id }); }, [id]); if (!product) return <>Loading...</>; const currency = localStorage.getItem('currency') || 'USD'; const priceText = new Intl.NumberFormat('en', { style: 'currency', currency }) .format(product.price); return ( <div> <img src={product.image} /> <div>{product.name}</div> <div>{priceText}</div> </div> );
} — Компонент делает всё: загрузка, форматирование, аналитика, работа со storage, UI. — Жёсткая привязка к fetch, analytics, localStorage, Intl и структуре product. — Любое внешнее изменение тянет правки сюда. Хорошо: высокая связность + низкая сцепленность type Product = { id: string; name: string; image: string; price: number };
type ProductApi = { getById(id: string): Promise<Product> };
type CurrencyFormatter = (currency: string, amount: number) => string; function ProductCardView({ product, priceText }: { product: Product; priceText: string }) { return ( <div> <img src={product.image} /> <div>{product.name}</div> <div>{priceText}</div> </div> );
} type Props = { id: string; api: ProductApi; currency: string; formatPrice: CurrencyFormatter;
} function ProductCard({ id, api, currency, formatPrice }: Props) { const product = useProduct(id, api); if (!product) return <>Loading...</>; const priceText = formatPrice(currency, product.price); return <ProductCardView product={product} priceText={priceText} />;
} — ProductCard оркестрирует UI конкретной карточки (высокая связность). — Зависимости приходят снаружи: api, formatPrice, currency (низкая сцепленность). — Легко подменять реализации. Опасные виды сцепленности на фронте 🛑
— Компонент знает «внутренности» ответа бэкенда и лезет в deeply.nested.a.b.c. — Временная: функция/эффект B должна вызываться строго после функции/эффекта A (завязка на порядок эффектов). — Прямое использование window, document, localStorage прямо в компоненте. — Зависимость от окружения: компонент «знает», что он в проде/тесте. Как снижать coupling и повышать cohesion 🛠
— Интерфейсы и адаптеры: компоненту нужен api.getById, а не fetch/axios. — DI через props/context: прокидывайте зависимости сверху. — Разделяйте UI и данные: View без побочек, отдельные сервисы для данных и бизнес-логики. — Избегайте «utils.ts на 1000 строк»: маленькие тематические модули (price/strings/date).