*** ВНИМАНИЕ: Блог переехал на другой адрес - demin.ws ***

воскресенье, 17 мая 2009 г.

Travis Swicegood, "Pragmatic Version Control using Git"

Travis Swicegood

Pragmatic Version Control using Git



Хорошее введение в распределенную систему контроля версий Git от сообщества разработчиков ядра Линукса и от Линуса Торвальдса в частности.

Я ценю такие книги за начальное вовлечение в предмет. Это книга для начинающих, и если вы не новичок в области распределенных систем контроля версий, то вы ее проглотите за вечер и захотите более глубоких знаний по Git. Так и произошло со мной. Я прочитал книгу за вечер, она сформулировала в голове десятки неотвеченных вопросов и позволила мне понять — на какие вопросы мне нужны ответы.

На официальном сайте есть превосходная электронная живая книга по Git. Многие главы имеют дельные коротенькие видео уроки.

Вывод: обычно я не храню книги "для начинающих", так как после них ты либо никогда предметом не интересуешься, либо копаешь глубже и знания для начинающих становятся очевидными. Но эту я оставлю.

P.S. Для интересующихся распределенными системами контроля версий рекомендую отличный блог про альтернативую систему Bazaar "Базарный день". Прочтете несколько постов и будете готовы использовать Bazaar.

Как вы пишете в Blogspot?

Лично я считаю, что Blogspot имеет радикально неудобный интерфейс для ввода и тем более последующего редактирования постов. Полное “сведение” поста в нем — это кошмар. Сначала ты пишешь основной текст в Ворде, затем вставляешь исходники, если нужно, и потом начинается длительное ёрзанье в html для придания посту правильного вида в браузере.

Так как предварительный просмотр поста в Blogspot не дает полной картины, то единственный способ проверить вид поста, это его, собственно, запостить. Но кому охота выкладывать недоделанный пост? Итерация правки поста крайне неудобна и медленна — цикл “правка –> просмотр –> постинг –> ошибка –> правка –> ...” очень коряв.

После некоторого времени использования Blogspot я пришел вот к такой схеме.

Для начала, нужен таки блог-клиент, как бы этого не хотелось. Тут тебе и вордовая проверка текста встроена, и preview какой никакой есть, и сохранение черновика и много прочих мелких радостей. Перебрав Semagic, BlogJet, несколько клиентов на Яве и придя от всего увиденного в ужас, а остановился, как ни странно на Microsoft Live Writer. Бесплатный (чудо для продукта от Microsoft), понимает Blogspot, много плагинов и встроенная вордовая проверка текста (то есть можно сразу в нем писать). В целом, почти все хорошо.

Но как бы не был хорош preview блог-клиента, единственный способ полностью проверить верстку в Blogspot — это запостить. Для этого можно завести еще один блог, тестовый, который должен быть точной копией основного блога в плане стилей и макета страницы. Теперь можно спокойно постить черновик в тестовый блог и отлаживать верстку окончательно. Причем цикл отладки выглядит так: редактирование в блог-клиента -> постинг в тестовый блог -> refresh страницы в браузере. Гораздо быстрее чем была, так как надо просто переключаться между окнами.

В конце отлаженный пост переносится в основной блог просто копированием html-кода.

понедельник, 11 мая 2009 г.

Табуляция

Символы табуляции в исходниках — это бесконечное зло. А зло в квадрате, когда табуляция используется не только для отступов слева, но как разделитель (например, между аргументами функций, в теле блоков комментариев и т.д.). Ничего, кроме криков из другого конца комнаты типа "какая б... опять дописала кусок в моем неприкосновенном исходнике на С в Эклипсе, используя пробелы вместо табов, так что у меня тут в vi съехали все отступы?". И тут оба неправы. Первый в том, что не использовал тип отступов, принятый уже в существующем документе, а второй — в том, что использовал табуляцию изначально. Все шоколадно и солнечно, когда все сидят в Студии, но когда один использует vi, другой Студию, третий - FAR и т.д. (а это, увы, реалии много-платформенной разработки), то невозможно, чтобы все следовали правилу. Никто не любит соблюдать неудобные правила.

Лично я очень спокоен на тему стиля в целом и длины отступов в частности (лишь бы выглядело читабельно и соответствовало принятому для проекта соглашению), но вот табуляция — это как красная тряпка.

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

понедельник, 4 мая 2009 г.

Автоматизация сборки продукта

Лично я убежден на 100%, что сборка более менее серьезного по размерам проекта/продукта должна производиться в командной строке, то есть никаких GUI-сред, в которые надо заходить, нажимать кнопки, смотреть в окна результатов и т.д. Все это здорово на этапе собственно написания кода, тестирования и отладки. Но когда код переходит в стадию “почти закончен”, все должно заканчиваться полностью авторизированной сборкой без вариантов “тут надо кликнуть, тут надо ввести путь, тут надо сделать clean-up и refresh, а то все съедет” и т.д. Прелесть командной строки в том, что вне зависимости с какого ты сегодня будуна, и что твоя голова с утра проходит в дверь только боком, ты набираешь “cd /my/super/project” и затем “make”. После этого ты откидываешься на стул в мыслях о пивасике, а проект тем временем собирается и тестируется. В идеале, конечно, вместо компиляции, ты должен просто скачать свежую автоматизированную ночную сборку, которая уже там, оттестирована и готова к употреблению.

