«Накостылить» или «подпереть костылями» — значит создать временное решение проблемы, которое закрывает баг или добавляет функционал, но не устраняет первопричину и не соответствует архитектурным стандартам проекта. Костыли неизбежны в любой разработке: дедлайны, неполное понимание системы и внешние ограничения заставляют принимать компромиссные решения. По данным Refactoring Guru, ключевое различие между прагматичным костылём и техническим долгом — в осознанности решения и наличии плана по его устранению. Грамотное использование временных решений требует дисциплины и документирования.
Главное
Костыль (crutch) — программное решение, которое работает, но сделано «на скорую руку»: оно закрывает конкретную проблему, но не устраняет её причину, не следует архитектуре проекта и может сломаться при малейших изменениях окружения. Метафора точна — как и реальный костыль, такой код помогает «идти», но не лечит «ногу».
Разработчики «подпирают костылями» баги, несовместимости версий, особенности платформы и срочные требования заказчика. Типичный костыль — костыль-условие: если iOS 15 добавь отступ, если Huawei — скрой кнопку. Такие проверки множатся и превращают код в «слоёный пирог» из платформенных и версионных ответвлений.
Костыли бывают разных масштабов: от одной строки с костыльным условием до целого модуля-прослойки, который «исправляет» поведение библиотеки. Важно понимать, что костыль — это не всегда зло: в правильных руках это инструмент, позволяющий релизнуть продукт вовремя. Проблема начинается, когда костыль остаётся в коде навсегда.
Основная причина появления костылей — конфликт между идеальным решением и реальными ограничениями проекта. Разработчик знает, как сделать правильно, но время, деньги или технические ограничения не позволяют этого сделать. В результате появляется компромиссное решение, которое «просто работает».
Рассмотрим четыре основные причины, по которым разработчики сознательно идут на костыли. Понимание этих причин помогает относиться к костылям не как к ошибке, а как к прагматичному инструменту, который нуждается в управлении.
Самая частая причина. Релиз завтра, баг воспроизводится только на конкретной модели, чинить архитектурно — две недели. Костыль-условие занимает час и закрывает проблему. После релиза команда обещает вернуться и переписать правильно. «Временного нет ничего более постоянного, чем постоянного нет ничего более временного» — именно про такие костыли.
Библиотека A требует Android 12, но ваше приложение поддерживает Android 10. Решение — написать прослойку, которая проверяет версию ОС и выбирает путь выполнения. Это костыль, потому что при обновлении библиотеки прослойку придётся переписывать. Но альтернатива — отказ от библиотеки или поддержки старых устройств — может быть хуже.
// Crutch for API 29 compatibility
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
useModernApi()
} else {
useLegacyFallback()
}
Библиотека, от которой зависит проект, содержит баг, но её обновление может занять недели (нужен PR, код-ревью, публикация). Вместо ожидания команда пишет wrapper, который патчит поведение библиотеки на лету. После выхода исправленной версии библиотеки wrapper удаляется. Если не удалить — это уже архитектурная проблема.
Новый разработчик в legacy-проекте не понимает, почему код работает именно так. Вместо того чтобы разобраться, он добавляет новое условие поверх существующего. Это самый опасный тип костыля, потому что автор не осознаёт, что это костыль. Единственное лекарство — код-ревью и парное программирование для новых членов команды.
Не каждый костыль — зло. В реальной разработке абсолютная чистота кода недостижима и часто нецелесообразна. Прагматичный подход признаёт, что временные решения — часть процесса, но требует их осознанности, документирования и планирования устранения. Костыль оправдан, когда он решает бизнес-задачу быстрее, чем чистое архитектурное решение.
Критерии оправданного костыля: он закрывает конкретную проблему, у него есть owner (кто отвечает за его удаление), и существует план рефакторинга. Если хотя бы одного из трёх условий нет — костыль превращается в технический долг. Инструменты вроде TODO-комментариев с тикетом в трекере — минимальный способ документирования.
Критический баг в релизной ветке, который нужно закрыть до завтрашнего деплоя. Чистое решение требует рефакторинга архитектуры и займёт две недели. Костыль — добавить проверку на nil и отправить фикс как hotfix. Условия оправданности: в трекере создан тикет на рефакторинг, ответственный назначен, костыль помечен комментарием. Через две недели команда возвращается к задаче.
// TODO: IT-1234 — remove this crutch after AuthService refactoring
guard let userId = session.user?.id else {
return Result.failure(.notAuthenticated)
}
Граница между осознанным костылём и архитектурной проблемой (техническим долгом) проходит по двум параметрам: осознанность решения и наличие плана по его устранению. Костыль — это всегда временное решение с известным сроком жизни. Технический долг — это последствия множества костылей, оставленных без внимания.
| Параметр | Осознанный костыль | Технический долг |
|---|---|---|
| Осознанность | Команда знает, что это временное решение | Никто не помнит, почему код такой |
| Документация | Есть TODO, тикет в трекере | Нет комментариев, ссылок, описания |
| План устранения | Назначен спринт для рефакторинга | «Когда-нибудь перепишем» |
| Влияние | Локальное, не мешает новой функциональности | Блокирует изменения, замедляет разработку |
Ситуация ухудшается, когда количество костылей превышает критическую массу. Каждый новый костыль увеличивает «хрупкость» системы: изменение в одном месте ломает другое. В итоге разработка замедляется, баги множатся, а новый разработчик не может разобраться в коде без помощи автора. В этот момент костыли перестают быть временными решениями и становятся архитектурной проблемой.
Если в коде встречается пять вложенных проверок на версию ОС, производителя устройства и наличие конкретной библиотеки — это не костыль, это архитектурная проблема. Если добавление одного фикса вызывает три регрессии в смежных модулях — костыли перестали быть локальными. Если код-ревью регулярно отклоняется из-за «ещё одного костыля» — пора планировать рефакторинг.
Рефакторинг костылей — процесс замены временных решений на архитектурно корректные. Это требует времени, поэтому нужна стратегия приоритизации: не все костыли нужно устранять немедленно. Хорошая стратегия — оценивать каждый костыль по двум параметрам: частота изменений в этой области кода и влияние на пользователей.
Высокий приоритет — костыли в часто изменяемых модулях (бизнес-логика, UI общего назначения), которые замедляют разработку и вызывают регрессии. Средний приоритет — костыли в редко изменяемых модулях, но с потенциальным влиянием на пользователей (обработка платежей, авторизация). Низкий приоритет — костыли в legacy-коде, который работает стабильно и не планируется к модификации.
Шаг 1: инвентаризация — найди все TODO и FIXME, связанные с костылями. Шаг 2: оценка — определи, какие из них всё ещё актуальны. Шаг 3: планирование — назначь рефакторинг костылей в спринт, начиная с высокоприоритетных. Шаг 4: замена — реализуй чистое решение, удали костыль и его TODO-комментарий. Шаг 5: верификация — убедись, что тесты проходят и регрессий нет.
# Find all TODO-crutches in the project
grep -r "TODO\|FIXME\|HACK\|XXX" --include="*.kt" --include="*.swift" .
Лучший способ бороться с костылями — не создавать их без необходимости. Перед тем как написать костыль, задай себе три вопроса: можно ли сделать чистое решение за разумное время? Есть ли альтернатива, которая не является костылём? Будет ли у команды время вернуться и переписать это? Если хотя бы на один вопрос ответ «нет» — подумай ещё раз, прежде чем «подпирать» код.
Часто задаваемые вопросы
Накостылить — написать временное решение, которое закрывает проблему, но не устраняет её причину. Код работает, но не соответствует архитектуре проекта и может сломаться при изменениях.
Костыль — осознанное временное решение с планом устранения. Технический долг — последствия множества забытых костылей. Костыль локальный, долг системный и блокирует развитие.
Когда дедлайн критичен, чистое решение требует времени, а костыль документирован TODO-комментарием и тикетом в трекере. Условие: у костыля есть план удаления в обозримом будущем.
Добавьте TODO или FIXME с номером тикета и кратким описанием правильного решения. Пример: // TODO: IT-567 — rewrite using Factory pattern. Без тикета костыль будет забыт.
Проведите инвентаризацию всех TODO, оцените приоритет, начните с часто изменяемых модулей. Заменяйте костыль на чистое решение, удаляйте комментарий и проверяйте тестами.
Итоги
Мы разработаем мобильное приложение под ключ
IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.
Читайте также