Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Ответы по_TRPP.docx
Скачиваний:
0
Добавлен:
01.05.2025
Размер:
45.47 Кб
Скачать

Роль прецедентов в проекте

Прецеденты играют жизненно важную роль при реализации унифицированного процесса, поскольку вся разработка в рамках этого подхода осуществляется под управлением прецедентов (use-case driven development). Это означает следующее.

• Требования в основном формулируются при описании прецедентов (в моде­ли прецедентов). Остальные требования (если таковые существуют) являют­ся либо техническими (например, список функций), либо второстепенными.

• Прецеденты — важный этап итеративного планирования. На каждой итера­ции реализуются некоторые сценарии или целые прецеденты. Поэтому опи­сания прецедентов вносят существенный вклад в оценивание результата.

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

- Прецеденты служат основой приемки программы и приемочного тестирования.

  1. Роль тестирования в ХР

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

Основные роли (цели) тестирования в XP:

  1. Поиск и исправление ошибок (средство отладки).

  1. Приемка готового продукта (средство приемки).

  2. Верификация проекта (устойчивость и целостность разработки)

  3. Средство улучшения проекта (рефакторинга).

  4. Документирование модулей (как CRC - карточки).

  5. Сама разработка (Средство разработки в TDD).

  6. и т.д.

  1. Возражения по составлению модульных тестов

  1. Исчерпывающее тестирование сразу приводит к мысли о двойном объеме работ

. То есть, вместо одного проекта приходится писать два. Да, это так. Казалось бы, это представляет основную проблему. И это действительно основной аргумент противников модульного тестирования в XP.

2) Тесты мешают думать над основной задачей Некоторые разработчики чувствуют, что инкрементальное юнит тестирование прерывает процесс. Они пишут большой кусок сложного кода для приложения, и беспокоятся, что остановка для того, чтобы написать тест приведет к тому, что они забудут, на чем остановились

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

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

5) У меня уже есть очень много строк старого кода Никто и не отрицает. Это очень трудно - добавить юнит тесты к старому коду. Этот код, возможно не структурирован так, чтобы можно было легко тестировать. Даже если и структурирован, это огромные издержки - добавить все тесты. Хорошо протестированная система будет иметь больше строк, чем рабочий код.

6) Бывает код, который нельзя протестировать. Проведя некоторое время в борьбе с оправданиями, чтобы не делать юнит тесты, мы должны покаяться. Это одно оправдание, которое имеет основу

  1. Экстремальное планирование

Для чего выполняют планирование в XP

- чтобы заниматься самыми важными делами на данный момент;

- чтобы согласовывать свои действия с действиями других людей ( сдругими разработчиками при командной разработке, с заказчиком – всегда);

- чтобы знать, что делать при возникновении нештатных ситуаций при выполнении двух предыдущих пунктов.

Итак, мы провели анализ (начальный этап), возможно, подумали об архитектуре нашего приложения (собственно, только эскизно). Да, еще, возможно, мы написали несколько прототипов (программок, которые можно набросать за 1-2 дня, а лучше меньше). Что мы делаем дальше ? Мы должны заняться планированием. Но не стоит думать, что планирование в XP это какой-то этап разработки – это, скорее, процесс, как и проектирование и тестирование и рефакторинг. Планирование должно выполняться постоянно !

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

Итеративность разработки.

Планирование выполняется постоянно. План постоянно подвержен изменениям.

«Ловушка планирования» - ?.

Составляются разные по степени подробности и временному интервалу планы : план версий, план итераций, план текущей итерации план масштаба дня и т.д.

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

Одним из ключевых моментов планирования является измерение производительности команды разработчиков. Производительность измеряется в задачах, решенных за «идеальный день», соответственно план расписан в идеальных днях.

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

