Любая командная разработка может быть эффективной только в том случае, если участники команды имеют общее видение. Если над проектом работает команда, а не один‑два разработчика, то обязательно должен быть стандарт оформления кода — набор правил и соглашений, которые описывают базовые принципы оформления программного кода, используемого совместно группой разработчиков.
TDD — разработка через тестирование
TDD, test-driven development или процесс разработки через тестирование — это методология разработки программного обеспечения, которая основывается на повторении коротких циклов разработки — Red, Green, Refactor:
- Пишется тест или набор тестов, покрывающих желаемое изменение в системе. Написание тестов позволяет лучше понять цель разработки. На этом шаге написанные тесты не должны проходить. «Проваленные» тесты в интерфейсе сред разработки выделяются красным цветом, поэтому эту фазу называют Red.
- Пишется программный код, который реализует требуемое поведение системы и позволяет пройти написанный тест. На этом шаге основная цель — это только добиться прохождения тестов, оптимальная реализация не требуется. Успешные тесты в интерфейсах IDE окрашиваются в зелёный цвет, поэтому и фазу называют Green.
- Проводится рефакторинг написанного кода с постоянной проверкой прохождения всех тестов. Задача фазы Refactor — это улучшение реализации под контролем автоматического тестирования — оптимизация производительности, улучшение читабельности кода и т.д.
При следовании этой методологии тесты пишутся всегда до написания кода, реализующего бизнес‑логику приложения. Или до исправления бага, если написание кода инициировано необходимостью исправить выявленную ошибку.
Тестирование программного обеспечения
Тестирование ПО — это процедура, которая позволяет подтвердить или опровергнуть работоспособность кода и корректность его работы. При осуществлении тестирования приложению передаются входные данные и запрашивается выполнение некой команды, после чего производится проверка полученных результатов на соответствие эталону, если результат соответствует ожидаемому — тест считается пройденным.
Процедура тестирования может осуществляться вручную, но может быть и автоматизирована. В случае автоматического тестирования проверка работоспособности и правильности работы приложения осуществляется гораздо быстрее, полноценнее и фактически чаще (в сравнении с ручным тестированием).
Цикл разработки по TDD
Методика разработки через тестирование заключается в организации автоматического тестирования разрабатываемых приложений путем написания модульных, интеграционных и функциональных тестов, определяющих требования к коду непосредственно перед написанием этого самого кода.
TDD по шагам:
- Добавить тест для новой и еще не реализованной функциональности или для воспроизведения существующего бага.
- Запустить все тесты и убедиться, что новый тест не проходит.
- Написать код, который обеспечит прохождение теста.
- Запустить тесты и убедиться, что они все прошли успешно: прохождение нового теста подтверждает реализацию новой функциональности или исправление существующей ошибки, а прохождение остальных позволяет удостовериться, что ранее реализованная функциональность работает по‑прежнему корректно.
- Заняться рефакторингом и оптимизацией — улучшение сопровождаемости и быстродействия целесообразно осуществлять уже после того, как получилось добиться проверяемой работоспособности. Вносить изменения в код под контролем прохождения тестов всегда проще и надёжнее.
- Перезапустить тесты и убедиться, что они все ещё проходят успешно.
- Повторить цикл.
Преимущества TDD
Эта методология позволяет добиться создания пригодного для автоматического тестирования приложения и очень хорошего покрытия кода тестами. ТЗ переводится на язык автоматических тестов, то есть всё, что программа должна делать, проверяется. Если в приложении выявляются баги, то выявленная ошибка сначала покрывается тестами, а затем уже исправляется, что исключает регресс с повторным появлением ранее исправленных ошибок.
Также TDD часто упрощает программную реализацию: исключается избыточность — если компонент проходит тест, то он считается готовым. Если же существующие тесты проходят, но работает компонент не так, как ожидается, то это значит, что тесты пока не отражают всех требований, а это повод добавить новые тесты.
Архитектура программных продуктов, разрабатываемых таким образом, обычно лучше (в приложениях, которые пригодны для автоматического тестирования, обычно лучше распределяется ответственность между компонентами, а выполняемые сложные процедуры декомпозированы на более простые). Стабильность работы приложения, разработанного через тестирование, также выше за счёт того, что все основные функциональные возможноси программы покрыты тестами и их работоспособность регулярно проверяется.
Сопровождаемость проектов, где тестируется всё или практически всё, очень высока — разработчики могут не бояться вносить изменения в код, если что‑то пойдёт не так, то об этом ещё до релиза сообщат результаты автоматического тестирования.
Если резюмировать, то TDD имеет следующие «плюсы»:
- Повышение качества кода — тесты становятся «живой документацией», описывающей требуемое поведение системы, а код изначально проектируется для тестируемости, что снижает связанность компонентов.
- Раннее обнаружение ошибок — тесты выявляют баги на этапе разработки или тестирования, а не в продуктивной среде.
- Упрощение рефакторинга — вносить изменения в работающий проект не страшно, если есть уверенность, что тесты «поймают» неожиданные побочные эффекты и баги.
- Фокус на требованиях — написание тестов заставляет разработчика изначально определить, что должна делать система, прежде чем решать, как это реализовать.
Рациональное применение TDD
Разработчикам требуется время, чтобы научиться писать эффективные тесты и привыкнуть к подходу TDD. Написание тестов в принципе удлиняет и удорожает разработку на первых этапах, хотя в долгосрочной перспективе повышает стабильность и снижает затраты на отладку.
Стоит помнить, что TDD — это одна из наиболее требовательных к покрытию тестами методологий, и что не стоит сравнивать только две крайности — TDD и разработку вообще без тестирования.
TDD рационально использовать при разработке критических систем, где ошибки недопустимы. TDD полезно в долгосрочных проектах, когда изначально понятно, что кодовая база будет расширяться и поддерживаться годами.
Не стоит использовать TDD при разработке прототипов, при проверке бизнес‑гипотез или в исследовательских задачах с неясными требованиями — многократное переписывание не только бизнес‑логики, но и всех тестов, весьма ресурсоёмкая задача. Тоже самое касается и очень маленьких или «одноразовых» проектов, где окупаемость потраченных на тесты усилий будет незначительна.
Во всех остальных случаях вполне можно как использовать, так и не использовать TDD. Всегда можно искать собственный баланс между скоростью разработки и уровнем тестирования. Вполне разумно бывает писать тесты не на всю логику, а только на ключевую функциональность, а также покрывать код тестами не до разработки, а уже после.
Заключение
TDD — это не инструмент тестирования, а философия разработки, которая учит мыслить через призму требований и надежности. Несмотря на начальные сложности, в больших проектах ресурсоёмкость TDD окупается снижением числа ошибок, упрощением поддержки и повышением уверенности в коде.
Тематические статьи
SOLID это аббревиатура пяти основных принципов проектирования в объектно-ориентированном программировании, предложенных Робертом Мартином:
- Single responsibility — принцип единственной ответственности
- Open-closed — принцип открытости / закрытости
- Liskov substitution — принцип подстановки Барбары Лисков
- Interface segregation — принцип разделения интерфейса
- Dependency inversion — принцип инверсии зависимостей
Принцип заключается в том, что возможности, которые не описаны в требованиях к системе, просто не должны реализовываться. YAGNI основан на идее, что большинство «гипотетических» возможностей, которые кажутся полезными на этапе проектирования, никогда не будут востребованы. Реализуя их заранее, разработчики тратят время, усложняют код и повышают риск ошибок.
KISS — это принцип проектирования и программирования, при котором простота системы декларируется в качестве основной цели или ценности. Большая часть программных систем необосновано перегружена практически ненужными функциями, что ухудшает удобство их использование конечными пользователями, а также усложняет их поддержку и развитие разработчиками. Следование принципу KISS позволяет разрабатывать решения, которые не обладают этими недостатками: они просты в использовании и в сопровождении.
Следование принципу DRY позволяет добиться высокой сопровождаемости программного продукта: внесение изменений и тестирование значительно упрощаются. Если код не дублируется, то для изменения логики достаточно внесения исправлений всего в одном месте. Также значительно проще тестировать одну (пусть и более сложную) функцию, а не набор из десятков однотипных. При следовании DRY упрощается и повторное использование функций, вынесенных из сложных алгоритмов, что позволяет сократить время разработки и тестирования новой функциональности.
Флаги функций позволяют отделить развертывание функциональности от развертывания кода, обеспечивают возможности для A/B-тестирования и предоставляют механизм быстрого отключения проблемных функций.
Trunk Based Development (TBD) или транковая разработка — модель ветвления системы управления версиями, при которой все разработчики работают в одной ветке. Эта модель имеет значительные преимущества с точки зрения совместной работы, качества кода и скорости доставки изменений.
Информационная безопасность важна практически для любого бизнеса, так как деятельность почти всех компаний достаточно существенно зависит от информационных технологий. Взломы, утечки данных и неработоспособность ключевых систем приводит как к финансовых потерям, так и к репутационным издержкам. Чтобы снизить риски в сфере ИБ стоит внедрять базовые процессы ИБ в разработку, тестирование и системное администрирование.
MVC — это паттерн проектирования приложений, который разделяет на три отдельных компонента модель данных приложения, пользовательский интерфейс и слой взаимодействия с пользователем. В парадигме MVC контроллер определяет способы взаимодействия пользователя с приложением, модель — за слой хранения данных и бизнес‑логику, а представление — за пользовательский интерфейс / формат выходных данных. Модификация каждого из этих компонентов либо оказывает минимальное воздействие на остальные, либо не оказывает его вовсе. Это облегчает понимание логики работы системы и упрощает внесение изменений в кодовую базу.