[Перевод] 7 смертных грехов программного проекта
Ремонтопригодность — наиболее важная ценность любого развивающегося программного продукта. Ремонтопригодность измеряется в рабочем времени, необходимом новому подрядчику для изучения продукта до того, как он начнет вносить в него существенные изменения. Чем больше времени на это тратится, тем ниже ремонтопригодность. В некоторых проектах это время стремится к бесконечности, что означает абсолютно непригодный к какой-либо поддержке или внесению изменений продукт. Мы верим, что есть 7 фатальных ошибок, которые ведут к созданию таких неподдерживаемых продуктов. Вот они.
Антипаттерны
К сожалению, все современные программные языки обладают слишком большой гибкостью. Они слишком много позволяют и слишком мало запрещают.
Например, Java не имеет ничего против того, чтобы вы вместили целое приложение в один единственный «class» с помощью 5000 разных методов. Технически приложение компилируется и запускается, но это хорошо всем известный антипаттерн, который называется Божественным объектом.
Таким образом, антипаттерн — это технически допустимый способ разработки, общеизвестный и ошибочный. В каждом языке уйма таких антипаттернов; их присутствие в продукте аналогично наличию опухоли в живом организме. Как только он начинает разрастаться, остановить его уже невозможно. В конечном итоге погибает целый организм. Целый программный продукт становится неремонтопригодным и должен быть переписан.
Как только вы допустили один антипаттерн, их сразу становится больше и больше, и эта «опухоль» только растет.
Это утверждение особенно правдиво для объектно-ориентированных языков (Java, C++, Ruby, and Python), в основном, из-за того, что они многое взяли от процедурных языков (C, Fortran, и COBOL).
Всегда старайтесь относиться с достаточной долей скептицизма к своему проекту и не расслабляйтесь, если он «просто работает». Чем раньше вы диагностируете проблему, тем проще ее вылечить.
Неотслеживаемые изменения
При работе с любым программным продуктом вы должны в любой момент быть в состоянии объяснить, что было изменено, кто это сделал и почему. Более того, время, требуемое для того, чтобы получить ответы на эти вопросы, должно измеряться в секундах. Для большинства проектов это не так. Приведем несколько практических рекомендаций:
Всегда используйте тикеты. Неважно, насколько мал проект или команда, которая его обслуживает — даже если вы работаете над ним в гордом одиночестве, всегда используйте тикеты для любой возникающей проблемы. Объясните в двух словах суть проблемы, зафиксируйте свои предположения. Используйте тикет-систему как временное хранилище для любой информации, имеющей отношение к проблеме. Фиксируйте все, что может в будущем иметь смысл, когда кто-то другой будет пытаться вникнуть в «что-то странное, что происходит с продуктом».
Ссылайтесь на тикеты в коммитах. Нет необходимости поучать, что каждый коммит должен сопровождаться сообщением. Коммиты без сообщений достаточно противная штука; тем не менее, просто сообщения недостаточно. Каждое сообщение должно начинаться с номера тикета, над которым вы работаете. Многие веб-сервисы, например, GitHub, автоматически связывают коммит с тикетов, улучшая отслеживаемость изменений.
Ничего не удаляйте. Некоторые веб-сервисы для хостинга ИТ-проектов позволяют переписать целую ветвь, которая ранее существовала на сервере. Это всего один пример того, как вы можете уничтожить историю развития программного продукта. На таких веб-сервисах многие удаляют комментарии в дискуссиях к большинству тикетов, чтобы дискуссия выглядела почище. Это в корне неверно: никогда ничего не удаляйте. Дайте истории программного продукта право на существование, как бы плохо или запутанно она ни выглядела.
Ad Hoc релизы
Перед доставкой к конечному пользователю каждый программный продукт должен быть упакован. Если это библиотека Java, она должна быть заключена в файл.jar и распаковываться в какое-либо хранилище. Если это веб-приложение, оно должно развертываться на какой-либо платформе, и так далее. Неважно, объемен ли продукт или нет, для тестов, развертываний и форм доставки существуют определенные стандартные процедуры.
Идеальное решение — автоматизировать эту процедуру, чтобы было возможным выполнять ее с командной строки посредством одной команды:
Многие проекты далеки от этого. Процессы их релиза — это всегда что-то магическое, когда ответственный за это человек (также известный как DevOp) должен нажать на определнные кнопки здесь и там, где-то залогиниться, проверить определенные показатели и т. д. Такие релизы называются ad hoc релизами, они типичны для всей индустрии.
Здесь может быть только один совет: автоматизируйте процесс.
Волонтерский статический анализ
Статический анализ — это то, что «причесывает» код. Делая его лучше внешне, мы обеспечиваем его лучшую работу. Однако так происходит только тогда, когда вся команда должна выполнять правила, продиктованные статическим анализатором кода.
Обязательно используйте анализатор кода. В большинстве проектов, где используется анализатор кода, разработчики просто делают на его основе красивый отчет и продолжать писать код дальше — так же, как и делали это раньше. Такой «волонтерский» подход к статическому анализу не делает чести программному проекту. Более того, он просто создает иллюзию хорошего качества.
Статический анализ должен быть обязательным этапом в конвейере разработки продукта, и его правила не должны игнорироваться.
Неизвестное тестовое покрытие
Тестовое покрытие — это степень, в которой ПО прошло интеграционное тестирование. Чем больше покрытие, тем больший объем кода был выполнен во время тестирования. Очевидно, что высокое покрытие — хорошая штука.
Тем не менее, многие разработчики не знаю, каково их покрытие: они просто не измеряют этот показатель. Возможно, они и проводят какие-то тесты, но никто не знает, как глубоко тестируется ПО, а какие его участки не тестировались вовсе. Это гораздо хуже, чем плохое тестовое покрытие, о котором вы рассказали каждому встречному.
Конечно, высокое покрытие — не гарантия высокого качества. Но неизвестное покрытие — это четкий индикатор проблем с функциональной надежностью продукта. Когда проект попадет в руки нового разработчика, он или она должны иметь возможность внести какие-либо изменения и посмотреть, как это влияет на покрытие. В идеале тестовое покрытие должно проверяться так же, как и статический анализ, иначе билд завершится провалом, если покрытие окажется ниже определенного уровня (обычно это 80%).
Непрерывная разработка
Под непрерывной здесь подразумевается разработка без временных рамок и релизов. Неважно, ПО какого типа вы создаете, вы должны часто делать релизы и изменять его. Проект без четкой истории релизов — это просто неподдерживаемая программная неразбериха. Все это потому, что возможность поддержки продукта — это если, например, мы будем в состоянии понять вас, читая ваш код.
Просматривая исходный код и историю его релизов, каждый должен быть в состоянии определить намерения его разработчика, скажем, год назад, что происходит сейчас, дальнейшие перспективы и т. д.и т. п. Вся эта информация должна быть в исходном коде.
Некоторые веб-сервисы для хостинга ИТ-проектов, например, GitHub, имеют сильные инструменты для создания такой информации. Если они есть — используйте их по полной. Помните также, что любая бинарная версия продукта должна быть доступна для немедленной загрузки. Вы должны иметь возможность загрузить версию 0.1.3 и протестировать ее прямо сейчас, если проект в данный момент работает над версией 3.4.
Недокументированные интерфейсы
Каждый участок ПО имеет свой интерфейс, через который предполагается его использовать. Если это веб-приложение, существуют веб-страницы, которые увидит конечный пользователь и с помощью которых он будет использовать приложение. Каждый интерфейс должен быть документирован.
Как и все сказанное выше, этот факт относится к возможности поддерживать продукт. Любой новый программист начинает изучение проекта с его интерфейсов, и любой должен понимать, для чего нужен тот или иной интерфейс и как его использовать.
Мы здесь говорим о документировании для пользователя, а не для разработчика. В общем и целом, мы против документации внутри ПО: работающее ПО гораздо лучше, чем понятная документация к нему. Но это не относится к «внешней» документации, которая предполагается для использования пользователями.
Взаимодействие конечного пользователя с ПО должно быть документировано в обязательном порядке. Если ваша программа — это библиотека, то ее конечные пользователи — разработчики, которые не развивают продукт, а просто используют его как «черный ящик».
Все эти критерии используются для проектов с открытым исходным кодом.