По каким признакам и критериям можно определить, что код является плохим?

Привет! У меня вопросы о качестве кода и о том, что означает «го*вно-код». Прежде чем отвечать, лучше прочитать краткую историю моего опыта, чтобы понять контекст. <br/> <br/>
  • 5 июля 2026 г. 18:00
Ответы на вопрос 1
Привет — спасибо за вводную. Прежде чем давать подробные советы, хорошо бы увидеть твою «краткую историю опыта» (я смогу точнее подсказывать, если знаю: на каких языках ты пишешь, в каких командах/проектах работал, какие типичные проблемы видишь). Но уже сейчас дам универсальный набор признаков, критериев и практических проверок, чтобы определять плохой ( «говно‑») код.

Коротко о принципе: «плохой код» — это не всегда просто «плохо написанный» с точки зрения синтаксиса. Это код, который трудно понимать, поддерживать, расширять, тестировать или который постоянно порождает баги/инциденты/технический долг. Ниже — признаки, объективные критерии, инструменты и чек‑лист для быстрой оценки.

Признаки плохого кода (поведенческие и видимые)
- Частые баги и срочные хотфиксы (hotfixes) в одних и тех же местах.  
- Разработчики боятся менять код (боятся «взорвать» функциональность).  
- Длинные PR‑ы, множество правок в ревью, конфликтующие изменения.  
- Тесты медленные/хрупкие/отсутствуют; покрытие низкое.  
- Много «костылей», TODO/ FIXME, закомментированного кода.  
- Код «неформальный» — разные стили в одном проекте, нет единого соглашения.  
- Документации нет или она устарела; сложнее понять поведение, чем читать код.  

Структурные признаки «говно‑кода»
- Большие функции/методы (длиннее ~50–100 строк), глубокая вложенность (if/for внутри if/for).  
- «God objects» / классы, выполняющие много ответственности.  
- Сильная связанность модулей (high coupling) и слабая когезия (low cohesion).  
- Повторяющийся код (copy‑paste).  
- Длинные списки параметров и флаги boolean вместо отдельных функций.  
- Глобальное состояние, скрытые сайд‑эффекты, скрытые зависимости.  
- Магические числа и строки (magic constants) вместо именованных констант.  
- Плохая обработка ошибок — подавление исключений, пустые catch, игнорируемые ошибки.  
- Хрупкие API/контракты, при изменении мелкого параметра ломается куча мест.  

Критерии и метрики (пороговые ориентиры)
- Цикломатическая сложность функции: >10 — подозрительно; >20 — плохо.  
- Длина функции/метода: >50 строк — стоит пересмотреть; >100 — почти наверняка плохо.  
- Размер класса/файла: >500–1000 строк — часто признак недостаточной декомпозиции.  
- Дублирование кода: >10% — тревожный сигнал.  
- Покрытие тестами: <50% — плохо; 50–80% — риск; >80% — нормально (зависит от контекста).  
- Количество открытых багов/горячих исправлений по одному модулю: растущее число — признак проблем.  
- Время на выполнение тестов/CI: очень долгое (>10–20 мин) — тормозит разработку и ведёт к вырождению качества.  

Паттерны «говно‑кода» (конкретные антипаттерны)
- Spaghetti code — поток управления непонятен.  
- Lava flow — ненужный старый код, который никто не решается удалить.  
- Shotgun surgery — одно изменение требует правки многих файлов.  
- Golden hammer / overengineering — чрезмерно сложное архитектурное решение там, где не нужно.  
- Primitive obsession — широкое использование базовых типов вместо доменных абстракций.  

Инструменты и автоматизация для обнаружения проблем
- Статический анализ: SonarQube, ESLint, Pylint, rubocop, clang‑tidy.  
- Замер метрик: CodeClimate, Sonar, lizard (для сложность), radon (Python).  
- Покрытие: coverage.py, Istanbul/nyc, dotCover.  
- CI/CD: автоматические проверки стиля, тесты, линтеры, slow tests detection.  
- Security scanners: Snyk, Dependabot, Bandit.  

Практический чек‑лист для оценки кода (быстрая ревизия)
1. Сборка/запуск: проект собирается и запускается без хаков?  
2. Тесты: есть ли тесты; можно ли их запускать локально; сколько времени они занимают; покрытие.  
3. Структура: понятны ли модули/пакеты/контракты; нет ли файлов‑монстров.  
4. Именования: имена функций/переменных говорящие? Нет ли аббревиатур?  
5. Дублирование: легко ли найти похожий код в нескольких местах?  
6. Сложность функций: есть ли сильно ветвящиеся места?  
7. Ошибки: проверяется ли возможная ошибка; не игнорируются ли исключения?  
8. Сайд‑эффекты: функции возвращают значения или меняют глобальное состояние?  
9. Документация/комментарии: объясняют ли они «почему», а не «что»?  
10. CI/linters: присутствуют ли автоматические проверки?  

Как отличить «плохой, но работающий» от «плохого и опасного»  
- Работает и редко меняется → может быть «грязным, но приемлемым» (высокий технический долг, но низкий риск).  
- Часто ломается, мешает развитию → нужно рефакторить или переписать участки.  
- Без тестов и с критическими ошибками/уязвимостями → опасно, требует немедленного вмешательства.

Что делать при обнаружении плохого кода
- Оценить влияние (как часто ломается, на сколько это важно для продукта).  
- Собрать метрики и примеры реальных проблем.  
- Небольшими шагами рефакторить (тестируй → рефакторь).  
- Добавить автотесты и линтеры/CI перед рефакторингом.  
- Разделять большие PR на мелкие изменения.  
- Документировать контракт/поведение и добавить интеграционные тесты для критичных участков.  

Примеры «красных флагов» в коде (быстрая проверка в код‑ревью)
- Метод с глубиной вложенности >4.  
- Комментарий «FIXME» или «HACK» в логике, лежащий рядом с важной бизнес‑логикой.  
- try/catch, где catch пустой или логирует «ignore».  
- SQL/шаблоны, склеенные через конкатенацию строк (risk of injection).  
- Использование глобальных переменных или singletons, передающих состояние по всему приложению.  

Если хочешь — могу:
- Прислать короткий чек‑лист в виде задач на ревью (чтоб распечатать/использовать в PR).  
- Посмотреть репозиторий/файл/фрагмент кода и дать конкретные замечания.  
- Подготовить план рефакторинга для конкретного примера (маленькие безопасные шаги).

Напиши, пожалуйста, твою краткую историю опыта (языки, типы проектов, что тебя беспокоит) или пришли кусок кода/ссылку на репозиторий — и я дам более прицельный анализ.
Похожие вопросы