Сервер сборки на базе CruiseControl для непрерывной интеграции
Уровень: средний
Марк Уилкинсон (Mark Wilkinson, mhw@codehaus.org), консультант, Codehaus
Перевод: Иван Песин
11 октября 2005
Экстремальное программирование и agile-методики рекомендуют, чтобы процесс разработки включал непрерывную интеграцию и модульное тестирование. Практическим подходом, использующим данные методы, является настройка автоматизированной системы для сборки и тестирования последней версии вашего кода после каждого его изменения. Эта статья рассматривает практические вопросы, возникающие при настройке собственного сервера для сборки Java™-проектов, основанного на Linux™.Эта статья знакомит вас с CruiseControl, программным обеспечением с открытым исходным кодом, которое вы можете использовать для автоматизации процессов сборки и модульного тестирования в проектах, где задействовано несколько разработчиков. Мы рассмотрим, почему автоматические сборки являются необходимыми для успешных команд разработчиков, и опишем процессы установки, настройки и сопровождения системы непрерывной интеграции на базе CruiseControl.
Использование систем управления версиями, таких как CVS или Subversion (см. Ресурсы), на сегодняшний день является общепринятой практикой. Когда над одной системой работает много разработчиков, такая координация становится необходимой. Другой подход, набирающий популярность, это написание модульных тестов и включение их выполнения в процесс сборки. Например, утилита сборки Maven выполняет модульные тесты JUnit в процессе обычной сборки (см. Ресурсы). Но использование этих методов — всего лишь начало. Они формируют основу многих простых и практичных методик разработки программного обеспечения, возникших за последние несколько лет.
|
Когда над одним проектом работает много разработчиков, важно быть уверенным, что последняя версия кода, находящаяся в системе управления версиями (транк), всегда собирается. Это хороший метод для проектов с замкнутыми командами разработчиков; когда разработчики периодически синхронизируют свои рабочие области с транком, несобирающийся исходный код задержит процесс разработки до исправления проблемы. Для проектов с открытым исходным кодом, сохранение транка в рабочем состоянии жизненно важно. Потенциальные программисты могут загрузить код в любой момент и если он будет в нерабочем состоянии, это может оттолкнуть их.
Методология "экстремального программирования" (XP) пропагандирует непрерывную интеграцию. Разработчики интегрируют свой код в транк как можно чаще — обычно раз в несколько часов — проверяя при этом успешное выполнение всех тестов. Другие agile-методики вторят этому совету.
Для адаптации непрерывной интеграции и модульного тестирования необходимо, чтобы ваша команда прониклась этими методиками. Однако часто этого недостаточно. Эти методы состоят из неавтоматизированных шагов — интеграции кода, выполнения тестов и постоянном внесении кода в репозиторий — все это может повлечь ошибки. Автоматизированная система, собирающая код и выполняющая модульные тесты, является гораздо более надежным решением.
Последующая часть статьи рассматривает процесс настройки сервера сборки для ваших Java-проектов с помощью CruiseControl, программного обеспечения для управления процессами автоматической сборки (см. Ресурсы). Вам понадобится надежная машина с большим диском, но не обязательно особо мощная (вам нужны регулярные сборки, не важно, будет на них тратиться 2 минуты, или 20). Настраиваемый сервер будет работать под управлением Fedora Core 4, дистрибутива Linux, разрабатываемого открытым сообществом программистов и спонсируемого Red Hat (см. Ресурсы), так что предполагаются некоторые знания Unix. Ниже перечислены основные задачи, рассматриваемые в статье:
Первым делом нужно убедиться, что все необходимое ПО для разработки на Java установлено в вашей системе. Fedora Core 4 включает инструментарий Java, основанный на gcj, компиляторе Java из проекта GNU Compiler Collection (gcc), но, по соображениям совместимости, разумно будет установить JDK от IBM или Sun. Самым красивым решением является сборка и установка собственного RPM-пакета. Инструкции по сборке приведены на сайте jpackage.org (см. Ресурсы). Пакет xerces-j2 включенный в Fedora Core 4 собран некорректно, в результате реализация XSLT от Xalan отказывается работать. Потому вам будет необходимо установить обновленный пакет xerces-j2 из репозитория разработки Fedora (см. Ресурсы).
Вам, также, понадобится следующее ПО:
Для выполнения следующих шагов, вы должны быть зарегистрированы в системе как root. Вот список RPM-пакетов, которые должны быть установлены в вашей системе:
|
Установите пакеты Java, Xerces, XMLStarlet и Subversion:
|
Вам так же нужно создать на сервере нового пользователя, который будет владеть файлами и процессами CruiseControl:
|
Наконец, поскольку некоторые проекты для сборки
используют Maven, вам нужно его загрузить, установить и задать
соответствующие переменные окружения (см. Ресурсы) (переменная JAVA_HOME
должна содержать /usr/lib/jvm/java). Положим, все дополнительные пакеты,
такие как Maven и CruiseControl, мы будем устанавливать в каталог pkg.
Полная инструкция по установке доступна на веб-сайте Maven, потому
я не буду ее описывать:
|
Следующая наша задача — загрузить CruiseControl (см. Ресурсы) и установить его в каталоге pkg:
|
Вам не нужно собирать CruiseControl, поскольку пакет включает собранный JAR-файл.
Теперь вы можете запустить свою первую автоматизированную сборку. Будем использовать исходный код проекта XStream в качестве начального примера (см. Ресурсы). Позже, вы научитесь добавлять проекты с локальными и удаленными репозиториями исходных кодов. CruiseControl читает информацию о проектах, которые он должен собирать, из файла config.xml в своем стартовом каталоге. В нашем случае, это домашний каталог /home/cruise. Листинг 1 содержит простой конфигурационный файл config.xml с которого мы и начнем. Скопируйте его к себе в систему:
|
Конфигурационный файл CruiseControl содержит три основных блока информации для каждого собираемого проекта:
<schedule>
описывает как собирать проект:
<modificationset>
:
svn
) для
проверки соответствия локальной рабочей копии исходных кодов
последней версии кода в репозитории (нет необходимости пересобирать
проект, если исходный код не изменился).<listeners>
и <log>
:
Теперь вам нужно получить исходный код XStream из репозитория проектов Subversion. Чтобы быть последовательными, загрузите все дерево исходных кодов в подкаталог xstream каталога /home/cruise/src, как указано в файле config.xml:
|
Далее, настройте подкаталог force-build :
|
Последний шаг необходим, потому что CruiseControl откажется запускаться, если файл, указанный в элементе <filesystem>
файла config.xml, не существует.
Возможно, что на данном этапе не все утилиты, нужные для сборки проекта работают правильно, поскольку можно упустить из виду некоторые их зависимости. Таким образом, стоит вручную проверить правильность процесса сборки XStream:
|
|
Когда вы будете добавлять новые проекты, вам будет нужно знать имена целей, которые используются для сборки кода и очистки его от созданных артефактов. Эту информацию нужно будет указать в файле config.xml.
Теперь мы готовы к тому, чтобы CruiseControl автоматически выполнял сборку. Просто запустите CruiseControl и подождите:
|
CruiseControl уже работает, но вы еще не можете запустить его в полностью автоматическом режиме. Он работает в терминальном окне, т.е пользователь cruise должен быть постоянно зарегистрирован в системе. Терминал также является единственным средством управления программой: вы можете завершить CruiseControl, нажав Ctrl+C, и перезапустить его, повторно выполнив команду. Вы не можете это сделать удаленно, не применяя средств, на подобие VNC (Virtual Network Computing). Если CruiseControl (или JVM) аварийно завершится, вам нужно будет перезапускать его вручную. А после перезагрузки машины, CruiseControl не запустится, пока вы не откроете терминал и не введете команду его запуска. Нам нужно что-то, что позволит выполнять CruiseControl как сервис, или демон, в терминологии Unix.
В Linux существует множество способов запуска программ в режиме демона. Вероятно, наиболее распространенный подход состоит в запуске программы во время загрузки системы, с помощью специального скрипта, который выполняется при автоматической инициализации системы. Такие скрипты умеют запускать и останавливать программы, но они не умеют автоматически перезапускать ее в случае сбоя.
Подход, который использовал я, состоит в установке пакета daemontools
Дениела Бернштайна (Daniel J. Bernstein, см. Ресурсы). Это маленький пакет программ, которые берут на себя запуск и контроль над набором сервисов. Для установки daemontools
вы должны быть зарегистрированы в системе как пользователь root:
|
Для успешной компиляции пакета в Fedora Core 4 вам будет нужно
внести маленькое изменение в исходный код. С помощью любого текстового
редактора измените строку 6 файла src/error.h с extern int errno;
на #include <errno.h>
. Вот, как это можно сделать с помощью ed
:
|
Теперь можно завершить установку:
|
daemontools
содержит программу-демон svscan
,
которая занимается управлением сервисами. Каждый сервис представляется
подкаталогом каталога /service, так что вам нужно создать там
каталог для CruiseControl. Для каждого подкаталога
в /service, svscan
запускает процесс supervise
.
supervise
это программа, которая работает непосредственно
с сервисом, таким как CruiseControl. Она запускает сервис, вызывая
программу run
из подкаталога сервиса (например, /service/cruisecontrol/run).
Если этот процесс-потомок вдруг завершит свое выполнение, supervise
его запустит повторно. Кроме того, supervise
может останавливать и перезапускать свои процессы-потомки посылая им сигналы.
daemontools
предоставляет два механизма для протоколирования работы сервисов. Первый — программа readproctitle
, которая перехватывает вывод в стандартный файл ошибок (System.err
в
мире Java) и копирует его в небольшой буфер, который является частью
названия процесса. Увидеть его можно с помощью команды ps
:
|
При запуске буфер инициализируется точками, которые заменяются
на сообщения об ошибках по мере их появления. Этот механизм удобен
для маленьких объемов информации, таких как критические сообщения об
ошибках. Но маленький размер буфера неудобен при больших объемах
журнальной информации, кроме того эта информация не сохраняется на
диске, потому ее сложно анализировать во времени. Для
протоколирования больших объемов информации daemontools
предлагает другой механизм — программу multilog
.
Он записывает строки поступающие на стандартный ввод в журнальный файл,
с учетом указанных в командной строке ключей. С их помощью можно задать
ротацию файлов, максимальный размер журнальных файлов, чтобы не
переполнить диск и пр.
Например, команда multilog /home/cruise/log
протоколирует информацию в файл в каталоге /home/cruise/log,
сменяет файл по достижении 99,999 байт и хранит последних 10
файлов.
multilog
предназначен для работы с supervise
, также как и любой другой сервис. В каталоге каждого сервиса svscan
ищет подкаталог log и создает дополнительный процесс supervise
для выполнения скрипта run
,
который там находится. Также он создает канал для передачи стандартного
вывода основного процесса на стандартный ввод журналирующего процесса.
Так что же нужно сделать, чтобы daemontools
управляли CruiseControl-ом? Вы должны создать структуру каталогов для него и его партнера — multilog
. Далее, для каждого сервиса вы должны создать скрипт run
и каталог для журнальных файлов. Сначала назовем каталог сервиса .cruisecontrol. Лидирующая точка говорит svscan
игнорировать каталог, что позволит нам все настроить до первого запуска сервиса:
|
Теперь создайте каталог env. Содержимое этого каталога
используется для установки переменных окружения CruiseControl-а и
процессов, которые он будет запускать. Здесь вам нужно убедиться, что
переменная JAVA_HOME
содержит правильное значение. И здесь же вы задаете другие переменные, такие как MAVEN_HOME
, необходимые для утилит сборки:
|
В листинге 2 приведено содержимое скрипта /service/cruisecontrol/run:
|
Этот скрипт относительно прост. Он выполняет следующие действия:
multilog
, который уже подключен к стандартному выводу.Листинг 3 демонстрирует скрипт /service/cruisecontrol/log/run, который еще проще. Он запускает multilog
от пользователя cruise :
|
Обратите внимание, что вы должны выполнить команду chmod
для скриптов, чтобы они стали исполняемыми. Также, оба скрипта используют команду exec
, которая замещает одну программу другой, не создавая при этом нового процесса. Это важно, поскольку supervise
может управлять только своими непосредственными процессами-потомками. Если вы не будете использовать exec
,
то JVM запустится как процесс-потомок командного интерпретатора, выполнявшего скрипт. Когда supervise
будет
слать сигнал завершения своему процессу-потомку, его получит и завершит
свою работу командный интерпретатор, а JVM продолжит свое, уже неуправляемое, выполнение. supervise
об этом знать не будет и может запустить вторую копию демона — совсем не то, что вам нужно.
После настройки каталога сервиса, его нужно переименовать, исключив точку из названия. svscan
автоматически запустит
CruiseControl, а его вывод появится в журнальном файле:
|
Теперь у вас есть CruiseControl, который работает в хорошо настроенной среде. Вероятно, вам нужно добавлять свои проекты в его конфигурацию. Как вы можете догадаться, все описания проектов в файле config.xml выглядят однотипно, за исключением некоторых деталей, вроде утилит необходимых для сборки проекта. Вы можете поддерживать файл config.xml вручную, используя копирование в текстовом редакторе. Но есть технология, менее подверженная ошибкам — генерация файла config.xml из более простого XML-документа с помощью таблицы стилей XSLT. Набор файлов, реализующий эту схему доступен для загрузки в виде сжатого tar-файла (см. Ресурсы). Распакуйте этот архив в каталог /home/cruise:
|
Упрощенный конфигурационный файл называется meta-config.xml.
Этот файл преобразуется с помощью таблицы стилей meta-config.xsl в
конфигурационный файл CruiseControl config.xml. Простой
скрипт mkconfig
выполняет преобразование с использованием установленной ранее утилиты XMLStarlet. Запустите mkconfig
для перегенерации конфигурационного файла CruiseControl config.xml.
Простая настройка CruiseControl, с которой вы начали, была достаточна для успешной сборки первого проекта, но она не позволяет контролировать процесс сборки. Наиболее очевидное требование — чтобы результаты сборки отправлялись электронной почтой соответствующим разработчикам. Таблица стилей meta-config.xsl генерирует конфигурацию, которая будет посылать электронные письма, но для этого необходима дополнительная информация о локальной среде. Информация задается с помощью переменных в файле meta-config-params.xsl; вы должны соответствующим образом изменить этот файл перед использованием. В файле задаются следующие параметры:
CruiseControl обладает большой гибкостью в настройке кому слать сообщения при успешной и неудачной сборках. Конфигурация, которая используется здесь, будет слать почту всем разработчикам, которые вносили изменения в репозиторий системы управления версиями с момента последней сборки. Ваша система сборки может работать с проектами с открытым исходным кодом, которые, вероятно, разрабатываться людми из разных стран (будем называть их удаленными проектами). В этом случае вам не нужно слать отчеты непосредственно разработчикам, когда они что-то сломают. Лучше отправлять отчет о сборке по адресу списка рассылки, на который могут подписаться разработчики, желающие быть в курсе состояния проекта. Это позволяет руководителям проектов получать информацию о проблемах максимально быстро.
Листинг 4 содержит общий синтаксис файла meta-config.xml:
|
Конфигурационный файл состоит из тегов <project>
. Каждый проект имеет атрибут name
.
Опциональный атрибут interval
переопределяет
значение интервала между сборками, которое по-умолчанию равно пяти
минутам. Вы должны увеличить интервал для удаленных проектов, чтобы
уменьшить нагрузку на их системы управление версиями.
С помощью обязательных пустых элементов <svn/>
или <cvs/>
для
каждого проекта задается утилита системы контроля версий, которая
должна использоваться для обновления дерева исходных кодов. Кроме того, тегами <ant/>
или <maven/>
должна быть задана утилита сборки проекта.
Проект также должен содержать два элемента, определяющих цели,
используемые для очистки и сборки исходных кодов. Типичные значения для
Maven, это <clean>clean</clean>
и <build>jar:install-snapshot</build>
.
Для Ant, вам нужно будет изучить файл build.xml и найти имена целей.
Исходный код проекта должен находится в
подкаталоге каталога /home/cruise/src, носящем имя проекта. Таким образом,
проект, у которого атрибут name
равен my-project
должен находиться в каталоге /home/cruise/src/my-project.
Некоторые проекты имеют большое дерево исходных кодов, с подкаталогами,
которые могут собираться отдельно; для поддержки таких проеков, секция
<project>
может содержать тег <srcdir>
, который задает конкретный подкаталог каталога /home/cruise/src. Например:
|
По-умолчанию, CruiseControl рассылает сообщения всем, кто внес
изменения в код со времени последней сборки. Если вы загружаете код из
удаленного репозитория, укажите тег <remote-project/>
. В результате, сообщения будут отправляться по адресу указанному параметром developers-address
в файле meta-config.xsl.
CruiseControl ничего не знает о зависимостях между проектами. У вас может существовать проект, который создает JAR-файл, содержащий вспомогательный классы, используемые многими другими проектами, но CruiseControl будет оставаться в неведении до тех пор, пока вы не объясните ему эти зависимости. Вы можете внести изменения во вспомогательные классы, что обусловит их пересборку, но проекты, зависящие от этих классов, пересобраны с новой версией вспомогательных классов не будут. Это могло бы ограничить возможности интеграционного тестирования, потому решения данной проблемы существуют.
Основной способ, предлагаемый CruiseControl, заключается в теге <filesystem>
. Вы можете включать его в раздел <modificationset>
,
что позволит пересобирать проект в случае изменения некоторой части
файловой системы. Наш первый вариант файла config.xml, приведенный в листинге 1,
использует этот подход для принудительной пересборки при изменении
каталога force-build. Все проекты создают или изменяют файлы в
определенных местах файловой системы (например,
проект вспомогательных классов в результате сборки обновит свой
JAR-файл). Вы можете использовать местоположение этого файла в
теге <filesystem>
, чтобы инициировать пересборку проекта, который от него зависит.
Ant предоставляет большую гибкость в способе сборки проекта, потому
невозможно сказать, какая часть файловой системы будет модифицирована в
результате пересборки. Единственным способом точно определить это,
является изучение файла build.xml каждого проекта. Тогда вы сможете
добавить соответствующие теги <filesystem>
в описание зависящего проекта. Упрощенный файл meta-config.xml позволяет задавать тег <modificationset>
,
который может содержать любые допустимые в нем элементы настройки
CruiseControl. Они будут скопированы в результирующий
файл config.xml. Например, проект который зависит от XStream,
может включать такое описание:
|
Maven реализует единый процесс сборки, потому вы можете определить
общие правила зависимостей проектов, собираемых с помощью Maven. Проект
может определять зависимость от объектов в репозитории Maven,
который создаются определенной группой. Точнее, указав <repo-dependency>classworlds</repo-dependency>
,
проект будет пересобран, если любой файл в
каталоге /home/cruise/.maven/repository/classworlds был изменен.
Предположив, что процесс сборки classworlds
устанавливает
полученный JAR-файл в локальный репозиторий Maven, любой проект,
который включает этот элемент, будет автоматически пересобран.
Проект, также, может задавать зависимость от результатов сборки другого проекта. Указав строку <srcdir-dependency>classworlds</srcdir-dependency>
,
вы обуславливаете пересборку проекта при изменении любого файла в
каталоге ${srcdir}/target, где ${srcdir} исходный каталог
названного проекта.
Чтобы добавить новый проект на ваш сервер сборки, нужно выполнить следующие шаги:
./mkconfig
.ps
для определения идентификатора процесса выполняющейся JVM, после чего уничтожить этот процесс с помощью команды kill
. Либо выполнить от пользователя root команду svc -t /service/cruisecontrol
, чтобы daemontools
завершили процесс. В любом случае, supervise
перезапустит CruiseControl.Работающая система CruiseControl отсылает результаты сборок разработчикам по электронной почте. Однако, возможно, есть люди, которые принимают участие в процессе разработки, но сообщения эти не получающие. Например менеджеры или тестеры. CruiseControl включает в себя простое веб-приложение, которое позволяет этим людям следить за сборками.
Веб-приложение CruiseControl работает с сервером
приложений Apache Tomcat, который включен в дистрибутив Fedora
Core 4. Вам будет нужно установить пакеты tomcat5
и tomcat5-admin-webapps
:
|
Кроме того, необходимо установить реализацию Java Transaction API
(JTA). Вы можете собрать свой RPM-пакет JTA с помощью spec-файла, который можно получить на сайте
JPackage (см. Ресурсы),
но проще установить пакеты geronimo-specs
и geronimo-specs-compat
из репозитория разработки Fedora:
|
Веб-приложение CruiseControl не может найти подходящую реализацию JAXP TransformerFactory
в
стандартной установке Tomcat, потому вам нужно добавить преобразователь JAXP XML по-умолчанию в каталог
классов endorsed:
|
Веб-приложение CruiseControl может рисовать графики важной
статистики о сборках, например отношение успешных и неудавшихся
сборок. Библиотеки, которые рисуют графики используют Java AWT,
поэтому вам будет нужно запускать JVM в режиме headless. Для этого, откройте файл /etc/tomcat5/tomcat5.conf в редакторе и вставьте возле десятой строки: JAVA_OPTS="-Djava.awt.headless=true".
Теперь добавьте веб-приложение CruiseControl в конфигурацию Tomcat, создав файл cruisecontrol.xml в каталоге /etc/tomcat5/Catalina/localhost. Содержимое файла приведено в листинге 5:
|
Обратите внимание, что вторая строка в листинге была разбита на две для удобства чтения. Атрибут docBase
должен быть записан в одной строке.
Также, вам нужно создать каталог для хранения скэшированных веб-приложением CruiseControl страниц:
|
Теперь вы можете запустить Tomcat и задать его автоматический запуск при загрузке системы. Скрипты запуска выдают предупреждения, которые можно проигнорировать:
|
Теперь вы можете воспользоваться браузером и доступиться к веб-приложению CruiseControl по адресу http://localhost:8080/cruisecontrol/. На рисунке 1 показан пример того, что вы должны увидеть:
Перед завершением, я хотел бы сделать несколько замечаний относительно вопросов безопасности, возникающих при настройке и эксплуатации своего сервера сборки. Первое: мы не рассматривали вопрос безопасного доступа к данному серверу. Вы должны обратиться к другим источникам по вопросам обеспечения безопасности, либо эксплуатировать сервер в сети, предоставляющей должный уровень защиты.
Второе: необходимо определить, насколько вы готовы доверять разработчикам других проектов, которые собираются на вашем сервере. Процесс сборки проекта и модульные тесты имеют доступ к ресурсам сервера, в том числе и сети, к которой он подключен. Автоматизированный процесс сборки означает, что изменения, зафиксированные в репозитории системы контроля версий, будут загружены и выполнены без вмешательства оператора. Это подвергает сервер риску от ошибок и злоумышленного кода, помещенного в репозиторий исходного кода. Вы можете ограничить количество внешних проектов, собираемых на вашем сервере, либо уделить внимание защите ваших системе и сети от собираемых проектов.
Эта статья содержит описание установки сервера сборки для непрерывной интеграции на базе CruiseControl. Вы установили CruiseControl и изучили, что нужно для поддержания его постоянной работы. Вы получили представление о ежедневных задачах по управлению сервером сборки. И вы вычленили наиболее важные части конфигурации, включая тип системы управления версиями, утилиты сборки и цель для сборки проекта, в более простой XML-документ.
Вы также знаете, как задавать зависимости между собираемыми
проектами. Это немного проще для проектов, которые собираются с
помощью Maven, благодаря однотипности процесса сборки и
разделяемого репозитория получаемых объектов. Ant позволяет
индивидуально настраивать процесс сборке для каждого проекта, но если у
вас есть несколько проектов, собираемых с помощью Ant
и имеющих общий процесс сборки, вы можете использовать теги <filesystem>
,
расширяющие конфигурацию для создания межпроектных зависимостей.
CruiseControl имеет множество других настроек, которые могут
использоваться для улучшения процесса непрерывной интеграции. Их можно
легко задействовать, добавив в рассмотренную выше таблицу
стилей XSLT.
Мы поверхностно рассмотрели шаги, необходимые для запуска
веб-приложения CruiseControl, но открытыми остались вопросы
безопасности и надежности. Более безопасная система должна использовать
веб-сервер Apache для обработки и передачи запросов Tomcat. Для увеличения надежности стоит передать контроль над Tomcat JVM системе
daemontools
таким же образом, как и в случае с самим CruiseControl. Кроме
того, вы должны рассмотреть вопросы безопасности, связанные с запуском
тестов на сервере сборки, их доступом к сети и утилитам Linux.
Цель этой статьи — сделать ваш процесс разработки более быстрым и активным, улучшить качество разрабатываемого программного обеспечения, применяя для этого подход непрерывной интеграции. Создание сервера сборок это конкретный и практический шаг в использовании agile-методик, а адаптируя другие, вы сможете добиться дальнейшего улучшения процесса разработки ПО. Рекомендую прочесть информацию об этих идеях (начните со ссылко, приведенных в разделе Ресурсы) и применять их на практике.
Описание | Имя | Размер | Метод загрузки |
---|---|---|---|
Утилиты из примера | j-simple-cc.tar.gz | 2 KB | FTP |
Информация о методах загрузки | Загрузить Adobe® Reader® |
Марк Уилкинсон является независимым консультантом, специализирующемся на архитектуре ПО, дизайне и процессах разработки. Он руководил небольшими командами программистов, разрабатывавших инновационные решения для различных клиентов. Марк разработал практический подход к управлению процессом разработки, который интенсивно использует автоматизацию и такие системы как CruiseControl. Он также работает над несколькими проектами в Codehaus. Марк имеет степень доктора компьютерных наук Йоркского университета. |