Здравствуйте, Неизвестный пользователь
No DB connection
 
Пообщаться
Шутки
Ссылки
Книги
Статьи
Новости
Версии
 
Логин

Пароль

Регистрация

Статьи

08.09.2004/126

Введение 3 Что такое исследовательский проект и зачем нужна методология . 3 Типичные черты исследовательского проекта. 3 За кадром_ 4 Структурная сложность_ 4 Что такое структурная сложность системы? 4 Способы борьбы со структурной сложностью. 5
Методологии программирования_ 5 Модель системы_ 6 Процесс разработки системы. 6 Простейший процесс 7 Итерационный процесс 7 Улучшенный итерационный процесс 7 Языки программирования. 9 Дополнительные ограничения. 9
Что было до ОО? Структурная методология_ 10 Структурная модель системы_ 10 Динамическая модель 10 Статическая модель 10 Языки программирования_ 10 Что плохо?_ 10 Что хорошо?_ 11 ОО методология. 11 Основные определения_ 11 Три базовых понятия ООП_ 12 Инкапсуляция. 12 Наследование. 12 Полиморфизм. 12 Объектная модель системы_ 12 Иерархическая модель разбиения системы на части_ 12 Граф наследования 12 Стандартные способы изображения 13 Наследование 13 Агрегация 13 Атомарность взаимодействий_ 13 Классификация сообщений_ 14
Наблюдаемость 14 От сообщений к методам_ 14 Типичные проблемы взаимодействия объектов 14 Ограничение количества связей_ 15 Агрегация и атомарность взаимодействий_ 16 Простейшая модель 16 Модель транзакций_ 16 Языки программирования_ 17 Чем хорош ООП?_ 17 ОО Анализ 18 Предметная область 18 Исходные данные для анализа 18 Результат анализа 18 Виды деятельности при анализе 18 Идентификация Объектов и Классов 18 Идентификация структур_ 19 Обобщение-Уточнение. 19 Целое-Часть 19 Идентификация доменов 19
Определение атрибутов 20 Источники Атрибутов. 20 Связывание Атрибутов с Классами. 20 Определение сервисов 20 Сервисы и Классы_ 21 Часто встречающиеся алгоритмически простые сервисы_ 21 ОО Проектирование_ 21 Исходные данные для проектирования 21 Результат проектирования 21 Аспекты системы_ 21 Аспект предметной области_ 22 Аспект пользовательского интерфейса 22 Шаблон Модель-Наблюдатель 22 Аспект управления выполнением_ 23 Взаимодействие между объектами_ 23 Параллелизм_ 24 Реализации модели независимых актеров 25
Аспект управления данными_ 26 Проблемы стандартных механизмов сериализации_ 27 ОО Программирование_ 27 Исходные данные для программирования 27 Результат программирования 27 ОО Тестирование_ 27 Исходные данные для тестирования 27 Результаты тестирования 27 Жизненный цикл тестов 28 Тестирование пользовательского интерфейса 28 Тестирование производительности_ 28 ОО Переработка кода 28 Исходные данные для переработки кода 29 Результат переработки кода 29 Признаки необходимости переработки кода 29
Основные способы переработки кода 29 Оптимизация 29 Приложения_ 30 Базовые элементы ООП в Java 30 Нити и Синхронизация в Java 30 Реализация Read/Write Lock на Java 30 Литература_ 30 Введение Что такое исследовательский проект и зачем нужна методология. Исследовательский проект выполняется на свой страх и риск одним или маленькой группой разработчиков с целью удовлетворения научного любопытства, проверки концепций или как прототип рабочей системы.
При этом разработчики не скованы никакими внешними формальными требованиями типа проектной документации или используемых средств и методов разработки кроме одного: проект должен быть завершен в кратчайший срок. Сложные концепции для проверки требуют большого объема кода. Замечено в течение длительного времени, что при увеличении объема кода программы время разработки и количество ошибок в ней растут существенно быстрее, чем линейно. Это верно даже для программ, разрабатываемых одним человеком.
Для коллективной разработки дела обстоят еще хуже. Таким образом, возникает необходимость применения методов, помогающих уменьшить скорость роста времени разработки при увеличении объема кода. Типичные черты исследовательского проекта. - Время разработки: до 1 года - Размер: от 10 Кб до 1 Мб исходного кода. - Коллектив разработчиков: 1-2 человека
- Специфические особенности: сложные алгоритмы, высокая изменчивость кода, минимум или отсутствие проектной документации, отсутствие дополнительного тестирования. Почему именно так? Программы <10Кб всегда имеют простую структуру, и могут иметь сложность только с алгоритмической точки зрения. ~ 1Мб Объем отлаженного кода, который один квалифицированный программист может написать за год.
Либо разработчик удовлетворяет свое любопытство, либо программа переходит в другой класс (коммерческая разработка, открытый проект). Сложные алгоритмы. Как правило, цель исследовательского проекта - добиться новых неизвестных (как минимум разработчику) результатов. Все простые вещи уже придумали до нас. Отсутствие проектной документации. Документирование - дело чрезвычайно скучное.
В отсутствие внешнего заказчика большинство разработчиков считают документирование таким же странным, как разговор вслух с самим собой. Также поддержание документации в соответствии с текущей версией системы требует больших дополнительных ресурсов и почти не влияет на качество системы. Отсутствие дополнительного тестирования. Тестирование выполняется силами разработчиков. Отсутствуют требования к тестированию со стороны заказчика.
Разработчики стараются минимизировать тестирование по причине скучности написания тестов, пытаясь обойтись минимумом интерактивных тестов. Далее будут показаны недостатки такого подхода и влияние тестов на качество, и время разработки системы. За кадром Заведомо сужая область рассмотрения, мы исключаем многие важные в других типах проектов элементы, такие как: - формальный анализ требований и построение спецификаций - формальные процессы анализа и проектирования
- распределение работы между группами и сетевое планирование - межгрупповая коммуникация - документирование - формальные требования к пользовательскому интерфейсу - формальные стратегии тестирования - управление ошибками - поддержка Эти аспекты в большой степени определяются корпоративной культурой организации, к которой принадлежит разработчик. Структурная сложность Скорость роста затрат при увеличении объема кода зависит от структурной сложности системы. Что такое структурная сложность системы?
Программирование в широком смысле - это один из видов познания и изменения мира (бытия). Раздел философии гносеология - учение о познании - разрабатывается со времен античности, и методы, применяемые в программировании, ведут свои корни именно оттуда. Одним из основных методов познания мира является метод анализа-синтеза. Этот метод был формально описан Георгом Гегелем ("Логика",1817).
Вторым основным методом является метод абстракции (обобщения-уточнения) разработанный еще греческими философами (Евклид, Фалес, Платон и др.). Отличие программирования от философии в том, что вместо объяснения свойств существующих систем те же методы используются для создания новых. Способности человека к осмыслению информации ограничены. Он может одновременно зрительно воспринять объем структурированной информации, приблизительно равный одному экрану кода.
Таким образом, чтобы осознать и реализовать сложную систему, человек вынужден иерархически разбивать ее на более мелкие части, до тех пор, пока каждый элемент иерархии не достигнет размера, доступного для понимания. Для каждого уровня иерархии при этом рассматриваются только ключевые для этого уровня взаимодействия между частями. Количество подсистем линейно зависит от объема кода. Как известно из философии, сложность системы не сводится к суммарной сложности ее подсистем.
Система рассматривается как граф взаимосвязанных подсистем. Связи между подсистемами также имеют различную сложность. Структурная сложность системы - это суммарная сложность всех взаимосвязей между ее подсистемами. Как видно из определения, только за счет увеличения количества подсистем структурная сложность может расти как квадрат от объема кода (максимальное количество связей равно размеру матрицы смежности) даже без учета роста сложности самих связей.
Следует также учитывать неявные связи между подсистемами (наведенные ошибки). Почему влияние на коллективную разработку больше? Если две подсистемы разрабатываются разными людьми, то взаимосвязь между подсистемами требует общения между разработчиками, что занимает время. Недостаток такого общения приводит к скрытым взаимосвязям между подсистемами и увеличивает количество ошибок. Способы борьбы со структурной сложностью. Количество подсистем нижнего уровня линейно зависит от количества кода, которое в свою очередь непосредственно зависит от сложности задачи, которую система должна решать. Для уменьшения структурной сложности есть несколько точек возможного приложения силы: Уменьшение количества подсистем. Уменьшение сложности связей. Уменьшение количества связей.
Есть два простых механических способа уменьшения количества подсистем за счет уменьшения объема кода: Использование более выразительного языка. Использование внешних библиотек подсистем. К сожалению, эти способы не всегда позволяют радикально уменьшить структурную сложность системы, поскольку не влияют на количество и сложность оставшихся связей. Поэтому основным фактором структурной сложности является структура системы, лежащая полностью на совести разработчика.
Методологии программирования позволяют облегчить нахождение наиболее простой структуры системы. Методологии программирования Методология - это набор методов, которые при совместном применении позволяют добиться заданной цели. Методология не является обязательной. Ее применение зависит только от воли разработчика системы. Целью любой методологии программирования является уменьшение скорости роста затрат при увеличении объема кода, а значит, уменьшение структурной сложности системы.
Почему это важно для исследовательского проекта? Несмотря на то, что исследовательский проект не связан строгими требованиями по срокам и объему работ, он ограничен по ресурсам даже жестче, чем большинство коммерческих проектов. Если в коммерческом проекте в случае отставания менеджер теоретически может нанять новых сотрудников или перенести срок сдачи, то в исследовательском проекте коллектив разработчиков почти никогда не может быть расширен.
А при достижении критического отставания от графика разработчики просто оставляют проект. В состав методологии всегда входят правила построения иерархической модели системы и описание процесса разработки системы. Примеры: структурная методология, объектно-ориентированная методология. Модель системы Модель системы - иерархическое разбиение системы на подсистемы и описание их взаимодействия в соответствии с определенными правилами. Например, структурная модель, ОО модель.
Модель может быть описана различными средствами, такими, как диаграммы или код на языке программирования. Реализация системы - выполнимый код на языке программирования реализующий требования к системе. Является одновременно ее моделью. Программно-аппаратная платформа - контекст реализации системы.
В него входят: аппаратная платформа, операционная система, стандартные внешние библиотеки, сетевые протоколы, системы баз данных, другие внешние для системы сущности, не определенные требованиями к системе, но взаимодействующие с ней. Процесс разработки системы. Процесс разработки обычно состоит из нескольких чередуемых видов деятельности, таких как: Анализ (Analysis) - анализ требований к системе.
Система на этапе анализа представляется в виде черного ящика, и строится модель взаимодействия системы с внешним миром удовлетворяющая требованиям. Анализ производится вне контекста программно-аппаратной платформы реализации. Проектирование (Design) - иерархическая детализация аналитической модели системы до уровня, пригодного для последующей реализации в виде кода. Проектирование производится в контексте программно-аппаратной платформы реализации.
Программирование (Programming) - кодирование проектной модели системы на языке программирования. Тестирование (Testing) - разработка набора тестов и проверка системы с их помощью на наличие ошибок. Отладка (Debugging) - локализация и устранения ошибок. Переработка кода (Refactoring) - изменение модели и кода работающей системы для облегчения ее расширения. Процесс разработки может рассматриваться отдельно от используемых правил построения модели.
Но эти правила существенно влияют на смысл и содержание каждого из видов деятельности. То есть следует отдельно рассматривать структурный анализ и ОО анализ. Для поддержки процесса разработки часто используются несколько инструментальных средств. 1. Интегрированная среда разработки - система редактирования исходных текстов и сборки проекта, может включать в себя и другие инструментальные средства.
2. Система управления исходными текстами - служит для хранения истории изменений исходных текстов системы. 3. Отладчик - система пошаговой отладки на уровне исходных текстов. 4. Система управления тестами - база тестов с возможностью протоколирования и анализа результатов. Простейший процесс Модель системы строится по ходу кодирования. Недостатки: ошибки проектирования накапливаются. Система быстро ветшает и разваливается под собственным весом. Итерационный процесс
Модель системы строится по ходу кодирования и улучшается при необходимости. Недостатки: 1. Один и тот же работающий код переписывается по множеству раз. Вероятность совершить ошибку во время переработки кода значительно выше, поскольку перерабатываемый код обычно находится на границе текущего поля зрения разработчика. Улучшенный итерационный процесс Модель системы строится поэтапно с явным разделением на анализ, проектирование и кодирование и улучшается при необходимости.
Недостатки: те же, что и у предыдущего, но в меньшей степени. За счет лучшего качества модели переработка кода происходит реже и в меньшем объеме. Чередование деятельности. Метод волны. Не стоит пытаться сразу выполнить анализ всей системы, затем проектирование всей системы, а только потом приступать к программированию. Это может привести к отрыву проекта от реальности.
В результате при переходе к программированию может выясниться, что проектная модель нереализуема на реальной программно-аппаратной платформе. Более правильно - выполнить анализ для некоторой группы внешних взаимодействий. Затем спроектировать часть проанализированной подсистемы. Затем закодировать эту часть. Провести тестирование. Затем опять вернуться к проектированию. Когда вся подсистема будет закодирована можно, опять вернуться к анализу.
Возникающие нестыковки будут устраняться на этапе переработки кода. Таким образом, система будет расширяться от центра к краю. Разработка всегда будет вестись на периферии системы. Главным при этом является расстановка приоритетов. Первыми нужно анализировать, проектировать и кодировать более важные части системы. Более важными являются части, имеющие большое количество связей, и без которых невозможно тестирование других частей. Ключевая роль тестирования.
Несмотря на свою полезность, переработка кода является одним из основных источников ошибок. При многократной переработке кода одна и та же ошибка может возникать несколько раз. Для обнаружения таких ошибок ключевую роль играет методическое тестирование. Какие бывают тесты: По отношению к системе (подсистеме): Внешние - система рассматривается как черный ящик. Внутренние - тесты являются частью системы и тестируют отдельные внутренние подсистемы. По типам тестовых случаев:
Простые (Assertion) - проверяют характерные случаи использования системы. Граничные (Boundary) - проверяют граничные значения параметров, например, 0, 1, -1, null, INT_MAX и т.д. Покрывающие (Coverage) - проверяют отдельный путь в графе управления программы. Для осуществления методического тестирования тесты должны быть: 1. Автоматическими. То есть выполняться без участия разработчика. Результат работы теста - либо отсутствие ошибки, либо ошибка и диагностика причины ее возникновения.
2. Выполняться достаточно быстро, чтобы их можно было выполнять часто, например, после каждой успешной сборки системы. Другие применения тестов: Простые тесты могут использоваться для формализации требований к функциональности системы (функциональные тесты). Простые тесты могут использоваться в качестве рабочей документации. Простые и граничные тесты - для спецификации внешних интерфейсов. Простые тесты могут использоваться как тесты производительности. Когда какие тесты писать:
После успешной компиляции системы стоит написать простой тест на новый код. Перед переработкой кода стоит написать несколько граничных тестов для фиксации текущего поведения. Если обнаружена ошибка, необходимо написать минимальный тест, покрывающий путь в графе управления, вызвавший ее (регрессионный тест), для исключения повторного возникновения похожей ошибки. Тестовое покрытие - процент строк исходного кода системы выполненных хотя бы один раз во время прогона всех тестов.
Вероятность ошибки в коде непокрытом тестами существенно выше, этот код может быть вообще мертвым (никогда не выполняться) или там может быть написана какая-то глупость. Идеалом является 100% тестовое покрытие. Для измерения тестового покрытия служит инструментальное средство Покрытие (Coverage). Языки программирования. Язык поддерживает методологию, если существует естественная проекция правил построения модели системы для этой методологии в конструкции данного языка.
И язык хотя бы частично поддерживает проверку правильности их применения. Дополнительные ограничения. Основным результатом любого этапа разработки и любого вида деятельности должна быть исполняемая версия системы на языке реализации. Дополнительные продукты разработки также должны представлять собой выполнимый код на языке программирования или допускать автоматическую проверку соответствия текущей версии системы иным способом.
Если это не так, то ценность данного вида деятельности в исследовательском проекте сомнительна, поскольку его результат не влияет на качество кода. Что было до ОО? Структурная методология Система строится на основании структурной модели системы. Структурная модель системы Состоит из динамической и статической модели. Динамическая модель представляет алгоритм работы программы. Статическая модель описывает структуру данных программы.
Структурная методология - попытка реализации тезиса Н. Вирта "Алгоритмы + Структуры данных = Программы". Динамическая модель Система рассматривается как процесс преобразования данных, имеющий внешние источники данных и стоки для результатов. Система иерархически разбивается в направленный граф подпроцессов, соединенных каналами передачи данных. Для изображения динамической структуры системы часто используется иерархическая диаграмма потоков данных (Data Flow Diagram). Статическая модель
Статическая модель - множество структур данных, возможно иерархических, используемых для взаимодействия подсистем. Для больших систем статическая модель часто рассматривается как структура реляционной базы данных для хранения состояния системы. Языки программирования Для реализации проектов с использованием структурной методологии используются структурные языки (Pascal, C, Fortran, PL/1). Ключевые свойства структурных языков: 1. Процедуры с параметрами. 2. Контроль типов. 3. Структуры. Что плохо?
Основной является динамическая проекция, поскольку именно она является базой для написания кода. Для ее построения требуется преобразование требований к системе с переносом акцентов c субъектов на процессы. Хотя мышление человека является объектно-ориентированным (Декарт). Поскольку только объекты могут непосредственно наблюдаться. А процессы могут наблюдаться только как изменение состояния объектов. Нет четкого взаимодействия между динамической и статической проекциями.
Из-за этого большая часть внутренних взаимосвязей между данными и процессами, а так же процессов друг с другом через данные остается ненайденной. Это приводит к неестественной структуре системы, ее усложнению и потере понимаемости. При большой сложности структур данных кроме явных взаимосвязей между подсистемами появляется множество скрытых, что связано с отсутствием контроля целостности потоков данных. Что хорошо?
Зная недостатки структурной методологии, мы можем сформулировать требования к проекту, при которых структурная методология работает хорошо и переход к другой методологии не даст существенного выигрыша даже при значительном объеме кода. Требования к системе изначально сформулированы как описание процесса преобразования данных. Все потоки данных в системе имеют простую структуру.
К таким системам относятся почти все расчетные проекты (вычислительные эксперименты), системы упаковки/распаковки и кодирования произвольных данных, низкоуровневые коммуникационные протоколы. ОО методология. ОО Методология - методология, основанная на объектно-ориентированном подходе. Цель создания - устранение недостатков структурной методологии. Система описывается как совокупность взаимодействующих объектов, принадлежащих некоторым классам, классы образуют иерархию наследования.
(Г. Буч, ОО анализ и проектирование) Основные определения Объект - уникальная сущность, обладающая, поведением и состоянием и сохраняющая правильное наблюдаемое состояние на всем протяжении своей жизни. Уникальная сущность - отличимая от любой другой сущности. Поведение - способ (протокол, стандарт) взаимодействия с другими объектами. Поведение обычно описывается в терминах сообщений или методов. Могут быть и другие способы.
Интерфейс - наблюдаемое (внешнее) поведение, описание поведения объекта с точки зрения внешних (не являющихся агрегатами) объектов. Реализация - внутреннее поведение, код на языке программирования реализующий данное поведение. Состояние - тип и значение внутренних данных объекта. Состояние может быть избыточным. Например, внутренним типом данных для неориентированного графа может быть ориентированный граф. Наблюдаемое состояние - класс состояний различимый для внешних объектов через поведение.
Наблюдаемое состояние по определению всегда правильное. Условие правильности - дополнительное ограничение на правильность внутреннего состояния, обеспечивающее правильность наблюдаемого состояния. Для примера с графом, условием правильности будет наличие обратных дуг. Тип данных - класс или структура. Структура - набор других типов данных, не имеющий собственного поведения (поведение полностью определяется типами частей) и условия правильности (оно тождественно истинно).
Является специальным видом класса. Класс I (первичный класс) - тип объектов, имеющих общий тип внутренних данных, реализацию и условие правильности данных (инвариант, контракт). Класс II - тип объектов, имеющих общий интерфейс. Класс III - объект фабрика, предоставляющая способ создания (конструктор) объектов данного класса. Три базовых понятия ООП Инкапсуляция. Сокрытие данных. Объединение данных и методов работы с ними. Смысл понятия в том что, каждый элемент системы является объектом. Наследование.
Классы образуют иерархию. Суперкласс (предок) нескольких подклассов (потомков) имеет интерфейс, являющийся подмножеством пересечения интерфейсов подклассов. Условие правильности суперкласса является следствием условия для любого подкласса. По смыслу суперкласс - обобщение своих подклассов. Подкласс - уточнение суперкласса. Откуда берется наследование: 1. Обобщение - например, List и Choice являются подклассами Component. 2. Роли - один объект может исполнять несколько ролей.
Например, подкласс Component может быть подклассом DragSource, если ее можно тащить и подклассом DropTarget, если в нее можно кидать. Полиморфизм. Любой объект класса 1, реализующего интерфейс класса 2 может быть использован как объект класса 2. Объектная модель системы Основными частями ОМ являются иерархическая модель системы (whole-part hierarchy) и граф наследования (generalization hierarchy). Иерархическая модель разбиения системы на части
Каждый элемент иерархического разбиения на подсистемы является объектом. Таким образом, система представляется как дерево владения. Объекты связаны каналами обмена информацией. Граф наследования Направленный ациклический граф, определяющий порядок наследования классов. Может быть несвязным. Он является деревом для языков программирования не поддерживающих множественное наследование (Pascal with Objects). Использование наследования: объект верхнего уровня определяет классы своих частей.
В качестве части быть использован любой объект, реализующий нужный интерфейс (полиморфизм). Свойства связей задаются интерфейсами классов, связанных объектов. Связи в некоторых случаях также могут рассматриваться как объекты. Стандартные способы изображения Будем использовать специальную нотацию для поясняющих рисунков. Эта нотация согласована с нотацией диаграмм классов UML. Поясняющие рисунки не являются частью модели, поскольку не могут быть автоматически использованы для генерации кода или тестирования. (Диаграммы UML при некоторых ограничениях могут использоваться для генерации кода или тестирования и в этом случае являются частью модели). Наследование Здесь Класс2 является подклассом Класс1. Агрегация Здесь объект Класс2 является частью объекта Класс1.
Часть1 - элемент внутренней структуры данных Класс1, использующийся для хранения этой части. Атомарность взаимодействий Для обеспечения инкапсуляции обычно делаются следующие предположения о взаимодействии объектов (Ш, М). 1. Объекты взаимодействуют между собой посредством дискретных блоков информации (сообщений). 2. В каждый момент времени один объект может обрабатывать только одно сообщение. 3. Различные объекты могут обрабатывать сообщения одновременно (параллелизм).
4. Обработка сообщения требует времени. 5. Следующее сообщение может быть обработано только после завершения обработки предыдущего. 6. Один приемник обрабатывает все сообщения из одного источника в порядке отправления. 7. Порядок обработки сообщений из разных источников не определен. Модель объектов, удовлетворяющая этим требованиям, называется моделью независимых актеров (actors model). Она так же называется активной моделью (active model) поскольку объект сам выбирает момент обработки сообщения.
Во время обработки сообщения объект может иметь неправильное внутренне состояние. Но никакие другие объекты не могут наблюдать это состояние, поскольку другие сообщения не обрабатываются. Следовательно, это не нарушает инкапсуляцию. Классификация сообщений Сообщение может (не) изменять состояние объекта. Сообщение может (не) требовать ответа. Сообщение может быть ответом на другое сообщение. Наблюдаемость
Можно существенно ослабить требования модели независимых актеров для сообщений, не меняющих состояние объекта. Любое количество таких сообщений могут обрабатываться одновременно в любой момент времени, когда выполняется условие правильности внутреннего состояния объекта. Это свойство мы назовем свойством наблюдаемости. От сообщений к методам Метод, эквивалентен паре сообщений запрос-ответ. Запросом является вызов метода, ответом - возврат управления.
Типичная ошибка использования методов: предполагается, что после вызова метода другого объекта, состояние объекта не изменяется. Это неправда. Между запросом (вызов метода) и ответом (возврат управления) объект может обработать другие сообщения, меняющие его состояние. Например, другие объекты могут вызвать его методы. Типичные проблемы взаимодействия объектов 1. Взаимная блокировка (Deadlock). Объект 1 посылает запрос Объекту 2 и ждет ответа, прекращая обработку всех других сообщений.
Объект 2 в это время посылает запрос Объекту 1 и ждет ответа. Оба объекта навечно остаются в состоянии ожидания, заблокировав друг друга. Гонка (Thread Race). Объект 1 посылает сообщение Объекту 2, переводящее его в состояние А, после этого Объект 3 посылает сообщение Объекту 2, переводящее его в состояние В. Объект 1 продолжает думать, что Объект 2 в состоянии А. Почему этот сценарий называется гонкой? Если бы Объект 3 успел раньше Объекта 1, то все было бы хорошо.
3. Одновременная модификация (Concurrent Modification). Одна из разновидностей гонки. Состояние Объекта 2 изменилось, когда он не был к этому готов. Сценарии 2 и 3 выглядят довольно безобидно в случае гарантированного сохранения инкапсуляции объектов. Если инкапсуляция не сохраняется, то может произойти разрушение данных, ведущее к фатальной ошибке системы. Ограничение количества связей
Одной из основных целей при иерархическом разбиении системы является уменьшение количества связей, что ведет к уменьшению структурной сложности. Введем на дереве владения "феодальное" правило: вассал моего вассала не мой вассал. Разрешим только взаимодействия Владелец-Часть и Часть-Часть внутри одного владельца. Таким образом, количество типов связей в системе L=N+N*C*(C-1)/2=?(N), где N - количество элементов дерева владения, а С - характерное количество классов частей для одного элемента.
В таком подсчете есть небольшое лукавство. Если объекты делегируют часть связей своему владельцу, то сложность связей владельца растет. Но явная сложность всегда лучше скрытой сложности. Агрегация и атомарность взаимодействий Модель независимых актеров предполагает, что объект владелец и его части могут обрабатывать сообщения одновременно.
Это приводит к некоторому противоречию: объект часть может изменить состояние таким образом, что внутреннее состояние объекта владельца станет неправильным, если объект владелец одновременно попытается получить это состояние, то это приведет к нарушению инкапсуляции. Таким образом, требуется наложить ограничения на взаимодействие объектов участвующих в агрегировании. Простейшая модель Все взаимодействия должны быть изолированы в поддереве владельца.
То есть во время обработки сообщения, изменяющего состояние объекта части, объект владелец не может обрабатывать сообщений от внешних объектов. Следовательно, внешние объекты не могут наблюдать неправильное состояние объекта владельца. Это ограничение требует выполнения феодального правила, поскольку взаимодействие объекта части с внешним для владельца объектом индуцирует неявное взаимодействие объекта владельца с этим внешним объектом, что может нарушить инкапсуляцию объекта владельца.
Модель транзакций Простейшая модель может быть не оптимальна, с точки зрения эффективности использования параллелизма. Пусть, например, объект владелец имеет несколько частей. Пусть объект владелец обработал сообщение, инициировавшее изменение состояния одной из частей. Пока объект часть обрабатывает сообщение, объект владелец вынужден простаивать. Хотя он мог бы параллельно обрабатывать другое сообщение, если оно не затрагивает ту же часть.
Для улучшения ситуации может использоваться механизм транзакций. Транзакция - множество сообщений между множеством объектов, которое должно быть обработано без вмешательства других объектов. Сообщение объекта владельца инициирует транзакцию, включающую его части. Если по завершении транзакции объект владелец гарантированно имеет правильное внутреннее состояние, то одновременное исполнение нескольких транзакций не нарушает инкапсуляцию объекта владельца.
Следует учесть, что транзакция может закончиться неудачей. Пессимистичная модель транзакций Объект, участвующий в транзакции может обрабатывать только сообщения, принадлежащие транзакции. Другая транзакция включающая, тот же объект откладывается до завершения первой. Если объекты включаются в транзакцию последовательно, то возможна ситуация взаимной блокировки транзакций. Например, Транзакция1 владеет Объект1 и пытается завладеть Объект2, а Транзакция2 владеет Объект2 и пытается завладеть Объект1.
Для исключения взаимных блокировок может использоваться одновременный захват всех объектов транзакции или упорядочивание объектов, чтобы все транзакции захватывали их в одном порядке. В более сложных системах используется механизм обнаружения взаимной блокировки и механизм отката. Одна из заблокированных транзакций принудительно отменяется и все объекты в ней участвующие возвращаются в состояние до транзакции. Оптимистичная модель транзакций
Для всех включаемых в транзакцию объектов создается временная копия внутреннего состояния. Все транзакции исполняются одновременно, используя временные копии состояний. При окончании транзакции производится разрешение конфликтов между временной копией состояния и реальным состоянием объектов. Если разрешение конфликтов прошло успешно, то состояние участвующих объектов изменяется в соответствии с временной копией, в противном случае транзакция отменяется. Языки программирования
ОО методологию поддерживают такие языки как С++, Java, Pascal with Objects, Eiffel, Smalltalk, CLOS, C#. Ключевые свойства ОО языков: Классы. Защищенные (private) поля. Наследование. Виртуальные методы. Пояснение: Виртуальный метод - это метод, связанный с первичным классом объекта, а не с классом использования объекта. Таким образом, при приведении типа объекта к типу предка он сохраняет свои виртуальные методы. Чем хорош ООП? ОО описание системы акцентирует внимание на субъектах. Что приближает его к описанию на естественном языке. Любое действие (сказуемое) имеет явного или неявного субъекта (действующее лицо). Динамическая и статическая проекции системы явно связаны через понятие объекта. Присутствует контроль целостности потоков данных. Все потоки данных оперируют объектами. Сам ОО подход не уменьшает явную структурную сложность системы.
Он лишь дает возможность устранить часть неявных взаимосвязей между подсистемами, а другую часть сделать явной. ОО Анализ ОО Анализ - Построение объектной модели предметной области и требований к системе. Предметная область Предметная область - набор внешних сущностей и типов данных, не связанных с конкретной реализацией системы, с которыми ей необходимо работать для выполнения своих функций. Модель предметной области будет являться составной частью системы.
Например, система исчисления предикатов обязательно будет содержать класс Предикат. Исходные данные для анализа - Описание требований к системе на естественном языке. - Спецификации интерфейса других систем с аналогичными функциями. Результат анализа Модель системы на языке программирования описывающая ее взаимодействие с внешним миром. Виды деятельности при анализе 1. Идентификация Объектов и Классов 2. Идентификация Структур 3. Идентификация Доменов 4. Определение Атрибутов 5. Определение Сервисов
Все эти виды деятельности выполняются параллельно. Идентификация Объектов и Классов Зародышами объектов и классов являются существительные из описания предметной области. Для каждого из существительных следует задать несколько вопросов. 6. Имеет ли данная сущность состояние? Должна ли система помнить, что-либо о внутренних данных сущности. 7. Имеет ли сущность поведение? Взаимодействует ли она с другими сущностями. 8. Отличается ли ее поведение от поведения простого объединения ее частей?
9. Можно ли представить сущность глобально (в пределах вселенной) уникальной? Если на все эти вопросы ответ утвердительный, то сущность является объектом (см. определение). Если ответ утвердительный на все вопросы кроме 4, то это класс. Класс должен обладать уникальным именем внутри системы, точно характеризующим его назначение. Для каждого объекта следует найти уникальный первичный класс. То есть класс, принадлежность к которому полностью определяет поведение данного объекта.
Для каждого класса следует найти или придумать пример экземпляра этого класса. Следует объединять классы, если поведение, принадлежащих им объектов неразличимо. Если два класса имеют общее подмножество поведения, то следует рассмотреть отдельный класс, все объекты которого обладают этим поведением. Классы, содержащие ровно один объект, возможны, но подозрительны. Идентификация структур После предыдущего шага у нас может образоваться множество объектов и классов.
Данный шаг требуется для упорядочивания этого множества. Рассматриваются два вида структуры: Целое-Часть и Обобщение-Уточнение. Обобщение-Уточнение. Для каждой пары классов зададим вопрос, является ли Класс-1 подклассом Класса-2? Класс может быть подклассом нескольких других классов. Если ответ положительный, то эти классы связаны отношением наследования. Целое-Часть Для каждого Объекта зададим вопросы: 1. Является ли он частью другого объекта? 2. Имеет ли он другие объекты как компоненты?
Если ответ положительный, то объекты связаны отношением агрегации (включения). Это отношение индуцирует связь классов. Объект может иметь только одного владельца в каждый момент времени. 1. Владелец - обычно тот, кто управляет временем жизни объекта: запрашивает его создание и завершает его существование. 2. Обычно существует состояние агрегата, нарушающее условие правильности владельца. 3. Отсутствие агрегата обычно нарушает условие правильности владельца. Идентификация доменов
Домены - разбиение множества классов предметной области на подмножества. Основной целью такого разбиения является возможность проводить детализированный анализ и цикл разработки для каждого подмножества отдельно. Домены должны быть по возможности невелики и максимально независимы друг от друга. Рассмотрим объединение графа наследования и иерархии целое-часть для классов. Выделим в этом объединенном графе компоненты связности или, если нет такой возможности, подграфы наиболее на них похожие.
Хорошими кандидатами в домены являются отдельные деревья владения или отдельные деревья наследования. Определение атрибутов Атрибут I - элемент внутренней структуры данных класса. Атрибут II - непосредственно наблюдаемое свойство объекта. Существует сервис, возвращающий значение этого свойства. Атрибут должен обладать уникальным именем внутри Класса, точно характеризующим его назначение. Источники Атрибутов. 1. Агрегаты.
Каждому агрегату объекта в разбиении Целое-Часть соответствует атрибут, хранящий этот агрегат. 2. Партнеры. Для взаимодействия с другими объектами, объект должен иметь ссылки на них. Если нет способа динамически получить ссылку на партнера, то в классе должен быть атрибут для хранения этой ссылки. 3. Свойства. Некоторые свойства объекта в описании предметной области могут быть выражены прилагательными.
Следует выделить наборы взаимоисключающих свойств объекта и найти существительное, описывающее этот набор. Затем найдем класс для этого существительного. Каждому значению в наборе будет соответствовать объект этого класса. Он будет агрегатом исходного объекта. Связывание Атрибутов с Классами. Следует проталкивать атрибут вверх по графу наследования, пока он применим ко всем объектам данного класса. Определение сервисов
Сервисы - атомарные способы взаимодействия, предоставляемые объектом другим объектам. Главным свойством сервиса является сохранение условия правильности объекта, которому он принадлежит. Сервис должен обладать уникальным именем внутри Класса, точно характеризующим его назначение. В описании предметной области сервисам соответствуют глаголы. Нет однозначной взаимосвязи между сервисом и глаголом. С глаголом связан субъект (источник действия) и, возможно, множество объектов (предметов действия).
Возникает вопрос, сервисом какой сущности является действие, выражаемое данным глаголом. Как правило, одному действию соответствует несколько взаимодействующих сервисов различных объектов в соответствии с тем, инкапсуляцию какого объекта может нарушить это действие. Сервисы и Классы Сервисы являются частью поведения объекта и определяются Классом объекта. Следует проталкивать сервис вверх по графу наследования, пока он применим ко всем объектам класса.
Часто встречающиеся алгоритмически простые сервисы 1. Создание объекта. 2. Связывание объектов. Объединение объектов в динамическую структуру. 3. Чтение и установка атрибутов объекта. 4. Разрушение объекта. ОО Проектирование ОО Проектирование - процесс последовательного уточнения объектной модели системы до достижения уровня понимаемости, необходимого для ее реализации. Процесс ОО проектирования производится по тем же принципам, что и ОО Анализ. Исходные данные для проектирования
- ОО Модель предметной области, построенная на этапе анализа. - ОО Модель доменов/ классов, построенная на предыдущем этапе проектирования. - Набор внешних тестов системы/ домена/ класса реализующих случаи использования. - Стандартные проектные решения (шаблоны проектирования). Шаблоны проектирования - стандартные роли и ролевые модели взаимодействия для объектов системы. Например, упоминавшийся выше шаблон Фабрика. Фабрика - объект, предоставляющий сервисы создания новых объектов.
Примером фабрики является объект Класс, имеющий открытый конструктор. Результат проектирования - ОО Модель системы/ домена/ класса, полностью идентифицирующая объекты, классы, структуры, атрибуты и сервисы входящих в нее объектов. Аспекты системы На этапе анализа рассматривается платформонезависимый аспект системы. - Аспект Предметной области (Problem Domain)
На этапе проектирования система рассматривается в контексте программно-аппаратной платформы реализации и моделируются дополнительные аспекты, связанные с ней. - Аспект Пользовательского интерфейса (Human Interface) - Аспект Управления выполнением (Task Management) - Аспект Управления данными (Data Management) Для каждого из этих аспектов выполняются те же виды деятельности, что и при анализе. 1. Идентификация Объектов и Классов 2. Идентификация Структур 3. Идентификация Доменов 4. Определение Атрибутов 5. Определение Сервисов По возможности следует делегировать ответственность за определенный аспект отдельной группе объектов, не объединяя ответственность за разные аспекты в одном объекте, см. Модель-Наблюдатель. Аспект предметной области Классы предметной области рассматриваются на этапе анализа.
При изучении других аспектов системы они могут быть расширены атрибутами и сервисами. Аспект пользовательского интерфейса Пользовательский интерфейс - протокол визуального взаимодействия с пользователем. Реализуется через средства пользовательского интерфейса, предоставляемые программно-аппаратной платформой. Эти средства могут быть как сравнительно низкоуровневыми, так и высокоуровневыми абстракциями. Автоматическое тестирование ПИ чрезвычайно затруднено и обычно не проводится.
Это должно учитываться при проектировании системы. Для уменьшения объема нетестируемого кода взаимодействие с пользователем должно быть делегировано специальным объектам с, по возможности, простым поведением. Примеры низкоуровневых средств: Win32, Xlib. Прямой доступ к окнам и низкоуровневым компонентам. Библиотеки не содержат готовых к использованию классов для взаимодействия с пользователем. Инфраструктура ПИ должна содержаться в системе. Примеры средств среднего уровня: Gnome, Motif, AWT, Swing, MFC.
Библиотеки содержат набор готовых блоков, из которых можно построить визуальные компоненты системы. Система должна содержать небольшую прослойку, обеспечивающую взаимодействие стандартных визуальных элементов с данными. Примеры средств высокого уровня: Chrome. Пользовательский интерфейс автоматически строится по модели данных. Шаблон Модель-Наблюдатель Модель - как правило, объект аспекта предметной области инкапсулирует данные и методы их изменения.
Наблюдатель - обычно объект аспекта пользовательского интерфейса, инкапсулирует методы визуализации данных, и визуальные элементы управления. Аспект управления выполнением Включает в себя взаимодействие с операционной системой, обработку ошибок, обмен сообщениями, параллелизм и синхронизацию. Взаимодействие между объектами Может быть синхронным и асинхронным. Синхронное взаимодействие Метод не возвращает управление, пока не будет достигнут конечный результат выполнения, то есть неопределенно долго.
Пример: InputStream.read() не вернет управление пока не считает байт из потока. Асинхронное взаимодействие Метод является запросом на исполнение действия и возвращается немедленно. О результате действия сообщается другим способом. Опрос (Polling) После запроса на исполнение происходит периодический опрос объектов исполнителей о готовности результата. Чтение происходит по готовности результата.
Например, InputStream.available() возвращает количество байтов, готовых для считывания, затем InputStream.read() может считать готовые байты без блокировки. Опрос является наименее эффективным способом асинхронного взаимодействия, поскольку интервал опроса выбирается произвольно и не зависит от момента готовности результата. Если интервал слишком маленький то возрастают накладные расходы на опрос, если слишком большой, то задержка с момента возникновения события до реакции системы.
Метод опроса используется только если нет возможности использовать другие методы. Извещение (Notification) Объект заказчик получает извещение о готовности результата в одном из объектов исполнителей, затем определяет при помощи опроса, кто вызвал извещение и производит чтение результата из объекта исполнителя. Сообщение (Message) По готовности результата он заворачивается в сообщение, и сообщение помещается в очередь объекта заказчика.
Чтение результата происходит при обработке сообщения заказчиком без дополнительного взаимодействия с исполнителем. Эта техника является наиболее эффективной, но и наиболее сложной для реализации, поскольку требует реализации механизма асинхронного обмена сообщениями (Messaging) и очередей сообщений (Message Queue). Параллелизм Если система может выполнять одновременно несколько потоков команд, то имеет смысл использовать параллелизм. А если нет?
Оказывается, все равно есть случаи, требующие использования параллельных механизмов. Если система должна взаимодействовать с несколькими внешними объектами и некоторые из этих объектов предоставляют только синхронный способ взаимодействия, но при этом существует ограничение на время реакции системы на событие в одном из внешних объектов, то взаимодействие с объектами должно исполняться параллельно. Пример: система с пользовательским интерфейсом, использующая синхронные методы ввода-вывода.
При этом во время выполнения ввода-вывода пользовательский интерфейс должен реагировать на действия пользователя. Нити Нить (Поток управления, Легковесный процесс, Thread) - независимый поток команд, выполняющийся параллельно с остальными. Несколько нитей могут иметь общие данные. Выполнение кода системы на нескольких нитях, один из возможных и наиболее часто встречающийся вид реализации параллелизма в системе.
Чтобы исключить одновременный доступ к данным с нескольких нитей (и их порчу), нити предоставляют механизм синхронизации. Использование синхронизации увеличивает накладные расходы системы и может привести к взаимной блокировке нитей. По этому синхронизацию требуется использовать только там, где она необходима для сохранения целостности данных. Замечание: все механизмы синхронизации реализованы на базе считающего семафора (counting semaphore).
Как несколько нитей выполняются на одном физическом процессоре? За распределение времени между нитями отвечает планировщик (scheduler). Управление между нитями передается только в безопасных точках, которыми считаются вызовы методов синхронизации. Многие классы стандартных библиотек, особенно отвечающие за ввод-вывод, используют внутри себя синхронизацию.
Внимание: если вы не используете синхронизацию, стандартные классы ввода-вывода и явно не отдаете время другим нитям (yield, sleep), то параллельные потоки команд не будут выполняться. Эта ситуация называется голоданием (starvation). Сколько нитей обязательно необходимо системе? Одна нить для каждого синхронного взаимодействия плюс одна для асинхронных взаимодействий. Пример: система синхронно читает из 10 потоков ввода вывода и поддерживает асинхронный пользовательский интерфейс.
Системе необходимо минимум 11 нитей. Монитор (Monitor) Нити может получить монопольный доступ к монитору, любая другая нить желающая получить доступ к монитору останавливается, пока он не освободится. Монитор предоставляет возможность ожидания с извещением. Монитор по функциональности является объединением Мутекса (Mutex) и События (Event). - Monitor.enter() захватывает монитор, нить может вызывать enter любое количество раз при каждом последующем вызове счетчик захватов увеличивается на 1.
- Monitor.exit() уменьшает счетчик захватов на 1, освобождает монитор, когда счетчик равен 0. - Monitor.wait() освобождает монитор и ожидает извещения, может быть выполнен только когда нить владеет монитором. - Monitor.notify() извещает нить, ожидающую извещения, может быть выполнен только когда нить владеет монитором. Реализации модели независимых актеров Модель независимых актеров допускает, что несколько объектов могут обрабатывать сообщения одновременно. Объект-Нить
Объединение объекта и нити является простейшей реализацией активной модели. Каждый объект имеет очередь сообщений. Вызов открытого метода помещает запрос в очередь. Нить, связанная с объектом выполняет цикл обработки сообщений (event loop). Результат запроса помещается в очередь объекта заказчика. На практике выделение нити для каждого объекта является слишком расточительным, нити ценный системный ресурс, а накладные расходы обмена сообщениями между нитями могут превышать выигрыш от параллелизма.
Возможен смешанный подход, несколько объектов связано с одной нитью. Нить в цикле обрабатывает сообщения для всех связанных с ней объектов. Для взаимодействия часто используется шаблон Команда. Пассивная модель взаимодействия объектов Абстрактная посылка сообщения отображается в простой вызов метода, любые данные могут быть изменены в любой момент. Модель называется пассивной, потому что объект не может отложить выполнение метода (обработку сообщения) или отказаться от изменения данных. Допустим, что доступ к объектам может осуществляться только с одной нити. Все взаимодействия этих объектов таким образом происходят последовательно. Оказывается, что из-за отсутствия параллелизма эта модель эквивалентна активной модели.
Такая модель является базовой для всех современных ОО языков программирования. Для упрощения системы часто используется гибридный подход между объектом-нитью и пассивными объектами. Объект1 имеет цикл обработки сообщений и отвечает за связь с другими нитями. Остальные объекты могут использоваться только нитью, выполняющей, цикл обработки сообщений Объект1. Нити как транзакции Можно не делать жесткую привязку объектов к нитям, а рассматривать нити как одновременно выполняемые вложенные транзакции.
Пессимистическая модель транзакций С каждым объектом связывается монитор. Захват объекта транзакцией отображается в Monitor.enter(). Транзакция для данного объекта завершается, когда нить освободит его монитор. Неизменяемые объекты (Immutable objects) Если после создания состояние объекта не может быть изменено, то он может участвовать в любом количестве транзакций одновременно. Следовательно, нить не должна захватывать монитор этого объекта. Наблюдаемость
Для реализации механизма наблюдаемости используется механизм раздельной блокировки чтения и записи (Read/Write Lock). Когда транзакция собирается только читать состояние объекта, она захватывает его на чтение. Любое количество транзакций могут одновременно захватить объект на чтение, если он не захвачен на запись. Если объект захвачен на запись, то транзакция ожидает его освобождения. Если транзакция собирается изменять объект, она захватывает его на запись и чтение.
Только одна транзакция может захватить объект на запись и чтение одновременно, и только если объект свободен на чтение и запись. Если объект захвачен на чтение или запись, то транзакция откладывается до освобождения объекта. Усиление захвата (Upgrade Lock). Можно ли сначала захватив объект на чтение захватить его и на запись? Нельзя. Прежде чем захватить объект на запись, транзакция должна дождаться освобождения его на чтение.
Если две транзакции одновременно захотят усилить захват, то произойдет взаимная блокировка. Таким образом, перед захватом объекта на запись и чтение, транзакция должна сначала отпустить его на чтение. Кеширование (Caching) Можно ли сохранить свойство наблюдаемости во время исполнения транзакции, изменяющей состояние объекта? Да можно. Для этого пред началом транзакции надо сделать временную копию состояния объекта.
Все транзакции, не изменяющие состояние объекта, могут читать временную копию состояния объекта. Этот подход является простейшей реализацией оптимистичной модели транзакций. Поскольку в каждый момент времени выполняется только одна изменяющая состояние транзакция, нет проблемы с разрешением конфликтов. Для сохранения состояния объекта используется клонирование (clone) (шаблон Прототип (Prototype)) или выделение состояния объекта в отдельный класс (шаблон Состояние (State)).
Так же этот подход тесно связан с неизменяемыми объектами, сохраненное состояние является неизменяемым объектом. Аспект управления данными Включает ввод-вывод, взаимодействие с базами данных, взаимодействие частей системы по сети. Как правило, основной задачей является сопряжение объектной модели с необъектным внешним миром и оптимизация потока данных. Часто можно использовать простую эффективную технику сериализации. Сериализация - сохранение объекта и связанных с ним объектов в потоке ввода/вывода.
Десериализация - восстановление объекта и связанных с ним объектов из потока ввода/вывода. В современных системах программирования (например, Java, .NET) механизм сериализации является универсальным для любых объектов и реализован в стандартной библиотеке классов. Он позволяет сохранить объект в файл, поле базы данных, передать по сети и т.д. В некоторых случаях применение механизма сериализации неоправданно. Проблемы стандартных механизмов сериализации 1. Производительность.
Универсальные механизмы сериализации являются не слишком эффективными с точки зрения производительности. 2. Совместимость с существующим протоколом. Во многих случаях протокол сериализации жестко задан, либо его сложно изменить. Это может сделать невозможным использование сериализации при требовании передачи данных по известному внешнему протоколу. Например: сохранение объектов в виде таблиц реляционной базы данных. 3. Совместимость различных версий классов.
В течении разработки системы классы могут меняться. В зависимости от реализации сериализации, при чтении старой версии класса могут возникнуть проблемы. ОО Программирование Реализация поведения классов, описанных на этапе проектирования. Исходные данные для программирования - Модель класса, содержащая спецификации его предков, атрибутов и сервисов. - Набор внешних тестов для класса. Результат программирования Реализация класса на языке программирования, удовлетворяющая всем тестам. ОО Тестирование
Тесты также рассматриваются с ОО точки зрения. Внутренние тесты являются сервисами тестируемого объекта. Внешние тесты являются объектами-контейнерами, агрегирующими тестируемый объект. Феодальное правило радикально облегчает тестирование. Для полноценного тестирования объекта требуется поместить его в естественное окружение. При выполнении феодального правила окружение объекта состоит только из его владельца и агрегатов владельца. Исходные данные для тестирования
- Модель системы/ домена/ класса полученная на этапе анализа/ проектирования/ программирования. - Примеры случаев использования системы/ домена/ класса. - Локализованные ошибки предыдущего этапа тестирования. Результаты тестирования - Набор новых тестов, реализующих случаи использования. - Набор новых тестов, покрывающих ошибочные ситуации. - Диагностика вновь обнаруженных ошибок. Жизненный цикл тестов Тесты тесно связаны с текущей реализацией системы.
Она может не только расширяться, но и активно изменяться. Это может быть вызвано изменением внешних требований к системе или переработкой кода. Часть тестов при этом становится неактуальной. Неактуальные тесты перестают проходить, но причиной их падения не является ошибка в программе. В этом случае следует исправить сам тест. Тестирование пользовательского интерфейса Пользовательский интерфейс - наиболее сложный для тестирования аспект системы.
Его полностью автоматическое тестирование включает в себя создание виртуального пользователя, управляемого искусственным интеллектом. Это обычно намного перекрывает сложность самой системы. Поэтому для большинства систем автоматическое тестирование ПИ не проводится. Стратегия тестирования: 1. Для автоматического тестирования других аспектов системы пишутся тестовые объекты, подменяющие визуальные компоненты и эмулирующие взаимодействие пользователя с системой.
2. Отдельные визуальные компоненты тестируются вручную с использованием внешних тестов. 3. Проводится общее ручное тестирование ПИ. Тестирование производительности Одним из важных требований к системе является ее эффективность. Под эффективностью обычно понимается время выполнения характерного действия или количество обработанных запросов в единицу времени. Желательно определить формальные требования к эффективности на основе внешних тестов, моделирующих реальные случаи использования.
Это является необходимым требованием для оптимизации. Несмотря на то, что тесты эффективности легко автоматизируются, их обычно выполняют отдельно от остальных автоматических тестов. Поскольку они занимают длительное время и могут неоправданно замедлить регулярный прогон тестов. Для облегчения исследования производительности кода используется инструментальное средство Профайлер (Profiler).
Профайлер позволяет после выполнения кода, узнать какие методы наиболее часто вызывались, и какую часть общего времени система провела внутри каждого метода. Это позволяет использовать в качестве тестов производительности небольшой набор Простых тестов, содержащих характерные случаи использования системы. ОО Переработка кода Переработка кода - в основном процесс исправления ошибок допущенных на этапе анализа и проектирования. Главная сложность заключается в том, что такие ошибки обычно обнаруживаются, когда уже написана значительная часть реализации системы. Простой возврат на этап проектирования или анализа равноценен удалению этой части.
Переработка кода является эквивалентным преобразованием кода. Эквивалентность проверяется с помощью тестов. Исходные данные для переработки кода ОО Модель системы/ доменов/ классов. Набор тестов системы/ доменов/ классов. Результат переработки кода ОО Модель системы/ доменов/ классов, эквивалентная исходной. Набор тестов системы/ доменов/ классов исправленный в соответствии с новой моделью. Признаки необходимости переработки кода 1. Добавление новых сервисов нарушает инкапсуляцию объекта.
2. Дублирование кода. 3. Длинный метод. Тело метода не влезает на экран. 4. Большой класс. Класс содержит очень много методов или атрибутов. 5. Длинный список параметров. Список параметров метода занимает несколько строк. 6. Ленивый класс. Класс содержит всего несколько методов и атрибутов. 7. Посредник. Большинство методов класса является посредниками для вызова методов других объектов. 8. Отказ от унаследованного поведения.
Методы класса перекрыты таким образом, чтобы отменить результат вызова методов предка или не передают управление методам предка. Другие признаки см. в Refactoring. Основные способы переработки кода - Перераспределение методов и атрибутов между существующими классами. - Замена "наследование/агрегация" - Выделение/удаление классов и наследования - Выделение/удаление методов - Выделение/удаление атрибутов Другие способы см. в Refactoring. Оптимизация Оптимизация также является видом переработки кода.
Цель оптимизации - повышение эффективности системы. Оптимизация - сложный, трудоемкий процесс, отнимающий много времени разработчика. В соответствии с правилом 20/80, 20% кода выполняются 80% времени. Таким образом, только оптимизация этих 20% кода может существенно повлиять на эффективность. Для определения этой области кода, требуются тесты эффективности. Две основные причины неэффективности ОО кода: 1. Применение неэффективных структур данных и алгоритмов. 2. Инкапсуляция.
Сокрытие реализации во многих случаях приводит к длинным цепочкам вызовов и передачи параметров, а также не позволяет организовать объекты на разных уровнях иерархии в эффективную структуру данных. Таким образом, во многих случаях единственным способом, оптимизации является ослабление инкапсуляции, то есть порча ОО модели системы. Использование тестов эффективности позволяет локализовать оптимизацию в небольшой области кода и уменьшить ее отрицательное влияние на структуру ОО модели системы.
Приложения Базовые элементы ООП в Java См. JLS. Виртуальные методы: все, кроме объявленных с модификаторами private, static, final. Нити и Синхронизация в Java Реализация Read/Write Lock на Java См. JCP Литература [OOA] Coad P., Yourdon E., Object-Oriented Analysis, Second Edition. Yourdon Press, 1991 [OOD] Coad P., Yourdon E., Object-Oriented Design, Second Edition. Yourdon Press, 1991 [Refactoring] Фаулер М. Рефакторинг, улучшение существующего кода. - Пер. с англ. -СПб: Символ-Плюс, 2003. - 423 с.
[JLS] James Gosling, Bill Joy, and Guy Steele. Java Language specification, Second Edition. Addison-Wesley, 2000 [Patterns] Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides, Design Patterns: Elements of Reusable Object-Oriented Software, Addison-Wesley, 1995 [JCP] Doug Lea, Concurrent Programming in Java, Design and Principles. Addison-Wesley, 1996 [Bouch] Буч Г., Объектно-ориентированный анализ и проектирование, с примерами на С++, 2-е изд. - Пер. с англ. - М.: Издательство Бином, СПб:
Невский диалект, 1999 - 500 с. [States] Шлеер С., Меллор С., Объектно-ориентированный анализ: моделирование мира в состояниях. - Пер. с англ. - Киев: Диалектика, 1993. - 240 с. [Month] Брукс Ф., Мифический человеко-месяц или как создаются программные системы. - Пер. с англ. - СПб: Символ-Плюс, 1999. - 304 с. [XP] Бек К., Экстремальное программирование. - СПб: Питер, 2002 - 224 с.

Изменено: 08.09.2004