понедельник, марта 31, 2008

Console Application - дурное дело, не хитрое?

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

  1. Измените сигнатуру метода Main. Вместо static void Main(string[] args) используйте static Int32 Main(string[] args). Значение Int32, возвращаемое методом будет использовано, как Exit code приложения. Это позволит вашему приложению просигнализировать вызывающему коду о характере возникших проблем. Обычно в качестве Exit code, сигнализирующего об успешном выполнении используют значение 0. Значения отличные от нуля сигнализируют о наличии ошибок.

  2. Поместите все тело метода Main() в блок try – catch. Необработанные исключения делают невозможным использование вашего консольного приложения в пакетах и сценариях. В блоках catch вы можете возвращать различные значения (отличные от нуля), которые расскажут вызывающему коду о характере произошедших ошибок. Для обработки ошибок вы можете использовать событие AppDomain.CurrentDomain.UnhandledException, но, на мой взгляд, try – catch в Main() и проще и нагляднее.

  3. Не используйте чтение с консоли (Console.Read() Console.ReadKey() Console.ReadLine()) потому, что это может оказаться неприятным сюрпризом для тех, кто использует ваше консольное приложение в пакете для автоматизации каких либо действий. Для ввода значений используйте либо аргументы командной строки, либо (если значений очень много) файлы.

  4. Предусмотрите выдачу help-a по параметру /? Это существенно облегчит жизнь тем, кто будет использовать утилиту, а от вас не потребует много труда на реализацию.

  5. Не скупитесь на Console.WriteLine() в коде своей утилиты. Пусть она подробно рассказывает о том, что делает, особенно при выполнении длительных операций. При обработке исключений используйте Console.WriteLine(exception.ToString()). Таким образом, вы выведите максимальное количество информации об ошибке, в т.ч. и stack trace. Для консольной утилиты это самое то, что надо.

Mashup Security

Интересная заметка о Mashup Security на Technology Review.
Смогут ли машапы стать безопасными? От этого зависит укоренится ли эта технология в enterprise секторе либо ее уделом останутся разнообразные Pageflakes, Netvibes и Yahoo Pipes, пока ее не смоет новой волной какого нибудь Web 3.0.
Проблемма в основном в том, как обезопасить корпоративные источники данных. Злодейский код из чужого домена, подмешанный в машап может с легкостью получить корпоративные данные и слить их куда надо, воспользовавшись царящим на сегодняшний день в машапах бардаком с доступом к учетным записям.
Microsoft, как обычно предлагает ввести новые тэги (читай изменить стандарты) и добиться того чтобы все браузеры их понимали (знакомо, не правда ли).
IBM предлагает другое решение - Smash, который не требует изменений в браузерах и будет разруливать неразбериху с credentials в машапах. Они даже предлагают исходники своей разработки в OpenAjax Alliance. Но энтузиазма на лицах ajax-оводов пока не наблюдается: "the next step for the mashup industry is to make sure that we develop a universal picture of security."
Видимо Smash на универсальное решение все же не тянет.

четверг, марта 27, 2008

100% требований. Или «дьявол кроется в деталях».

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

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

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

Нам повезло, человек, который занимается этим новым направлением, и которого назначили владельцем системы, оказался очень грамотным специалистом и просто приятным человеком. За пару встреч с ним мы (менеджер проекта, аналитик, и архитектор) обсудили контуры будущей системы и получили общее видение, которое и оформили в виде соответствующего документа, в придачу наши ребята за пару дней соорудили прототип на статическом HTML. Прототип очень понравился заказчику, и он готов был дать отмашку на начало разработки (система нужна была ему, как говориться «уже вчера»), но не тут-то было. Руководство потребовало описания всех требований, составления детального план графика проекта и назначения формального milestone «Утверждение требований».

Что поделаешь, во времена моей юности в таких случаях говорили «Партия сказала – надо, комсомол ответил – есть». Мы взялись за формирование детальных требований. Владелец системы, конечно, не мог уделять нашему аналитику много времени (ему надо было новый бизнес поднимать) и он назначил для этих целей пару своих экспертов. Мы начали расписывать детальные use case, а наш прототип начал усложняться и детализироваться. Мы детально расписали атрибуты документов и их жизненный цикл. Мы описали и реализовали в прототипе все экранные формы. Мы согласовывали все, вплоть до заголовков столбцов и надписей на кнопках. Но чем глубже мы погружались в детали, тем становилось хуже. Я уже говорил, о том, что бизнес процесс заказчика был новый, и существовал в основном лишь в головах людей, с которыми мы говорили. При детализации требований всплывали противоречия, которые наши собеседники на ходу пытались разрешить. Их решения аккуратно записывал наш аналитик. Когда мы рассматривали эти решения, всплывали новые противоречия, и этому не было конца. Хуже того, когда мы на следующей встрече показывали прототип того, что обсуждали на предыдущей встрече, обычно обсуждение начиналось по новой и принималось какое нибудь новое решение. Некоторые формы прототипа мы переделывали таким образом по три-четыре раза. Фактически мы уперлись в невидимую стену. Чем больше у нас становилось требований, тем больше в них обнаруживалось противоречий. Так прошло два месяца, но от полной непротиворечивой картины нашей будущей системы мы были так же далеки, как и в тот день, когда в первый раз показали прототип системы заказчику. Не даром говорят, что дьявол кроется в деталях. Стоит ли говорить о том, что наши разработчики все это время нервно курили в сторонке :).

