Опыт Создания Фреймворков

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

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

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

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



Зачем нам нужны фреймворки?

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

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

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

2. Унификация решений.

Программисты иногда меняют работу.

Для борьбы с негативными сторонами подобных ситуаций технологии предоставляют некоторые унифицированные методы решения типовых проблем.

Это уменьшает количество велосипедов и сокращает время, необходимое новому человеку для присоединения к проекту.



Точки роста или созревания технологии

Немного о том, как в нашей стране зарождается новое технологическое направление.

Время от времени используемые платформы меняются и необходимо создавать технологии для этих новых продуктов.



Детский сад
В связи с тем, что наш продукт не является законченным приложением, для начала проекта-прототипа выбирается любая предметная область (1-3 штуки).

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

Просто ради интереса, последняя такая система у нас использовалась для отслеживания домашних кошек в квартире.

Особенность прототипов в том, что код сильно перепутан и непонятно, где технологический уровень и где начинается прикладная логика.

Этот «кошачий» проект используется для разработки всех необходимых компонентов, генераторов и элементов пользовательского интерфейса.

Над проектом работают только технологи.



Школьное время
Когда приходит время опробовать технологию на чем-то более серьезном, из числа коммерческих выбирается «жертвенный» проект. Как правило, на его разработку можно отвести в 1,5 – 2 раза больший срок, чем на типовой проект (все понимают, что есть риски, так как мы используем технологию впервые и компания сама оплачивает технологические работы).

, а не клиент).

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

Над проектом работают как технологи, так и прикладные программисты.

Следует понимать, что базовые подходы еще отлаживаются и не все в технологии готово на 100%, поэтому проекту будут присущи «велосипеды», усложняющие поддержку.

Иногда эти «велосипеды» заменяются стандартными технологическими решениями, иногда остаются такими до конца.



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

Переключаемся в обычный «рабочий режим».

Разработчикам приложений больше не нужна прямая помощь технологов.

Технологические сборки поставляются в собранном виде.

Задачи на улучшение и сообщения об ошибках отправляются в технологический проект TFS.

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

Как правило, такие новинки сразу становятся востребованы всеми активно развивающимися проектами.

Забавно, что иногда по окончании разработки очередной фичи приходит прикладной программист и просит реализовать именно эту.



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

Вместе с ними технология «уходит на пенсию» и переходит в режим разработки с учетом ошибок.

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

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

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

На основании них мы определим, что то, что работало раньше, не сломается.

• Пишем функционал • Проверяем качество и соответствие заявленным требованиям

Техническая сторона вопроса

Теперь немного о техниках и техниках.

Мы будем говорить о Microsoft .

NET Framework, поскольку наши решения построены на этой платформе.



Точки расширения
Технология должна не ограничивать программистов, а давать преимущества перед решением с нуля, а иногда и полностью готовыми решениями.

Чтобы программист проявил свою индивидуальность там, где технология «слишком стандартна», мы используем следующие подходы: • Наследование.

Существует базовый класс, реализующий стандартное поведение и расположенный в технологической сборке.

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

• События.

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

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

• Делегаты.

Аналогично событиям, но реализация может быть только одна.

Это предотвращает нежелательное срабатывание несколько раз.

• App.config. В файл конфигурации попадают разные мелочи.

Как правило, это какие-то флаги и пути (нужно ли писать отладочную информацию, строки подключения к сервисам и т.п.

).

•ДИ.

Этот вариант предполагает переопределение всего модуля.



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

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

В любом случае нам нужно как-то об этом сигнализировать.

Мы используем Log4net. Для выделения технологических сообщений можно использовать либо отдельный логгер, либо присвоить технологии уровень ошибки, например Warn.

XML-комментарии
XML-комментарии в коде процесса чрезвычайно важны.

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

