Лучше изучить лишнее, чем ничего не изучить

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

Posted: июля 1, 2008 | Author: | Filed under: easyQuizzy, Разработка софта | Tags: , , , , , , , | Комментариев нет

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

Как известно, номера версий программ — это побочный продукт итерационной разработки ПО, которую еще называют «Модель водопада» или «Flow».

Суть метода состоит в следующем. Как только работающая программа выпускается в свет, и у разработчиков, и у пользователей сразу возникают идеи по ее улучшению. А когда перед выпуском программу тестируют, применяя неправильную методологию, то пользователи найдут в ней со временем кучу ошибок. И если разработчики захотят учесть эти пожелания и исправить/дополнить программу, они должны будут как-то отразить процесс ее изменения перед пользователями. Самое простое, что приходит на ум, — это добавить после названия программы (торговой марки) цифру или набор цифр, показывающих номер итерации в ее цикле «разработка-тестирование-выпуск».

Самое большое распространение в мире ПО получила двухсегментная нумерация вида «x.x». Где каждый икс — это, в основном, арабская цифра. Реже — буква. А точка стоит в смысле десятичной дроби. Какие-то находчивые ребята очень давно придумали «Правило большого пальца», как формально отобразить степень изменения программы в эти два числа: если происходят радикальные изменения, затрагивающие пользовательский интерфейс, функциональность, форматы данных, то следует увеличивать первый (старший, англ. «major») сегмент версии. Если изменения незначительны, исправлены ошибки без изменения функциональности или добавлены незаметные удобства в пользовательский интерфейс, то увеличивать следует второй (младший, англ. «minor») сегмент. При увеличении старшего сегмента младший сбрасывается в ноль.

Увеличение не обязательно строго последовательное, иногда разработчики хотят подчеркнуть, что программа изменилась до неузнаваемости, и перескакивают несколько позиций в нумерации версии. Например, в версии 1.1 был интерфейс командной строки, а в следующей версии перешли сразу на пользовательский интерфейс от WPF и пронумеровали ее 10.0, чтобы пользователь почувствовал разницу.

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

Пока вроде бы все просто и понятно. Непонятное начинается, если посмотреть на номер версии исполняемого файла в проводнике Windows. Вы тоже можете провести этот эксперимент: откройте Проводник, найдите файл C:\Windows\regedit.exe, кликните на нем правой кнопкой мышки и выберите пункт «Свойства». В открывшемся окне перейдите на вкладку «Версия». Вы увидите что-то вроде 5.1.2600.2180. А если запустить Regedit, то в окне «О программе» можно увидеть версию программы 5.1. Логично предположить, что номер версии исполняемого файла состоит из обычной двухсегментной части (5.1) и двух дополнительных чисел (2600.2180).

MSDN сообщает, что номер версии исполняемого файла (exe и dll) хранится в строке ресурса с названием VERSIONINFO, и состоит из четырех чисел, разделенных точкой: Major.Minor.Build.Revision. Сегменты Major и Minor — это обычная двухсегментная адресация, соответствущая номеру версии, который видят пользователи в окне «О программе», Build — это номер сборки, а Revision — это номер ревизии. Всем все понятно? Да? Ну, а мне было непонятно, что это значит.

Чтобы разобраться, давайте сначала расскажу кое-что из личной биографии.

Одним из моих первых проектов, который я начал разрабатывать, еще когда учился на четвертом курсе в университете, была программа для управления составом изделий в одной большой организации. Эта организация создавала микропроцессорные системы автоматического управления для ядерных реакторов, нефтегазовой отрасли и, как ни странно, пищевой промышленности (это чистая правда, системы были очень универсальными!). У них уже были программы управления составом изделий, но они создавались еще в те времена, когда о компьютерных сетях никто не слышал. А потому для обмена информацией между отделами приходилось копировать dbf-файлы на общий сетевой диск файл-сервера, буква которого была жестко забита в исходном коде программ-клиентов под DOS. О совместном доступе и современном интерфейсе пользователя, конечно, речи не шло. Заведующий нашей кафедры компьютерной инженерии узнал об этой проблеме и предложил силами университета (и почти бесплатно) разработать полноценный клиент-серверный аналог с современным оконным интерфейсом. Организация без особого энтузиазма согласилась, выделила университету консультантов и набросала техническое задание. А для разработки новой программы было выделено трое самых способных студентов кафедры. Угадайте, кто был одним из них.

