OpenQuality.ru

Качество программного обеспечения

Качество программного обеспечения: в главных ролях

Лента  Радар  Блог  Опыт  
Разум  Видео  Заметки  Эпизоды


 

Идеи глупо держать под подушкой

Александр Дёмин | 12.11.2010

Александр Дёмин работает в компании Bloomberg, ведет популярный блог «Программирование – это просто», разрабатывает и поддерживает несколько полезных инструментов для разработчиков. Перевел документацию по Google C++ Testing Framework и Google C++ Mocking Framework. В интервью Александр рассказывает о своих подходах к созданию приложений и делится накопленным опытом.

Александр, как происходит разработка приложения после того как идея появилась на свет, и вы готовы приступить к ее реализации?

Обдумывание общего дизайна, проработка открытых и неясных вопросов (или хотя бы определения списка таких вопросов), далее общая оценка по времени. Если она укладывается в требования, то можно приступать к фазе подробной проработки выставленных требований, чтобы максимально избавиться от ситуаций «а как это вообще реализовывать?» на стадии программирования. Далее можно уже дробить на подзадачи, распределять их в команде и – вперед!

Пишите ли вы псевдокод, создаете ли прототипы или сразу же приступаете к созданию «боевой» системы?

Псевдокод редко, обычно только для всяких хитрых алгоритмов. Иногда делаю простые прототипы, например для «проверить протокол» и «попробовать нагрузить кластер» и т.д. Обычно использую Python или PHP.

В разрезе создания большой системы: какой стиль разработки нисходящий или восходящий вы предпочитаете и почему?

У меня чаще всего бывает так: сначала макеты низкоуровневых компонентов для проверки принципиальных каких-либо возможностей что-то сделать, куда-то подключиться, попробовать что-то послать и т.д. Далее разработка идет с двух концов: сверху пишется общий остов системы с заглушками, а с другой стороны пишутся сами заглушки, которые постепенно заменяются реальными модулями, когда общий дизайн более менее устаканивается. Иногда заглушки могут «по-быстрому» создаваться на «легком» языке типа Python (если задача позволяет), особенно всякие модули коммуникации или преобразования данных, на которых идет общая проверка правильности дизайна, а потом пишутся нормальные версии этих модулей на основном языке.

Применяете ли вы TDD? Оправдан ли этот подход в ваших проектах?

Да, да и да! Увы, лично ко мне это понимание пришло только несколько лет назад. Сейчас я просто не представляю любую разработку, длиной более нескольких сотен строк, без TDD. Начинаю проект на С++ и сразу настраиваю Google Test, чтобы тесты запускались перед каждой сборкой. Аналогично для проектов на Java и Python. TDD – это механизм превращения ваших знаний об архитектуре проекта в исходники, которые в любой момент можно скомпилировать и запустить. Один хороший тест стоит сотни слов в документации сопровождения.

TDD – огромная тема. Множество техник и подходов, но для меня вывод один: в той или иной форме проект должен иметь систему автоматического самотестирования. Лично пока я не встречал проектов, где я мог бы на 100% сказать: «нет, тут нам TDD вообще не подходит».

Гибкие технологии (Agile, XP, Scrum): насколько они эффективны на практике?

Есть простые вещи, в которые я верю: TDD, короткие итерации (неделя или две), после которых необходимо подвести итоги и определить планы на следующую итерацию, и невмешательство менеджмента в определение сроков разработки. Остальные вещи, такие как утренние пятиминутные летучки, burn down charts – это уже приятные мелочи: их здорово применять, но можно жить и без них.

Несколько слов о парном программировании. Я нахожу эту методику очень полезной, когда надо написать реально сложный кусок кода, например, реализовать алгоритм максимально эффективно. По сути, парное программирование имеет общие черты с коллективной работой за «классной» доской, когда совместно решается какой-то проектный вопрос и проводится планирование. Но в случае парного программирования уже надо не подготовить набросок или план, а написать реальный код.

Расскажите, пожалуйста, о наиболее загадочном баге в вашем коде.