Это приведет к помощи ( http://sandcastle.codeplex.com/ ) и предоставлять подсказки в проектах приложений благодаря IntelliSense. Не забудьте в настройках проекта указать необходимость формирования xml-файла с комментариями.



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

Если такое обновление можно предсказать, то нужно заранее предупредить, например, с помощью атрибута Устарело: [Устарело("Ээта функция будет удалена в следующей версии, используйте эту функцию")] Иногда приходится пойти на поводу и применить правило: «лучше один раз добавить, чем дважды обновить», т. е.

если в каждом проекте приложения сигнатура метода используется в 1000 местах, менять ее в технологии — не лучшая идея.

Самое главное правило: всегда подробное описание возможных проблем с обновлением – предупрежден, значит вооружен.



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

Для хранения информации мы используем движок Wiki с разрешением на запись от технологов.

Чтобы поддерживать актуальность информации, применяются 2 правила: 1. Сделал работу - запиши в Вики! 2. Ответил на вопрос - запишите его в Вики! Уровни описания: 1. Для себя (как это работает) 2. Для программистов прикладных проектов (как использовать методы и классы) 3. Для пользователей системы (как пользоваться компонентами)

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

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

Однако разные проекты требуют немного разных функций.

Что можно использовать? 1. Ссылки на cs файлы между проектами (работа с проектами становится немного сложнее) 2. ILMerge (это можно поручить Build-серверу, но отладка затруднительна) 3. Сборки в ресурсах (с отдельным механизмом загрузки сборок)

Подписание сборок или строгое имя
Еще одно железное правило: все технологические сборки должны быть подписаны.

Это дает нам следующие преимущества: 1. Подписанные сборки однозначно идентифицируются в GAC. 2. Подписать можно только в том случае, если подписаны все зависимые сборки (сборки приложений не смогут подписывать, если технологические сборки не подписаны) 3. Некоторая степень защиты (для изменения кода потребуется пересобрать все сборки приложения) Если случилось так, что код из сборки утерян, то подпись можно сделать, пересобрав сборку.

Пересборка производится таким образом (чтобы указать файл с ключом ищите специальный параметр): 1. ildasm.exe sampleA.exe/source/out:sampleA.il 2. ilasm.exe sampleA.il /exe /out:sampleA.exe

Стратегия выпуска
Чем чаще выходит продукт, тем меньше пользователям кажется, что программисты ничего не делают. Мы протестировали 2 варианта выпуска версий технологических продуктов: 1. Последние сборки — лучшие Все, что помещено в SourceControl, считается проверенным и программисты приложений могут брать любую серверную сборку технологических сборок.

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

• Ошибки могут легко проникнуть в версию клиента.

2. Периодический выпуск стабильной версии Периодический выпуск версий сборки технологии.

Плюсы: • Более надежная проверка интеграции.

Минусы: • Существует риск потери контроля над кодом в середине итерации.

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

Это вариант, который мы сейчас используем.



Версии сборки
Существует 2 стратегии именования версий сборки: 1. Изменяемые версии сборок • Обновление проектов приложений только с перекомпиляцией проекта (невозможность отправки технологического патча напрямую заказчику) • Некоторые проблемы будут видны во время компиляции (актуально для сложных зависимостей между сборками) • Проблема с сериализацией типов (сериализованные данные, хранящиеся у клиента, могут вызвать проблемы при обновлении версий сборки) 2. Фиксированные версии сборок • Обновление путем простой замены сборок • Проблемы будут видны при запуске, потому что.

при обновлении перекомпиляция не требуется.

• В крайнем случае заказчику можно отправить только исправленную сборку.

• Дата выпуска сборки как условная версия для идентификации.

Наша команда остановилась на втором варианте, потому что.

Часто приходится тестировать новые технологические сборки на прикладных проектах, но перекомпилировать их нет ни желания, ни времени.

У нас есть сборки серверов, настроенные в Team Foundation Server, и только сборка сервера может быть отправлена на реализацию.



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

Минус: • Требуется много слияний кода.

Одинарная версия без ответвлений Плюс: • Никакого слияния Минус: • Разобранная версия не подлежит быстрому ремонту Мы остановились на более простом втором варианте.

Мы стараемся не вносить долгосрочные изменения без Check-In, но Check-In не должны ухудшать производительность наших решений.



Внешние сборки
Несколько слов об OpenSource в коммерческом продукте: при желании можно найти OpenSource-решения с хорошей лицензией для решения любой желаемой задачи.

Однако, принимая такое решение, следует хорошо подумать, как там будут вноситься изменения: 1. Редактируйте все локально самостоятельно Плюс: • Ты можешь делать что угодно Минус: • При обновлении официальной версии вам придется объединить свои изменения самостоятельно.

2. Отправляйте обновления команде, поддерживающей проект. Плюс: • Дополнительная проверка качества исправлений Минусы: • Риск прекращения поддержки • М.

б.

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

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



Обфускация
Как защитить от дизассемблирования код, доступный как из приложения, так и из технологических сборок? Можно запутать технологические сборки перед передачей их в проект, но тогда получим: Плюс: • Программисты приложений не будут совать нос в технологический код и задавать по нему глупые вопросы Минусы: • Сложность отладки для разработчиков приложений.

• Возможная нестабильность во время разработки • Обфускация и проверка будут выполняться дважды.

Второй вариант — обфускация всего готового приложения со всеми технологическими сборками.

Плюсы: • Обфускация на этапе сборки приложения • Возможность отладки приложения путем ввода кода платформы.

Проверка заявки производится один раз Минус: • Защита технологических узлов осуществляется прикладными программистами Мы используем последний вариант.

Тестирование
Про юнит-тесты говорить не буду — это нужно любому слою, не только технологическому.

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

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

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

Только эта опция помогает отделить «помехи» от кода приложения.



Заключение

Могу отметить, что работа над техникой – очень увлекательное и порой забавное занятие.

Главное — не слишком увлекаться и иногда общаться с конечными пользователями, пытаясь понять их потребности.

Спасибо всем, кто дочитал этот длинный монолог до конца.

Теги: #.

NET #.

NET

Вместе с данным постом часто просматривают: