Построение "правильного" процесса разработки на платформе .NETИсточник: developers Kartsev Evgeny
ВведениеДостаточно часто программисты игнорируют (а возможно и не знают) некоторые приемы, позволяющие значительно облегчить весь процесс разработки. Предлагаю вам взглянуть на "альтернативный", но не единственный правильный процесс разработки в команде, позволяющий значительно сократить усилия, чтобы еще осталось время попить пивка с коллегами. Рассматриваемый в статье пример может показаться весьма наивным, и простым. Пусть это не вводит вас в заблуждение, я пытался сделать все достаточно просто, чтобы охватить как можно большую аудиторию. Прежде чем начать предлагаю вам ответить на ряд вопросов, которые будут раскрыты в конце статьи:
Итак, приступим… Windows Server 2008При написании статьи использовалась именно эта операционная система и этому есть ряд причин:
Т.к. мы собираемся писать скрипты для IIS 7, хотелось бы сделать ряд замечаний по поводу других операционных систем. Windows Vista - никаких трудностей, скорее всего, не будет, весь код из данной статьи без проблем будет работать. Windows Server 2003 - могут возникнут затруднения при переносимости скриптов, т.к. в Server 2003 установлен IIS 6. Но все примеры можно применить, приложив некоторые усилия и бубен. Windows XP SP2/3 - возникнут проблемы с переносимостью скриптов для настройки IIS т.к. в XP возможно установить только IIS 5.1 (Фанаты Windows Script Host могут справяться и с этим заданием). Более ранние версии Windows - к этой аудитории у меня есть резонный вопрос - вы в каком веке живете? Итак, в Windows Server 2008 должен быть установлен IIS 7. Чтобы съэкономить место, предлагаю вам зайти на этот ресурс, там подробно описано как это сделать (это первая ссылка из гугла на запрос "как установить IIS 7"). Visual Studio 2008Пример в статье будет разработан именно в этой среде, т.к. Visual Studio - это основное средство любого .NET разработчика. На протяжении всей статьи будет рассматриваться процесс разработки веб приложения со слоем бизнес логики, unit тестами и windows сервисом. В качестве фрэймворка для тестов будет использоваться Nunit, поэтому прежде чем приступить к разработке какркаса приложения идем по этой ссылке и качаем Nunit (у меня установлена версия 2.4.7, но вполне возможно установить и более свежую версию). Запускаем Visual Studio 2008 File->New->Project Выбираем Other Projetc Types -> Blank Solution Name: TestApp, Location = "C:\", папка "C:\TestApp" будет создана автоматически. Рис 1. Создание пустого проекта. Добавляем новый веб сайт Рис 2. Новый Веб сайт, шаг 1 Меняем Language на "C#" и Location на "C:\TestApp\WebApp" Рис 3. Новый веб сайт, шаг 2 Создаем проект "BusinessObjects", содержащий набор бизнес объектов Рис 4. Новый проект - BusinessObjects, шаг 1. Тип проекта - "Class Library", имя - "BusinessObjects". Рис 5. Новый проект - BusinessObjects, шаг 2. После создания проекта удаляем автоматически созданный класс с именем "Class1" за ненадобностью. Создаем проект для тестов. Рис 6. Новый проект - Tests. Удаляем "Class1"… Далее, создаем проект для Windows сервиса, который ничего не будет делать, но необходим для полноты примера деплоймента проекта. Рис 7. Новый проект TestService. После всех манипуляций должен получиться каркас проекта аналогичный представленному на Рис 8: Рис 8. Каркас проекта. На данном этапе было бы правильным создать репозиторий и залить туда проект, но мы это отложим, т.к. проект по образу и подобию "Hello World" и не хотелось бы разрывать логически связанные части статьи. Итак, следуя принципам TDD, начнем создание логики с написания тестов. Задача предельно проста - необходимо создать класс, содержащий один единственный метод, принимающий string, и возвращающий "Hello " + переданный параметр, если передать null должен быть выкинут ArgumentNullException. В тестовой сборке добавляем референс на Nunit.framework Рис 9. Добавление ссылки на сборку nunit.framework, шаг 1. Рис 10. Добавление ссылки на сборку nunit.framework, шаг 2. Создаем класс с именем "TestClass", код с пояснениями представлен ниже:
Если сейчас попробовать собрать проект, ничего не выйдет, т.к. не существует класса с именем Entity. Создадим его. Добавляем класс к сборке BusinessObjects, называем его Entity: Рис 11. Новый класс в сборке BusinessObjects. Добавляем референс в проекте Tests на проект BusinessObjects для того, чтобы тесты имели возможность использовать только что созданный класс: Рис 12. Добавление ссылки на сборку BusinessObjects, шаг 1 Рис 13. Добавление ссылки на сборку BusinessObjects, шаг 2 Добавляем
После этих шагов пробуем собрать проект, и опять ничего не получится, т.к. мы не добавили метод с именем GetHello. Добавим его. Весь код класса Entity приведен ниже.
После всех проделанных шагов проект успешно собирается. Пришло время проверить, правильно ли проходят тесты (хотя это нужно было делать немного раньше - до добавления логики к методу GetHello, и только после этого имплементировать логику в методе, но об этом я предлагаю почитать в литературе посвященной TDD и DDD). Я предпочитаю использовать Resharper для запуска тестов, т.к. этот плагин очень юзабильный и позволяет запускать тесты из студии (а также содержит большое количество фичей для рефакторинка и поиска), единственная проблема - платность продукта (триал версию можно скачать тут). Также существует бесплатный плагин для студии - Test Driven.NET который нужнен только для тестов (можно скачать тут). В конкретном случая, я предлагаю воспользоваться отдельным приложением Nunit GUI, т.к. данное приложение устанавливается вместе с nunit.framework. Идем в Пуск -> All Programs -> NUnit 2.4.7 запускаем NUnit GUI Жмем File -> Open Project -> "C:\TestApp\Tests\bin\Debug\Tests.dll" Получаем приблизительно следующее: Рис 14. Nunit GUI, запуск тестов Жмем "Run", должны получить такую же картинку как на рис 15. Если видите красный цвет, тогда где-то ошибка и нужно вернуться на пару шагов назад и проверить правильность кода. Рис 15. Nunit GUI, "послезапуск" тестов Итак, логика написана, тесты пройдены, пришло время написать пару строк кода на веб странице. Добавляем ссылку в веб сайте на сборку BusinessObjects. Рис 16. Добавление ссылки на сборку BusinessObjects, шаг 1 Рис 17. Добавление ссылки на сборку BusinessObjects, шаг 2 Открываем файл "Default.aspx.cs" в веб сайте. Добавляем Весь код приведен ниже:
Код достаточно прозрачный, думаю объяснения излишние. Открываем файл web.config, и изменяем
После чего можно нажать F5 и посмотреть, что получится в браузере SVNКаркас проекта создан, пора его залить в репозиторий. Существует несколько наиболее популярных видов репозитория, к которым относятся CVS, SVN, VSS и др. В конкретном случае будет использоваться SVN, т.к. его невероятно просто настроить, а также он тесно интергирован с Cruise Control.NET, но обо всем по порядку. Итак, идем по этой ссылке качаем "Visual SVN Server" (на момент написания статьи актуальной была версия 1.7.2). После чего запускаем только что скачанный инсталлер: После принятия лицензионного соглашения, есть возможность настроить пути установки сервера и репозитория (Рис 18). Для простоты оставим все как есть. Рис 18. Установка Visual SVN Server. После установки SVN сервера нужно сделать 2 очень важных шага. 1. Добавить путь к папке с бинарными файлами SVN Server (в моем случае это "C:\Program Files\VisualSVN Server\bin") в PATH (Рис 19). Рис 19. Добавление пути к Visual SVN Server bin к PATH 2. Добавить новый элемент в User Variables с именем "SVN_EDITOR" и значением "notepad" (можете выбрать любой редактор): Рис 20. Добавление нового элемента в User Variables После этого идем в Start -> All Programs -> Visual SVN -> VisualSVN Server Manager и создаем нового юзера с именем "Eugene" и паролем "1" (Рис 21, 22): Рис 21. Создание нового пользователя, шаг 1 Рис 22. Создание нового пользователя, шаг 2 Далее создаем новый репозиторий (Рис 23): Рис 23. Создание нового репозитория, шаг 1 Имя репозитория будет "TestApp". Также предлагается создать стандартную структуру папок (trunk, branches, tags), данная структура подразумевает разработу с версионированием, т.е. вся разработка ведется из папки trunk, когда выходит новая версия продукта, она перекладывается в папку branches, а в папке trunk продолжается разработка над следующей версией продукта. Таким образом папка trunk будет содержать актуальную и еще не выпущенную версию продукта, а папка branches будет содержать папки v1, v1.1, v2, и т.е. версии, которые уже в релизе. Для нашего примера никакой структуры в репозитории не нужно, т.к. мы собираемся выпустить только одну версию продукта. Рис 24. Создание репозитория, шаг 2 Итак репозиторий создан, пора залить в него проект. Для того, чтобы проводить манипуляции с svn существует несколько достаточно удобных клиент-интерфейсов, к которым относятся TortoiseSVN, VisualSVN и т.д. Но мы будем пользоваться командной строкой, чтобы наиболее четко ощутить все прелести примера. Хотелось бы еще пару слов сказать о менеджерах командной строки (или файловых менеджерах). Существует много вариантов - NC, VC, Total Commander, и т.д, но как сказал один очень сильный программист (Ден привет:) ): "Все нормальные поцаны используют Far". Поэтому в этом примере будем использовать именно этот менеджер. Заходим в VisualSVN Server Manager и копируем url к репозиторию (Рис 25): Рис 25. Копирование url к репозиторию в clipboard После чего открываем Far, переходим в корень диска C:, создаем папку "Projects", переходим в "C:\Projects" и выполняем команду "svn co" + вставляем только что скопированный url. Получится приблизительно то же что и на Рис 26: Рис 26. Checkout из репозитория Жмем "Enter", будет предложено отклонить (r), принять временно (t) или принять (p) сертификат сервера. Принимаем сертификат (p). Важно выбрать именно (p), почему - будет описано в разделе посвященному CruiseControl.NET. Также возможно потребуется ввести User Name и Password для юзера репозитория - вводим их для юзера, который был создан в VisualSVN Server Manager. После проделанных шагов в консоль будет выведено сообщение "Checked out revision 0." и будет создана папка "TestApp". Если зайти в только что созданную папку "C:\Projects\TestApp" можно обнаружить скрытую папку с именем ".svn" - эту папку нельзя ни в коем случае удалять, т.к. именно в ней хранятся все локальные изменения, и системные файлы SVN. Рис 27. Папка TestApp после svn checkout. Наконец то мы дошли до залития всего проекта в репозиторий. Переходим в C:\TestApp, удаляем все ненужные файлы и папки, такие как _ReSharper.TestApp, TestApp.4.5.resharper.user, bin, obj. Перемещаем все содержимое из C:\TestApp в C:\Projects\TestApp. Переходим в C:\Projects\TestApp и выполняем команду "svn add TestService Tests BusinessObjects TestApp.sln WebApp". Результат должен быть приблизительно таким же как показано на рис. 28: Рис 28. Добавление проекта в репозиторий. Далее, нужно залить все в репозиторий. Выполняем команду "svn ci". Будет открыт блокнот с перечнем файлов для коммита (именно для этого нужно было добавлять новую переменную SVN_EDITOR) в переменные среды. Сохраняем и закрываем файл (если не сохранить и попробовать закрыть, вам будет предложено решить - нужно ли делать коммит или нет). С этого момента вы можете использовать репозиторий с проектом. В данной статье не будет рассматриваться как осуществляется работа с репозиторием svn. Чтобы получить более подробную информацию, советую обратиться к специализированным источникам. NantСледующим шагом в построении процесса разработки должна стать разработка автоматизированного процесса деплоймента и запуска тестов. Для этих целей, как правило, используются 2 подхода. Первый подход - создание *.bat файлов с кодом для развертывания проекта. У данного подхода существует ряд ограничений, основным из которых является, неудобство использования. Второй подход - использование специализированных средств, к которым относятся Nant (для .NET) или Ant, Continuum (для Java) и др. В данной статье будет использоваться open source консольное приложение Nant. Загрузить это тул можно здесь - http://nant.sourceforge.net/. Советую загружать не ниже версии 0.86-beta1, т.к. только она на момент написания статьи поддерживает тип проекта Visual Studio 2008. После загрузки, распаковываем архив, и помещаем его, скажем, в папку "C:\Program Files\nant-0.86". Добавляем путь к "bin" в PATH (Рис 29): Рис 29. Добавление пути к бинарным файлам Nant в PATH Открываем Far, пишем в консоли "nant" и жмем "Enter". Если видим вывод, показанный на рис. 30, значит все впорядке - путь к nant работает правильно (если фар был открыт до добавления значения в PATH, его нужно закрыть и открыть заново). Рис 30. Проверка пути к nant Далее предлагается краткий обзор основ конфигурирования используя nant. Для того чтобы конфигурировать билд, необходимо иметь 1-н или более файлов *.build, которые представляют собой обыкновенные xml файлы. Точкой входа является файл default.build. Чтобы не отходить далеко в теорию, предлагаю рассмотреть короткий пример, после которого мы вернемся к основному примеру - приложению TestApp. Итак, создаем файл с именем default.build (В какой папке создать файл абсолютно без разницы). Добавляем в него следующее содержимое:
После чего в консоли пишем "
Мы только что создали target - основной элемент, на основании которого построена вся работа в nant, после чего передали имя target-а в качестве параметра приложению. Немного усложним пример. Изменим файл default.build как показано ниже.
После чего опять запустим "
В *.build файлах могут содержаться как таргеты (targets), так и проперти (property). Как показано в примере для того, чтобы использовать property, необходимо поместить его имя в фигурные скобки после знака $. Еще усложним пример.
Вывод будет зависеть от папки, в которой находится файл default.build, но он должен быть приблизительно следующим:
Как вы видите, существует возможность использования как констант, так и встроенных функций. Весь перечень функций можно найти здесь: http://nant.sourceforge.net/release/latest/help/functions/index.html Итак, пора бы написать что-нибудь полезное, поэтому закончим с основами, и перейдем непосредственно к автоматизации проекта TestApp. Для тех кто хочет подробно изучить возможности nant настоятельно рекомендую прочитать книгу "Expert .NET Delivery Using NAnt and CruiseControl.NET". Прежде чем приступать непосредственно к процессу написания скриптов для автоматизации процесса деплоймента, необходимо продумать стратегию (последовательность шагов) сборки. Предлагаемая стратегия сборки:
4-й пункт выглядит странно, но это связано с политикой безопасности в Windows Server 2008 и Windows Vista. Итак, поехали… Создаем файл default.build в папке "C:\Projects\TestApp". Копируем файл C:\Projects\TestApp\WebApp\web.config в C:\Projects\TestApp\WebApp\web.config.standard. В *.standard файле подменяем значение раздела appSettings:
После чего модифицируем файл default.build как показано ниже (самые нетерпеливые читатели могут сразу перейти в конец раздела, где представлен полный код файла default.build):
В таргете "build.recreateConfig" выводится на экран дата и время запуска таргета, после чего копируется файл "web.config.standard" в файл "web.config" с заменой значения [[[config.environment]]] на значение "QA". Идем дальше, следующим шагом необходимо создать таргет для сборки проекта. Сделаем это… Добавляем проперти:
Создаем таргет для билда:
После этого следует сохранить файл default.build, перейти в консоль, и выполнить команду "nant build". Если вы увидите вывод как показано далее, значит все в порядке, проект успешно собрался.
Если в выводе появится "BUILD FAILED" значит нужно вернуться на несколько шагов назад и перепроверить правильность кода. Следующий пункт - запуск тестов. Создаем папку "C:\Projects\TestApp\Tests\Results" для файла c результатами тестирования. Добавляем проперти в файлу default.build:
Добавляем таргет для запуска тестов:
Выполняем команду "
Мы закончили первые 3 пункта, переходим к самому интересному - созданию скрипта для развертывания веб сайта и установки сервиса. Чтобы немного усложнить задачу допустим для сайта должно быть настроено несколько биндингов (Bindings): 1. http://testapp.ua:80 2. http://admin.testapp.ua:80 Создаем папку "C:\Projects\TestApp\Scripts", в которой создаем файл "deployWebApp.bat.standard". Этот файл будет копироваться в файл "C:\Projects\TestApp\Scripts\deployWebApp.bat", причем будут подменяться некоторые параметры. Код файла "C:\Projects\TestApp\Scripts\deployWebApp.bat.standard":
В этой статье написано достаточно подробно как в IIS 7 создавать сайты, приложения, пулы и т.д. используя AppCmd, поэтому здесь я не буду тратить место для объяснения что делает каждая команда в этом файле. Далее добавляем новые проперти в файл default.build:
А также новый таргет для создания *.bat файла:
После чего можно попробовать выполнить команду "nant deploy.createIisBat", и запустить файл "Scripts\deployWebApp.bat". Если у вас выключен UAC, тогда вам необходимо запустить файл от имени администратора (Рис 31). Рис 31. Запуск *.bat файла от имени администратора. После запуска файла запускаем "inetmgr", и видим приблизительно следующее: Рис 32. IIS Manager после запуска скрипта. На данном этапе необходимо сделать один "кастомный" шаг - внести изменения в файл hosts, для того, чтобы можно было запускать сайт. Открываем notepad от имени администратора, далее File->Open-> "C:\Windows\System32\drivers\etc\hosts" и добавляем строку "127.0.0.1 testapp.ua", как показано на рис. 33: Рис 33. Правка файла hosts. Пришло время протестировать веб приложение. Открываем браузер и вводим в строку url: "http://testapp.ua/" Рис 34. Тест веб сайта. Как видим, все работает. Следующим шагом будет написание скрипта для установки Windows Service Создаем файл "C:\Projects\TestApp\Scripts\deployService.bat.standard" с следующим содержимым:
Добавляем проперти в файл default.build:
А также добавляем таргет:
Выполняем команду " Запускаем "Scripts\deployService.bat" от имени администратора. Далее открываем "services.msc" и ищем добавленный сервис: Рис 35. Установленный сервис Последним шагом является "странное" требование - архивирование бинарников TestService и копирование архива в папку "C:\builds\" Добавляем проперти в файл default.build:
Добавляем новый таргет:
Выполняем команду " Рис 36. Созданный *.zip файл Остался последний шаг - создать таргет, который будет собирать в себе все перечисленные ранее. Код таргета представлен ниже:
Тут нужно сделать одно замечание: если на машине выключен UAC, тогда проект не будет собираться, необходимо будет закоментировать вызовы "*.bat" файлов, и запускать их вручную. Если UAC выключен - тогда все что нужно сделать это выполнить команду " Весь код файла default.build представлен ниже:
Cruise Control.NETЗаключительным шагом будет установка и настройка "Continuous Integration" сервера для автоматического запуска сборки проекта и запуска тестов. Идем на сайт ccnet.thoughtworks.com и качаем последнюю версию Cruise Control.NET (на момент написания статьи актуальной была версия 1.4.4). Запускаем установщик… Рис 37. Установка CruiseControl.NET, шаг 1 Рис 38. Установка CruiseControl.NET, шаг 2 Рис 39. Установка CruiseControl.NET, шаг 3 Рис 40. Установка CruiseControl.NET, шаг 4 Рис 41. Установка CruiseControl.NET, шаг 5 Рис 42. Установка CruiseControl.NET, шаг 6 Необходимо сделать одно замечание. На шаге 4, была отмечена опция "Create virtual directory in IIS for Web Dashboard", но, несмотря на это, виртуальная папка в IIS 7 не будет создана (можете называть это багом). Будем надеяться, что в следующих версиях такой проблемы не будет. Необходимо сделать несколько дополнительных шагов для того, чтобы можно было запускать "Dashboard" в браузере, если этого не нужно (например, если вы будете использовать CCTray), можете смело пропустить эту часть раздела. Открываем "inetmgr" и добавляем приложение к "Default web site" Рис 43. Добавление приложения для "Web Dashboard", шаг 1 Далее заполняем форму как показано ниже. Очень важно поменять значение "Application pool", т.к. по умолчанию оно устанавливается в "DefaultAppPool", если не поменять этот параметр на "Classic", приложение запускаться не будет. Рис 44. Добавление приложения для "Web Dashboard", шаг 2 Web Dashboard установлен, теперь нужно проверить это. Открываем браузер, в строке url пишем "http://localhost/ccnet/". Если вы видите такую же картинку как на рис. 45, значит все установлено правильно, если нет - вернитесь на пару шагов назад и проверте правильность своих действий. Рис 45. CruiseControl.NET Web Dashboard Пришло время приступить к настройке ccnet на работу с тестовым приложением TestApp. Модифицируем файл "C:\Program Files\CruiseControl.NET\server\ccnet.config" как показано ниже:
Несколько важных замечаний:
Далее открываем "services.msc", находим сервис с именем "CruiseControl.NET Server", заходим в настройки сервиса. Рис 46. Настройка сервиса CruiseControl.NET Server, шаг 1 По умолчанию сервис будет запускаться как "Local System account", необходимо поменять это поведение, сервис должен запускаться с правами пользователя, у которого есть сертификат для работы с SVN. Грубо говоря, необходимо, чтобы сервис логинился как юзер, который выполнял команду "svn co", т.к. именно после этой команды пользователь должен принять или отклонить сертификат, как говорилось в разделе посвященном SVN. Меняем настройки аутентификации сервиса: Рис 47. Настройка сервиса CruiseControl.NET Server, шаг 2 Сохраняем изменения и запускаем сервис. Открываем браузер, переходим по следующей ссылке "http://localhost/ccnet/". Рис 48. Cruise Control.NET Dashboard С этого момента проект можно собирать нажатием 1-й кнопки - "Force", при этом будет взята последняя версия проекта из репозитория, запущен билд и тесты. На самом деле, еще много чего можно сделать, например можно настроить автоматический билд после каждого коммита, вместо билда по нажатию кнопки. Можно настроить рассылку писем всем разработчикам с результатами билда (достаточно юзабильная вещь), в письме можно будет увидеть последние изменения и определить кто завалил билд. ЗаключениеСуществует методика, которая называется "12 шагов Джоэла Спольски". Это набор из 12-ти субъективных методов, которые могут привести к успеху в разработке проекта. В данной статье было рассмотрено 3 шага из 12-ти, а это уже что-то (существуют фирмы, в которых не наберется даже 1-го балла). Приведенный в статье метод разработки не нужно считать панацеей, т.к. существует много способов все усложнить на ровном месте, как говорится: "Кадры решают все". Так или иначе, принимать информацию к сведению или игнорировать, решать вам. Теперь давайте ответим на вопросы, которые были заданы в начале статьи: - сколько действий вам нужно сделать, чтобы собрать проект, включая установку Windows Services, дейплоймент веб сайта, запуск тестов (вы же пишете тесты?)? Если выключен UAC, тогда 1 - запустить правильный таргет - что вам нужно сделать, чтобы настроить всю инфраструктуру на машине нового члена команды? Сделать checkout из репозитория, запустить таргет, модифицировать файл hosts - как часто у вас собирается проект на Тест-сервере? Несколько раз в день (возможно настроить на сборку после каждого коммита) - насколько отличается процесс деплоймента на машине девелопера, qa сервере и production сервере? Абсолютно идентичен, все сводится к запуску правильного таргета - сколько человек в команде сумеют развернуть проект на production сервере? Кто угодно сумеет это сделать, т.к. для этого нужно всего лишь запустить таргет для деплоймента |