Единственное, что вспоминается, это случай, когда после перехода на новую версию компилятора начали происходить необъяснимые вещи, причем в разных местах, и независимо друг от друга. В итоге выяснялось, что в новой версии был баг в генерации кода, который проявлялся при некотором сочетании опций оптимизации. Например, банальное сложение двух строк в некотором контексте языка работало неверно. Но в том проекте совсем не было unit-тестов, поэтому расследование и анализ проблемы пришлось делать на функционирующей системе со всеми включенными системами логирования, чтобы понять, где искажаются данные. Модульные тесты сразу же показали бы источник проблемы и сэкономили тучу времени.

Анализ чужого программного кода: каковы признаки плохого и хорошего кода?

Спорить о хорошем коде сложно, так как может быть очень много различных мнений. Проще остановиться на явных признаках плохого кода. Для меня первый признак плохого кода – неряшливость. Если я вижу «временно» закомментированные куски, блоки «ToDо» там-сям, плохое и разностилевое форматирование, то это индикация того, что в коде нет порядка, а значит нет порядка и в голове его автора. Далее идут более очевидные вещи: классы, методы и функции длиной в среднем более 100 строк, исходные файлы более тысячи строк, непонятные имена. Для меня это явно плохо без каких-либо сомнений. Конечно, могут быть исключения для библиотек широкого пользования, но для прикладного кода – нет.

Обычно старый «legacy» код больших промышленных систем на Си или Фортране страдает огромными функциями, отсутствием четкой модульности и практически невозможностью покрыть его модульными тестами.

Где искать образцы хорошего кода?

Я люблю читать исходники больших и сложных проектов. Например, Google Chrome или Google NaCl. Для меня это пример того, как надо создавать код. Жесткая стилистика кода, вплоть до контролирования отсутствия концевых пробелов (может затруднять автоматизированное слияние различных веток), максимальная автоматизация тестирования и сборки, code review. Это кладезь примеров и руководств к действию.

Выбор языка программирования для создания приложения: насколько он важен?

Выбор языка важен, но очень часто язык является не выбором, а данностью. Если в компании уже много лет пишут на С++, то вряд ли удастся обосновать написание какого-то одного проекта на Java. Но если все же есть возможность выбора, то тут стоит задуматься, ибо грамотный выбор может определить успех проекта. Например, насколько важна портируемость, масштабируемость, многопотоковость, наличие каких-то специализированных библиотек.

Может ли тот или иной язык сделать код более качественным, а разработку более эффективной?

Говоря о двух на данный момент самых популярных языках для больших проектов, С++ и Java, отмечу, что в Java проще обстоит дело с тестированием благодаря механизму reflection и виртуальной машине в целом, но, с другой стороны, С++ допускает больше гибкости при работе с низкоуровневыми вещами. Python удобно встраивать как дополнительный язык скриптования и т.д. Лично я не имею какой-либо объективной привязанности к одному языку. Да, есть опыт в некоторых, который может повлиять на выбор, но в целом ничто не мешает изучить новый язык при случае. Например, недавно реально погрузился практически с нуля в Lua, так как это очень удобный язык, например, для встраивания и создания «умной» нестатической конфигурации.

Каковы, на ваш взгляд, наиболее важные навыки, знания для эффективного программиста?

Знания: чем больше, тем лучше. Больше проектов, больше операционных систем, языков, библиотек, алгоритмов и т.д. Лично для меня есть два доминирующих фактора: умение доводить дело до конца и быть разносторонним и интересующимся человеком (участвовать в разработках с открытым кодом, писать и читать блоги, следить за новостями индустрии).

Табу для разработчика: каких проколов не стоит допускать при создании программных продуктов?

Не стоит пренебрегать формальными процедурами при разворачивании проекта на боевую, особенно если это онлайн проект, и можно задеть много клиентов. Обязательно code review (особенно для «экстренных» изменений), план тестирования и разворачивания.

Модульные тесты и QA: где заканчивается первое и начинается второе?

Unit-тестирование не имеет выделенного начала и тем более конца. Модульные тесты – это часть проекта. Они существуют, поддерживаются и развиваются, пока развивается сам проект. А раз они часть проекта, то их прогон перед каждой сборкой выполняется до тех пор, пока выполняется сама сборка.

QA. Из своего опыта могу сказать, что первый человек, кто должен задаться вопросом «как мы будет все это тестировать?» – это сам программист. Тестирование начинается практически сразу, когда есть более-менее работающий кусок функциональности. В идеале, все тестирование должно быть автоматизированным, а проводить его должен сам программист. Но в реальной жизни что-то приходится делать вручную. И чтобы программист все еще имел время на дальнейшую разработку, создаются выделенные отделы тестирования. Но изначальная информация о том, как и что тестировать, исходит от разработчиков.

Кстати, именно поэтому мне импонируют модели гибкой (agile) разработки, когда короткие итерации позволяют четко сформулировать, что именно надо тестировать.

Разворачивание системы в Production: что нужно учесть?

Вот базовые шаги, которые предприниматься у нас в компании Блумберг:

• любой код всегда проходит code review
• любой код всегда тестируется QA-инженером, а не только самим программистом (хотя это может быть другой программист)
• любой код всегда независимо тестируется в dev-среде, затем в alpha-, затем в beta-среде, и только потом идет в Production
• при достижении Production разворачивание происходит веерно, чтобы при возникновении проблем затронуть как можно меньше клиентов
• все описанные шаги фиксируются в системе, чтобы всегда можно было понять полную историю произошедшего

Конечно, в экстренных случаях любое из правил можно исключить, но при этом чем больше шагов исключается, тем больше людей (в том числе и менеджеров) подписывают такой шаг. Несмотря на наличие всех этих шагов, штатные релизы в Production каждую неделю являются нормой.

В чем отличие dev-среды, alpha-среды и beta-среды с точки зрения тестирования?

Каждая из этих сред постепенно приближается к Production. Например, в dev программист может делать все, что угодно. В alpha происходит первая стадия интеграции, но пока без вовлечения данных реальных клиентов. Но тут уже можно действовать только в рамках установленных правил и надо учитывать функционирование других систем. Beta – почти боевая среда. Технически, beta-машину можно превратить в боевую.

Какие типы багов/несостыковок обнаруживаются при тестировании в каждой из этих сред?

Обычно, при подобном многошаговом тестировании выявляются баги, связанные со средой и внешними связями, так как формальные ограничения заставляют убирать «подпорки» и заглушки, оставшиеся с dev-среды, документировать процедуры тестирования и управления разворачиваемой функциональностью.

Как проходит веерное разворачивание? Если система в онлайне, то разве она не едина для всех клиентов? Или все же можно обеспечить «дробление» клиентов: часть из них перешла на новую версию, а часть остается на старой?

Именно так. Часть клиентов работает на новой версии, а часть еще на старой. Способов тут несколько. Разные клиенты могут использовать физически разные машины, поэтому боевые сервера получают обновления по очереди. Также можно встраивать в код специальные программные переключатели:

if (is_feature_XXXX_active_for_client_YYYY()) {
... //
}

В зависимости от конфигурации эти переключатели управляют выполнением разных кусков кода. Новый код оборачивается в такой переключатель, и если что-то идет не так, можно одним движением в конфигурации отключить новый код.

Такие конструкции обязательны для любой новой функциональности или тем более, баг-фиксов. Конечно, такой подход требует определенного структурирования вносимых изменений, поэтому, возвращаясь к тому, что я говорил ранее, первый человек, который задумывается о тестировании и разворачивании – это программист.

Специальная библиотека позволяется контролировать значения таких функций централизованно и очень быстро распространять изменения между множеством машин. После некоторого времени стабильной работы такие «переключатели» объявляются устаревшими и удаляются. Это тоже обязательная процедура, иначе весь код будет ими завален. Логирование позволяет своевременно отслеживать «протухшие» переключатели и посылать их авторам уведомления о необходимости удаления.

Авралы: как часто они случаются в вашей практике и что обычно является их причиной?

Чаще всего аврал случается из-за слишком оптимистичного планирования. Мне кажется, очень важно уметь притормозить, умерить пыл в случае когда «мы выкатим это в Production завтра» и спланировать с реальной скоростью.

Как вы планируете сроки (время, которое выделяется на создание той или иной функциональности)?

По сути, пальцем в небо. Чтобы это небо уменьшить, надо дробить работу на короткие итерации, тогда и цена ошибки будет меньше.

Александр, большое спасибо за интервью. Успехов в ваших проектах!

Комментарии (5)

«В идеале, все тестирование должно быть автоматизированным, а проводить его должен сам программист. Но в реальной жизни что-то приходится делать вручную. И чтобы программист все еще имел время на дальнейшую разработку, создаются выделенные отделы тестирования. Но изначальная информация о том, как и что тестировать, исходит от разработчиков.»

Для любой более менее сложной системы автоматизировать все никогда не получится, ибо немыслимое число тестовых последовательностей и комбинаций. Автоматические тесты вне сомнения должны быть, причем разноуровневые, функциональные тесты должны разрабатываться QA.
А вот насчет как и что тестировать должно исходить от разработчиков, в принципе неверно. По собственному опыту могу сказать, что тестировщик, знающий архитектуру и слабые места системы может гораздо эффективные проверить и вскрыть такие места, о которых разработчик даже и не догадывается.

Pol Stashevsky | 15.12.2010 | 7:08 дп. Ответить #

Павел, спасибо за комментарий.

Конечная цель всего процесса разработки – получение продукта, востребованного пользователями. Проект проекту (и продукт продукту) рознь. В одних случаях роль команды QA более существенна, в других менее. К примеру, если разрабатывается серверная часть биллинговой системы, то, возможно, разработчик сможет охватить модульными тестами все базовые сценарии ее работы. Да, можно говорить, что он о чем-то даже не догадывается, но если такая форма работы приносит ожидаемый результат, то и хорошо.

Есть много успешных продуктов, успех которых в немалой степени определялся эффективной работой тестировщиков. Есть много успешных проектов, в которых выделенные тестировщики не были задействованы. Серебряной пули нет – в каждом проекте свои особенности.

Кстати, немыслимое число тестовых последовательностей и комбинаций гораздо вероятнее охватить автотестами, нежели усилиями даже самых эффективных тестировщиков. С другой стороны, тестировщик, знающий архитектуру и слабые места системы – это действительно ценный сотрудник. О важности таких людей были соответствующие заметки (http://blog.openquality.ru/testing-wanted/ , http://blog.openquality.ru/lucky-to-be-a-tester/ , http://blog.openquality.ru/intuition-in-software-testing/ , http://blog.openquality.ru/proactive-skills/ , http://blog.openquality.ru/exploratory-testing/ ). И в то же время, это не отменяет того факта, что нужно плясать от особенностей проекта, а не от обобщенных утверждений…

Кормчий | 15.12.2010 | 8:05 дп. Ответить #

«Тестирование начинается практически сразу, когда есть более-менее работающий кусок функциональности.»

- по канонам тестирование следует начинать, пока еще даже и не написан функционал – тестировать требования, тестировать данные. Это вкратце.

Хотя скорее всего имелось в виду мануальное непосредственное тестирование: нажимание кнопочек, ввод данных и т.д.

bob | 04.02.2011 | 9:04 дп. Ответить #

Bob, спасибо за комментарий.

«по канонам тестирование следует начинать, пока еще даже и не написан функционал – тестировать требования, тестировать данные.»

Да, все верно. Просто «дофункциональный» этап можно назвать по-другому: скажем, «анализ», «исследования».

Кормчий | 04.02.2011 | 9:56 дп. Ответить #

Знакомый утверждал, что в Блюмберге только зарубежные программисты работают. дам ему посмотреть этот адрес. А сайт действительно полезный в плане скажем истории валют. Должников удобно рассчитывать если долларами занимал)

медик | 12.07.2011 | 1:47 пп. Ответить #

Оставьте комментарий

Required.

(будет спрятан за семью замками)

(будет открыт, если это не спам)

Получать новые комментарии по электронной почте. Вы можете подписаться без комментирования.