Тут многие спросят, а зачем мы вообще занимались этой, извините, ерундой. Вообще-то, такая ситуация повторяется из раза в раз, вовсе не из-за глупости и неопытности участвующих в ней людей, а под давлением объективных обстоятельств. От команды разработчиков руководство требует наличия полного описания всех требований к системе, и проведение формального approve этих бумаг заказчиком. Заказчика, в этих обстоятельствах, придавливает груз ответственности, которую на него взваливают тем же самым требованием формального утверждения всех требований. Понятно, что после этого шага заказчик оказывается в заведомо невыгодном положении. У него нет уверенности в том, что собранные требования верны, а после формального утверждения команда разработчика смело может отфутболивать все его просьбы о внесении изменений в будущую систему. Получается, что и команда и заказчик находятся под давлением из-за необходимости утверждения всех требований к системе до начала разработки. Что поделаешь, среди менеджеров среднего звена распространено мнение, что это (milestone «Утверждение требований») хороший способ минимизации проектных рисков. Можно сколько угодно цитировать высказывания Крэтчена, Лармана, Фаулера и других корифеев о бессмысленности этого шага (я бы добавил, что очевидна его вредность), но это действительно хороший способ прикрыть задницу менеджера в отношениях с заказчиком, и тут ничего не поделаешь.

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

В заключение, небольшой case study:
  • никогда не пытайтесь сформулировать 100% требований к системе. Есть очень ограниченное число случаев, когда это возможно сделать в принципе. Из своей практики я могу привести лишь пример портирования существующей системы на новую платформу. Даже традиционные «тяжелые» методологии наподобие RUP не требуют формирования 100% требований до начала разработки. Если кто-то требует от вас сделать это, значит этот человек недостаточно профессионален в области разработки софта. Уточняйте и формируйте требования до тех пор, пока не почувствуете что у вас и у заказчика сформировалось единое видение системы, и вы понимаете как ее сделать.

  • если вы оказались в ситуации, когда с вас требуют 100% требований до начала разработки, не бодайтесь со стеной. Направьте свою энергию на установление хороших контактов с заказчиком и носителями экспертизы в предметной области. Требования все равно будут меняться и уточняться и хороший контакт с этими людьми поможет вам добиться успеха во время разработки.

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

среда, марта 26, 2008

Что вы тут понаделали?

Когда вы ведете разработку в стиле Agile или XP, это означает, что через пару итераций (3-4 недели), систему которую вы продолжаете разрабатывать, уже вовсю используют. К сожалению так бывает далеко не всегда. Владельца системы обычно пугает тот факт, что еще недоделанная система будет использоваться его сотрудниками в реальных условиях. А если это финансовая система? А если это business critical приложение? Часто разработчиков даже близко не подпускают к их системе в production. На одном из моих проектов только выкладка в production занимала две недели. И тем не менее заказчик хочет Agile и разработчики готовы его изобразить.
Обычно все сводится к тому, что раз в две недели владелец системы приходит к разработчикам (на Scrum или еще как), и те демонстрируют ему свои достижения. Кусок работы считается сделанным после того, как его показали заказчику. Далее составляется план на следующие две недели (в виде набора user story или еще как) и работа кипит дальше.
Вот все это называется нехорошим словом "суррогат", а вовсе не agile. В конце концов, когда дело подходит к сдаче проекта, выясняется, что система сырая и буквально разваливается на глазах, баги сыпятся из всех щелей, а часть задекларированного функционала не сделана вовсе. Сроки проекта съезжают на пару месяцев. Если проект выполнялся по фиксированному бюджету, то матерятся разработчики, потому как работают за даром. А если оплата идет по времени, то уже заказчик проклинает весь этот agile, потому как мало того что ему сроки прослайдили, так и платить за это безобразие должен он сам.
Отстутствие работающей системы разрушает систему agile процесса не хуже чем отсутствие нормальных коммуникаций с заказчиком. При выкладке новой версии в production о любом новом баге становится известно максимум на следующий день, и способы, которыми пользователи системы доносят эти не благие вести до разработчиков очень хорошо дисциплинируют последних. В отсутствии работающей системы демонстрация результатов итерации заказчику превращается в необременительное шоу, - "показываем то, что работает, что не работает - про то рассказываем (ничего, в понедельник доделаем)".
Что же делать в таких случаях? Вспомнить о гибкости agile. Вот несколько советов:
  • Обязательно ведите и храните требования. В виде user story, use case, карточек. В backlog-е или на бумаге - не важно. Важно чтобы они были. Обычно работающая система и есть воплощение требований, но у вас нет работающей системы.

  • Введите практику формальной приемки user story заказчиком или владельцем системы. Это подразумевается и в XP и в других agile методиках, но об этом часто забывают. Без приемки карточка не может считаться выполненной. Это можно организовать либо настройкой workflow в backlog-е системы, при котором работы закрывает только заказчик, либо отметками на карточках, если они ведутся на бумаге.

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

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