Одной из ключевых идей планирования ( и всей книги ) является следующая простая мысль: если разработчики не успевают выполнить определенный объем работ, то это означает, скорее всего, что он просто слишком велик, и его нужно пересмотреть в сторону уменьшения. Это выполняется, естественно, заказчиком. То есть, разработчики не говорят – «нам не хватает времени», они говорят «у нас слишком много дел». Речь не идет об обмане и лентяйстве – речь идет только о трезвой оценке своих возможностей и борьбе со стрессом и переработкой.

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

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

  1. Проектирование архитектуры

  2. Компоненты архитектуры

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

2) Основные классы приложения. Имеются в виду не все классы, а именно основные ! Действует принцип 20/80 – определить 20% классов, которые реализуют 80% поведения системы. Это сделать достаточно сложно, здесь можно руководствоваться опытом, здравым смыслом, моделью предметной области, базовыми принципами ООП, прецедентами и требованиями и пр. Для крупных систем нужно рассмотреть групировку классов в подсистемы (в контексте UML модели это можно отобразить с помощью диаграммы пакетов UML).

3) Организация данных. Рассматриваются основные файлы и таблицы БД системы, структуры данных для представления основных данных предметной области. Обращение к хранимым данным (файлы и БД) обычно осуществлется через один класс или подсистему. Если БД присутствует в проекте, она должна быть описана, как и проект на высоком уровне (то есть – основные таблицы, отношения и пр.). Должно быть обосновано использование именно одной БД, либо – нескольких, обоснован физический тип БД или сервера.

4) Бизнес-правила. Если система использует бизнес-правила, они должны быть рассмотрены и определено, как они влияют на архитектуру. Например, если имеется бизнес правило, что данные о клиенте (покупателе) должны быть «не старее» 30с, нужно рассмотреть, как архитектура поддерживает обновление и синхронизацию данных и т.д.

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

6) Ввод / вывод. Архитектура должна предусматривать упреждающее считывание, считывание по требованию (?), ввод-вывод в реальном времени, способ организации файлового ввода-вывода, уровень обработки ошибок при I/O и т.д.

7) Управление ресурсами. (соединения с БД, файловые дескрипторы, потоки, память, другие ресурсы, работа в нормальных условиях и экстремальных случаях, когда требуется ограничить потребляемые ресурсы и пр.)

8) Безопасность. (На уровне кода и проекта. - см. книгу Безопасный код. Работа с буферами, обработка небезопасных данных – пользовательский ввод, запросы к БД, конфигурационная информация, защита данных в памяти, объем информации в файлах лог, в сообшениях об ошибках, криптография, модель угроз и хакерских атак и пр.)

9) Производительность.

10) Масштабируемость.

11) Интероперабельность. То есть, насколько программа будет способна (если должна) взаимодействовать с другими системами, оюмпениваться с ними данными или совместно использовать ресурсы.

12) Интернационализация и локализация. («I18N» и «L10N»).

13) Обработка ошибок. По оценке некоторых исследователей до 90% (!) кода приложения посвящено особым, нестандатным, исключительным и ошибочным случаям. Поэтому стратегия обработки ошибок должна быть отражена в архитектуре.

14) Устойчивость к сбоям.

15) Реализуемость архитектуры (feasibility).

16) Переработка (?)

17) Решения вида Разработать-Купить.

18) Вопросы повторного использования (reuse). Они касаются как повторного использования ранее разработанных модулей в данном проекте, так и (реже) – возможностей использования разрабатываемых модулей в других параллельных или будущих проектах.

19) Стратегия обработки изменений. Несмотря на требование XP «нам это никогда не понадобится» и запрет создания инфраструктур, которые неочевидны, архитектурный проект должен предусматривать способы борьбы с изменениями, которые можно спрогнозировать. Эти способы могут включать зарезервированные поля, использование кодогенерации и ее оценку, использование интерфейсов для классов, модульность, табличную реализацию конечных автоматов, использование метаданных, настроечных файлов, макросов и пр.

