Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
DRY — Don't Repeat Yourself
DRY (Don't Repeat Yourself) — это один из фундаментальных принципов разработки, который гласит: каждый кусок знания должен иметь одно единственное, однозначное представление в системе. Другими словами, не пиши одну и ту же логику, код или данные в разных местах.
Основная идея
Если один и тот же код (или логика) появляется в двух или более местах, это признак того, что нужно извлечь общую функциональность в отдельное место и переиспользовать её:
// ❌ ПЛОХО — дублирование кода
function getUserProfile() {
const firstName = localStorage.getItem('firstName');
const lastName = localStorage.getItem('lastName');
const email = localStorage.getItem('email');
return { firstName, lastName, email };
}
function updateUserProfile(firstName, lastName, email) {
localStorage.setItem('firstName', firstName);
localStorage.setItem('lastName', lastName);
localStorage.setItem('email', email);
}
// ✅ ХОРОШО — одна функция для управления
function getStorageItem(key) {
return localStorage.getItem(key);
}
function setStorageItem(key, value) {
localStorage.setItem(key, value);
}
function getUserProfile() {
return {
firstName: getStorageItem('firstName'),
lastName: getStorageItem('lastName'),
email: getStorageItem('email')
};
}
function updateUserProfile(firstName, lastName, email) {
setStorageItem('firstName', firstName);
setStorageItem('lastName', lastName);
setStorageItem('email', email);
}
Примеры нарушения DRY в Frontend
1. Дублирование в CSS:
/* ❌ ПЛОХО */
.button-primary {
padding: 12px 24px;
border-radius: 8px;
font-size: 16px;
font-weight: 600;
border: none;
cursor: pointer;
}
.button-secondary {
padding: 12px 24px;
border-radius: 8px;
font-size: 16px;
font-weight: 600;
border: none;
cursor: pointer;
}
/* ✅ ХОРОШО — используй переменные и миксины */
:root {
--button-padding: 12px 24px;
--button-radius: 8px;
--button-font: 600 16px/1 sans-serif;
}
.button-base {
padding: var(--button-padding);
border-radius: var(--button-radius);
font: var(--button-font);
border: none;
cursor: pointer;
}
.button-primary {
@extend .button-base;
background-color: #007bff;
}
.button-secondary {
@extend .button-base;
background-color: #6c757d;
}
2. Дублирование логики в React компонентах:
// ❌ ПЛОХО — один и тот же хук в разных компонентах
function UserProfile() {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
useEffect(() => {
setLoading(true);
fetch('/api/user')
.then(res => res.json())
.then(data => setUser(data))
.catch(err => setError(err))
.finally(() => setLoading(false));
}, []);
return <div>{user?.name}</div>;
}
function UserSettings() {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
useEffect(() => {
setLoading(true);
fetch('/api/user')
.then(res => res.json())
.then(data => setUser(data))
.catch(err => setError(err))
.finally(() => setLoading(false));
}, []);
return <input value={user?.name} />;
}
// ✅ ХОРОШО — извлеки в кастомный хук
function useUser() {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
useEffect(() => {
setLoading(true);
fetch('/api/user')
.then(res => res.json())
.then(data => setUser(data))
.catch(err => setError(err))
.finally(() => setLoading(false));
}, []);
return { user, loading, error };
}
function UserProfile() {
const { user } = useUser();
return <div>{user?.name}</div>;
}
function UserSettings() {
const { user } = useUser();
return <input value={user?.name} />;
}
3. Дублирование констант и конфигов:
// ❌ ПЛОХО
const API_BASE = 'https://api.example.com';
// На 10 местах в коде повторяется
fetch(`${API_BASE}/users`);
fetch(`${API_BASE}/posts`);
fetch(`${API_BASE}/comments`);
// ✅ ХОРОШО — один источник истины
const API_CONFIG = {
BASE_URL: 'https://api.example.com',
TIMEOUT: 5000,
RETRY_COUNT: 3
};
const apiClient = {
get: (endpoint) => fetch(`${API_CONFIG.BASE_URL}${endpoint}`),
post: (endpoint, data) => fetch(`${API_CONFIG.BASE_URL}${endpoint}`, { method: 'POST', body: JSON.stringify(data) })
};
apiClient.get('/users');
apiClient.get('/posts');
Когда НЕ применяй DRY
Хотя DRY очень важен, есть исключения:
- Случайное совпадение кода — если две функции случайно содержат одинаковый код, но решают разные проблемы, их объединение может привести к излишней связанности:
// Две разные функции, хотя логика похожа
function validateEmail(email) {
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
}
function validatePassword(password) {
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(password); // Неправильная логика!
}
// Правильно — разные валидаторы
function validateEmail(email) {
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
}
function validatePassword(password) {
return password.length >= 8 && /[A-Z]/.test(password);
}
- Сложное объединение — если объединение кода усложнит его сильнее, чем дублирование, лучше оставить как есть.
Преимущества DRY
- Упрощение поддержки — изменение логики в одном месте автоматически применяется везде
- Уменьшение багов — исправление ошибки в одной функции фиксит её везде
- Улучшение читаемости — меньше кода для понимания
- Масштабируемость — проще добавлять новый функционал
DRY — это не просто о коде, это о поддерживаемости и качестве проекта.