среда, марта 05, 2008

LINQ to Everything

Я немного перефразировал заголовок оригинального поста Link to Everything: A List of LINQ Providers в блоге Charlie Calvert's Community Blog.
Там приведен действительно впечатляющий список провайдеров LINQ начиная с Active Directory и Excel и заканчивая Amazon и Flickr. А как вам, к примеру, LINQ to JavaScript?
Да, пожалуй LINQ, это на сегодня самая "гормкая" и популярная инновация от Microsoft в области програмных языков.

вторник, марта 04, 2008

ASP.NET MVC Framework

Должен вам признаться в том, что я жуть как не люблю ASP.NET WebForms. Я не люблю их за то, что они хотят казаться WinForm-ами, а это у них плохо получается. Я не люблю их за постбэки (postback) и их аццкие порождения – вьюстэйты. Это не религиозные чувства, просто все это очень сложно и с ними не удобно работать. Viewstate тяжело контролировать, а в купе с серверными событиями он порождает очень неэффективные решения, которые по полной грузят и канал и сервер. Механизм postback-ов провоцирует размещать код, отвечающий за сценарий взаимодействия с пользователем (workflow) в самих aspx формах. Постепенно они обрастают кодом, который естественно не охвачен модульными тестами и служит постоянным источником проблем.

Но, есть хорошая новость. В готовящемся к выпуску пакете Microsoft ASP.NET 3.5 Extensions есть замечательная штука под названием MVC Framework.

В своем блоге Scott Gu опубликовал несколько подробных постов с описанием MVC Framework, ссылки на которые собраны под заголовком «ASP.NET MVC Framework Road-Map»

Что же такого хорошего предлагают нам под маркой MVC Framework?

Во-первых, это честный Model View Controller фрэймворк, который к тому же очень красиво спроектирован. Он позволяет делать хорошо структурированные решения, и предлагает для этого очень удобный инструментарий. Web запросы обрабатываются не ASP.Net страницами, а классами контроллерами. Контроллеры содержат всю бизнес логику, а на долю web страниц оставлена лишь отрисовка UI.

Во-вторых, MVC Framework легко расширяем. В качестве модели можно использовать практически все что угодно: ADO.Net DataReader-ы и DataSet-ы, любые ORM фрэймворки, XML, и конечно LINQ to SQL. В качестве View можно использовать обычные ASP.NET формы и контролы, или написать свои собственные, хотя MVC предлагает свой готовый набор компонент и утилит для генерации представления.

В–третьих, MVC Framework спроектирован максимально удобно для модульного тестирования. Основные контракты реализованы через интерфейсы, и легко заменяются mock-объектами (у меня сложилось впечатление, что необходимые mock-и уже есть в составе фрэймворка). Контроллеры и URL-мапперы можно тестировать вне ASP.NET процесса и приложения. Представления практически не содержат кода, кроме биндинга и рендеринга. Все это облегчает тестирование MVC приложения.

В-четвертых, MVC Framework содержит мощный и гибкий механизм URL-маппинга. Так, например, можно сменить формат URL с вот такого «/products/edit.aspx?id=4», на вот такой «/products/edit/4», и при этом не придется изменять ни одной строчки кода, в контроллерах и web станицах. Достаточно только поменять URL-маппинг.

При всем при этом, MVC Framework не отменяет и не конфликтует (я надеюсь…) с существующими фичами ASP.NET, такими как аутентификация windows/forms, membership/roles, механизм провайдеров, кэширование данных, master pages и т.д.

В общем, MVC Framework производит очень приятное впечатление. С нетерпением буду ждать его выхода. Вот только не понятно мне, почему он выходит в составе ASP.NET Extensions, по моему ему самое место в ASP.NET Core :)