Помимо паттернов проектирования, которые предлагают проверенные решения типичных задач, существуют антипаттерны — распространённые ошибки в архитектуре и коде. Они приводят к усложнению поддержки, росту зависимости, нарушению принципов SOLID и деградации кода.

Что такое антипаттерн

Антипаттерн — это повторяющаяся неудачная практика, которая кажется удобным решением, но на деле создаёт больше проблем, чем решает.

Примеры распространённых антипаттернов

Антипаттерн Описание Последствия
God Object Один класс выполняет слишком много функций и хранит всю бизнес-логику системы. Нарушение SRP, сложность тестирования и изменений.
Spaghetti Code Запутанный, плохо структурированный код без модульности и понятной архитектуры. Ошибки, невозможность повторного использования, зависимость от деталей реализации.
Copy-Paste Programming Повторение одного и того же кода вместо его вынесения в отдельный модуль. Дублирование логики, рост багов и сложности сопровождения.
Golden Hammer Использование одного знакомого инструмента для всех задач, независимо от контекста. Неоптимальные решения, низкая производительность, нарушение принципа KISS.
Lava Flow Ненужный код, оставшийся в проекте из-за страха его удалить. Снижение читаемости, рост технического долга.
Hard Coding Жёсткое встраивание значений (например, путей, паролей, конфигурации) прямо в код. Проблемы при изменении, переносе и тестировании приложения.
Circular Dependency Два или более модуля зависят друг от друга напрямую. Нарушение модульности, невозможность переиспользования, потенциальные ошибки при компиляции.
Magic Numbers Использование числовых или строковых литералов без пояснения их смысла. Потеря понимания кода, сложность поддержки.
Shotgun Surgery Любое изменение требует правок в десятках мест. Рост времени разработки и ошибок, нарушение инкапсуляции.
Singleton Obsession Чрезмерное использование Singleton даже там, где это не нужно. Скрытые зависимости, проблемы с тестированием, глобальное состояние.

Запрещённые практики

  • Логика в конструкторах — конструктор должен лишь инициализировать объект, а не выполнять действия.
  • Использование static везде — приводит к глобальному состоянию и проблемам с зависимостями.
  • Преждевременная оптимизация — попытки ускорить код без профилирования приводят к ухудшению читаемости.
  • Бизнес-логика в UI — нарушает разделение ответственности и мешает переиспользованию кода.
  • Игнорирование исключений — пустые catch-блоки скрывают ошибки и усложняют диагностику.
  • Использование комментариев вместо рефакторинга — код должен быть понятен сам по себе.

Пример антипаттерна "God Object"

// ❌ Плохой пример: один класс управляет всем
public class ApplicationManager
{
    public void ConnectToDatabase() { /* ... */ }
    public void AuthenticateUser() { /* ... */ }
    public void RenderUI() { /* ... */ }
    public void ProcessPayments() { /* ... */ }
    public void SendEmail() { /* ... */ }
    // ...
}
// ✅ Исправленный вариант: разделяем ответственность
public class DatabaseService { public void Connect() { /* ... */ } }
public class AuthService { public void Login() { /* ... */ } }
public class PaymentProcessor { public void Process() { /* ... */ } }
public class MailService { public void Send() { /* ... */ } }

Как избежать антипаттернов

  • Следуйте принципам SOLID и DRY.
  • Проводите регулярный рефакторинг.
  • Покрывайте код тестами, чтобы безопасно его менять.
  • Ревьюйте архитектуру и используйте линтеры.
  • Не бойтесь удалять устаревший код.

Заключение

Антипаттерны — не просто ошибки, а симптомы неправильных решений. Их важно знать, чтобы распознавать и устранять ещё на стадии проектирования. Как и с паттернами, ключ — понимание контекста: иногда «запрещённая» практика уместна, но осознанно и с контролем последствий.