Задание было вкратце таким. Состав изделия набирается конструктором из трех справочников: радиоэлементов (транзисторы, конденсаторы, микросхемы), материалов (сталь, кабель коаксиальный, пластик) и стандартных изделий (болты, гайки, шайбы). Затем по набранному составу нужно было автоматически сгенерировать несколько видов конструкторских документов по стандарту ЕСКД.

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

Нам это показалось неправильным, и мы, посовещавшись, пришли к первой модели организации технологического процесса — главный/подчиненный программист (Master/Slave — это не всегда переводится как «хозяин и раб»). Один программист занимался кодированием и сборкой пользовательского интерфейса системы, а два других, и я в том числе, были у него «на побегушках», разрабатывая независимый вспомогательный функционал. Задания он нам давал в виде заголовков функций с параметрами и кратким описанием их назначения. А нашей целью было создавать логически независимые законченные модули, содержащие эти функции. Созданные модули не подлежали дальнейшему совершенствованию, так как перед включением в проект они проходили независимое тестирование и были уже полностью отлажены.

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

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

Цитата из Википедии

Большинство систем управления версиями используют централизованную модель, когда имеется единое хранилище документов, управляемое специальным сервером, который и выполняет большую часть функций по управлению версиями. Пользователь, работающий с документами, должен сначала получить нужную ему версию документа из хранилища; обычно создаётся локальная копия документа, т. н. «рабочая копия». Может быть получена последняя версия или любая из предыдущих, которая может быть выбрана по номеру версии или дате создания, иногда и по другим признакам. После того, как в документ внесены нужные изменения, новая версия помещается в хранилище. В отличие от простого сохранения файла, предыдущая версия не стирается, а тоже остаётся в хранилище и может быть оттуда получена в любое время. Сервер может использовать т.н. дельта-компрессию — такой способ хранения документов, при котором сохраняются только изменения между последовательными версиями, что позволяет уменьшить объём хранимых данных.

Мы перепробовали несколько систем управления версиями, включая Subversion, Visual Source Safe, CVS и др., но остановились на Microsoft Team Foundation Server, который очень хорошо интегрировался с нашим основным инструментом разработки MS Visual Studio.

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

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

  1. Cкачать на свой компьютер последнюю версию всех файлов проекта с сервера
  2. Пометить на сервере те файлы, которые он собирается менять, специальным флагом (check-out), чтобы другие программисты не пытались пока их изменять
  3. Внести изменения в выбранные файлы
  4. Скомпилировать и протестировать свою локальную копию итоговой программы
  5. Если все компилируется и работает, как надо, то отправить все измененные файлы на сервер (check-in) и снять флаг редактирования с файлов, которые он изменил

При каждой отправке файлов на сервер (check-in) создавалась ревизия исходного кода.

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

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

Номер ревизии был уникальным для каждой операции check-in и последовательно увеличивался.

Компиляция всех модулей программы называется сборкой (build). Сборка из самых новых исходных кодов, которые находятся на сервере управления версиями, могла производиться вручную или автоматически в заданное время дня. Каждой сборке также соответствовал уникальный номер. Автоматически этот номер генерировался по текущей дате/времени, но мы для простоты увеличивали его каждый раз последовательно (0001, 0002, 0003 и т.д.).

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

Что это нам давало?

Мы делали в среднем по одной рабочей сборке в день. Каждая сборка проверялась тестировщиками и отчеты об ошибках записывались в нашу внутреннюю базу данных ошибок через систему Mantis. Если тестировщик замечал ошибку, он описывал ее и связывал с конкретным номером сборки. Так появилась возможность выполнять параллельное тестирование продукта, не задерживая разработчиков ожиданием отчетов об ошибках, так как каждая ошибка однозначно связывалась со сборкой и ревизией кода. А все ревизии были легко доступны в любое время на сервере управлениями версиями.

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

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

Что касается текущего проекта easyQuizzy, то над ним пока работает только один программист (я), а потому контроль версий сводится к тому, что при создании каждой новой сборки происходит автоматическое копирование всех исходных кодов программы в отдельную папку (язык bat-файлов иногда просто творит чудеса!). Эта папка затем архивируется замечательной программой 7-zip. Номер ревизии кода при этом соответствует номеру сборки исполняемого файла, а потому версия исполняемого файла программы у меня строится так: «х.х.0.номер_сборки».

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

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

Чтобы не было сомнений в том, что вся эта статья — наглая самореклама, скажу, что скоро выходит версия easyQuizzy 1.4, и если вы купите лицензию сейчас, то новую версию, впрочем как и все последующие, получите совершенно бесплатно!



Leave a Reply