Ладно, это была всем очевидная лирика.

Наш софт представляет собой монструозный симбиоз из С, С++, Java, BASIC (это наш собственный внутренний СУБД-ориентированный язык), Python’а и UNIX-скриптов. Система же сборки основана на GNU Make и по сути является огромным многоуровневым Makefile’ом. Необходимая при сборке логика, которую нельзя реализовать напрямую в GNU Make дополняется UNIX-скриптами и мини утилитками на C, которые компилируются прямо перед запуском. Java части используют Ant. Плагин Ivy используется для подкачки из репозитория двоичных модулей. Лично я против каких-либо двоичных файлов в проекте, и считаю, что в разы удобнее все компилировать из текстового представления (пусть это и дольше по времени), так как текстовики можно сравнивать, в них можно искать и т.д. Конечно, реальная жизнь сложнее, и иногда приходится использовать заранее собранные бинарники (например, OpenSSL, ICU, тучу сторонних jar’ов для Java и т.д.).

Итак, ясно, такая сборка со временем деградирует, становится сложнее, запутаннее, в ней сложно искать ошибки, а тем более узкие места.

Я пытался все перевести на Ant – возможностей много, но все крайне Ява-центричное, расширения надо тоже писать на ней же. Если мы все писали бы на Java, но у нас не тот случай.

Пробовал CMake. Очень неплохо, но обнаружились сложности скрещения с нашим собственным компилятором Бейсика.

Пробовал SCons. Пожалуй, это самая прикольная система. Недаром ее используют в Гугле для реально нетривиальных проектов типа Chrome и Native Client и т.д. По сути Makefile – это программа на Питоне, то есть ограничения на особую логику сборки (запуск тестов, фильтров, сборка документации, публикация результатов на FTP и т.д.) просто отсутствуют. Нужное просто пишется на полноценном языке программирования Питон. Удалось мне даже собрать нормально Питон для AIX и HPUX (с Windows, Linux, Solaris проблем нет вообще). Но и тут получилась ложна гов... дегтя. У меня есть необходимость конвертировать тысячи отчетов по тестам в формат jUnit. Мини утилитка на С, которая писалась на коленке, делает это менее чем за секунду. Все мои попытки на Питоне работали минуты. Получается, что идея опять не чиста, так как нужны опять сопровождающие утилиты, и уже не ясно, зачем что-то менять как оно есть сейчас.

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

 

Посты по теме:

воскресенье, 26 апреля 2009 г.

Система автоматизированной интеграции Hudson

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

Мы использует для этих нужд Hudson. Написано на Java, управляется через веб-интерфейс.

Несмотря на мою нелюбовь к Java, лично я мирно ужился с этой программой.

Что умеет Hudson, и для чего он нужен?

Hudson — это программа, которая умеет запускать скрипты локально или на удаленных машинах в зависимости от различных условий. Скрипты обычно производят сборку, тестирование, генерацию отчетов и документации, а события — это в основном поступление новых изменений в систему контроля версий.

Для начала, Hudson построен на плагинах, коих много, под разные запросы и желания.

Первый плагин, который нужен был конкретно нам — это плагин для работы с Perforce. Он умеет периодически опрашивать Perforce о наличии новых commit’ов и инициировать некоторые события, например сборку или запуск тестов.

Далее, ключевой момент для нас. Hudson имеет master-slave архитектуру, что позволяет с одного головного компьютера (master) проводить компиляцию, тестирование, архивирование и т.д. на множестве slave-машин. Так как наш софт поддерживается на нескольких разных типах UNIX и на Windows, по подобный подход очень упрощает управление таким зоопарком сборочных машин. Время разворачивания очередного slave’а — несколько минут (копирование slave.jar, запуск “java –jar slave.jar” и прописывание адреса этого slave’а на головной машине).

Еще мы активно используем плагины для посылки извещений по электропочте и для наглядного отображения результатов тестирования из формата jUnit. Наш софт состоит из смеси С, С++ и Java, поэтому пришлось выбрать единый формат представления журналов тестирования. Остановились на формате jUnit.

Каждая задача в Hudson может выполняться как на самом мастере, так и на заданном множестве slave-машин. Также  задача может являться условием запуска другой задачи. Например, если задача компиляции проекта прошла успешно, то инициируется задача тестирования. Естественно, на каждом этапе можно архивировать промежуточные результаты (логи, тестовые файлы и т.д.), к которым можно всегда вернуться позже.

Наш сценарий использования Hudson таков: каждые пять минут Hudson опрашивает Perforce. Если в какой-то ветке появились новые изменения, то запускается “чистая” сборка ветки с новыми кусками кода. Каждая такая сборка снабжается файлом, в котором перечислены изменения по сравнению с предыдущей сборкой (changelog). Если сборка прошла успешно, по запускается набор функциональных и приемочных тестов. Кроме этого каждую ночь делается сборка со всеми изменениями за день. Если тесты прошли успешно, что результат архивируется в виде очередного ночного билда и выкладывается на ftp.