20) Общая оценка качества архитектуры. Здесь оценивается общая концепция архитектуры, ее целостность, красота и степень сбалансированности, а также степень соответствия решаемой задаче. (Ф. Брукс – проблема целостности). Основные цели архитектуры должны быть понятны (например, архитектура, рассчитанная на грядущие изменения и гибкость может сильно отличаться от архитектуры, нацеленной на производительность и пр.) При рассмотрении всех компонентов рассматриваются альтернативы и обосновывается выбранное решение. Нельзя доверять только опыту и правилу «мы всегда так делали и оно работало» (История про готовку).

  1. Признаки «плохого» кода

Дублирование кода (Duplicated Code)очень часто встречающаяся ситуация и одна из самых проблемных : два и более одинаковых (или похожих) фрагмента как минимум приводят к необходимости синхронизировать все изменения в разных фрагментах, размер кода увеличивается, он становится трудно обозримым и пр.

Длинный метод (Long Method) – метод процедурного типа, который содержит много кода и много последовательных действий. Типичный признак процедурного, а не объектного стиля программирования. Такой метод рекомендуется разбить на несколько, а на возмжные границы методов часто указывают комментарии.

Комментарии (Comments) – сами по себе комментарии не являются проблемой, но часто они либо а) приводятся для того, чтобы прокомментировать запутанный фрагмент кода, либо б) приводятся, чтобы прокомментировать очередной шаг в длинном методе. Оба эти случая нуждаются в рефакторинге.

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

Длинный список параметров (Long Parameter List) – слишком большой список параметров, усложняющий вызов функции / метода. Сами по себе параметры не вредны, однако нужно стараться, чтобы их не было слишком много (ну, скажем, более 10). Части параметров можно присваивать значения по умолчанию, в ряде случаев можно вместо вписка параметров использовать параметр-объект.

Расходящиеся модификации (Divergent Change) – ситуация, возникающая из-за нарушения принципа персональной ответственности (SRP), когда для изменения класса существует более одной причины (две или больше осей изменения). То есть, если класс имеет более одной ответственности, каждая из которых может меняться, придется все время править класс, а возможно, и часть его клиентов.

Стрельба дробью (Shotgun Surgery) – внесение какого-то одного изменения приводит к необходимости изменять целый ряд классов.

Группы данных (Data Clumps) - элементы данных, используемые совместно, лучше выделять в классы, или хотя бы для начала в структуры.

Классы данных (Data Class) – это классы, которые содержат только атрибуты (поля), но практически не содержат методов (как структуры), либо содержат только методы доступа к полям. Такие классы полезны на начальных этапах проектирования, но затем на них необходимо возложить дополнительные ответственности.

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

Неуместная близость (Inappropriate Intimacy) – аналогичная ситуация предыдущей, но касается двух и более классов – они слишком активно используют и методы друг друга, и зачастую – те методы и данные друг друга, которые в принципе лучше бы закрыть (либо они вообще имеют доступ к закрытым полям и методам, являясь “друзьями” - friend classes).

Большой класс (Large Class) - раздутый класс, имеющий слишком много методов, то есть сложный интерфейс, зачастую он же имеет слишком много ответственностей.

Ленивый класс (Lazy Class) – класс, который ничего или почти ничего не делает, имеет мало методов, которые редко используются клиентами.

Альтернативные классы с разными интерфейсами (Alternative Classes with Different Interfaces) - имеются два или более класса для выполнения одних и тех же действий, но имеющие разный интерфейс.

Цепочки сообщений (Message Chains) – слишком длинные цепочки делегирования (вызовов методов других классов).

Посредник (Middle Man) – класс, который выполняет только пересылку информации между другими классами.

Отказ от наследства (Refused Bequest) – классы-наследники не используют функциональность родительских классов, иногда и клиенты не используют функциональность родительских классов, общаясь с наследниками. (Речь не идет о наследовании от интерфейсов).

Теоретическая общность (Speculative Generality) – нарушение принципа “нам это никогда не понадобится” - проявлется в том, что создаются излишне абстрактные классы, параметризуемые классы и другие средства для возможного расширения функциональности в отдаленном будущем.