Если какая-то задача оканчивается сбоем (например, компиляция, так как кто-то “сломал” сборку, забыв проверить новый код на другой платформе, или какой-то из тестов не работает), то посылаются извещения ответственным лицам и также виновнику сбоя.

При нашей интенсивности commit’ов крайне редко за пять минут появляются более одного. Чем это удобно? А тем, что если при очередной сборке кто-то сломал функциональный или приемочный тест, сразу выясняется кто и как это сделал. 

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

А теперь реальный пример. В какой-то момент бета-тестеры начали сообщать, что система стала “как-то тормозить”. Точного момента никто не засек, а последняя "нормальная быстрая” сборка, которую эти тестеры имели, была сделана месяц назад. За этот месяц в ветку было внесено полсотни commit’ов. Искать среди них проблемный было бы занятием скучным (откат на определенную ревизию, сборка, тестирование, сравнение и т.д.).

Меня выручил Hudson. Я просмотрел отчеты по прогонам функциональных тестов за этот месяц и буквально сразу обнаружил, что в определенный день тесты сетевой подсистемы стали работать заметно медленнее. Область поиска сразу сузилась до четырех commit’ов сделанных в этот день. И только один из них был в сетевой подсистеме. Автор сего “улучшения” тоже нашелся сразу. Оказывается, человек что-то там оптимизировал в целях ускорения, а вышло наоборот.  Итого, около часа на полное разбирательство в проблеме, включая перебрасыванием электропочтой с участниками инцидента. Я думаю, ручной поиск занял был день-два. 

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

А вы какими программами пользуетесь для автоматической интеграции?

 

Посты по теме:

понедельник, 13 апреля 2009 г.

Задержка в одну секунду через time()

Иногда требуется сделать в программе цикл, работающий кратное секундам время. Есть множество способов для это.

Я предложу, как мне кажется, очень простой и очень переносимый способ.

Стандартная функция time() возвращает так называемое UNIX-время в секундах. Проблема в том, что секунда, номер которой возвращает эта функция, может быть уже через пару микросекунд перейдет на следующую. Надо как-то "подравняться" к границе секунд.

Фрагмент кода, в котором рабочий цикл имеет условие, позволяющее ему работать время, близкое к одной секунде:

...
// Получаем номер текущей секунды
time_t started = time(NULL);
// Ждем перехода на следующую секунду
while (time(NULL) == started);
// И сразу запускаем рабочий цикл
started = time(NULL);
do {
// Цикл, работающий в течение секунды
...
} while (time(NULL) == started);
...

Тут, конечно, есть недостатки. Подготовительный цикл ожидания перехода на следующую секунду может "есть" процессорное время, если time() для вашей системы не отдает time slice. Также сложно сделать какой-то надежный универсальный шаблон или макрос, так как надо гарантированно избежать какого-либо лишнего кода, чтобы не терять точность.

В целом, такой прием дает рабочему циклу работать время, очень близкое к секунде.

Если знаете, как сделать еще проще — предлагайте.


Посты по теме:

пятница, 3 апреля 2009 г.

Анализатор покрытия кода тестами Bullseye Coverage

Статические анализаторы кода, например Coverity или Klockwork являются отличным подспорьем для качественного программирования.

Еще одним мощнейшим подспорьем является тестирование. Есть различные виды тестирования — unit-тестирование, функциональное тестирование, регрессивное тестирование и т.д.

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

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

Итак, задача — надо понять, какие части программного коды были задействованы (были выполнены хотя бы раз) в процессе тестирования.

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

Мы в компании остановились на Bullseye Coverage. Относительно небольшая цена (для сравнения с Coverity, которая стоила нам несколько десятков кило-зеленых на год, хотя это того стоит). Можно получить тестовый временный ключ для того, чтобы поиграться перед покупкой. Система поддерживает множество основных платформ.

Bullseye Coverage работает на уровне компилятора. Все что нужно — это активировать ее перед компиляцией проекта. После этого бинарные модули проекта будут сохранять в специальном файле статистику по собственной работе (чем-то похоже на работу профилировщика). Откомпилировали, запустили тесты (любые) и посмотрели — какие строки кода были реально выполнены этими тестами.

Bullseye Coverage может показывать задействование на уровне файлов/модулей, функций/классов и просто строк. Открыв файл исходного текста после прогона тестов специальным просмотрщиком можно, например, сказать, что эта конкретная строка или эта функция никогда не вызывалась в процессе тестирования. Порой это очень впечатляет.

Единственное, чего Bullseye Coverage не умеет, так это делать сравнительный анализ нескольких сборок, чтобы бы можно было отследить изменения показателей, а не просто иметь их абсолютные величины.

Лично меня результаты анализа некоторых наших проектов очень впечатлили и, порой, озадачили.

А вас?


Посты по теме: