Лекція 7. Проектування програмного забезпечення

 

Проектування системи є пошуком відповіді на питання як потрібно зробити те, що потрібно зробити.

Етапи проектування:

1. Проектування архітектури системи.

1.1. Ідентифікація архітектурних рішень і механізмів проектування;

1.2. Аналіз взаємодій між класами аналізу, виявлення проектних класів, підсистем і інтерфейсів;

1.3. Формування архітектурних рівнів;

1.4. Проектування структури потоків управління;

1.5. Проектування конфігурації системи.

2. Проектування елементів системи.

2.1. Уточнення реалізацій варіантів використання.

2.2. Проектування підсистем.

2.3. Проектування класів.

2.4. Проектування баз даних.

Проектування архітектури системи виконується архітектором.

У процесі проектування визначаються деталі реалізації архітектурних механізмів, позначених у процесі аналізу. Наприклад, уточнюється спосіб зберігання даних, реалізація дублювання для підвищення надійності системи і тому подібне Вони документуються у проекті (моделі) за допомогою кооперації із стереотипом <<mechanism>>, при цьому структурна частина механізму описується за допомогою діаграм класів, а поведінка - за допомогою діаграм взаємодії.

Проектні механізми є перехідним етапом від механізмів аналізу до механізмів реалізації. Механізм реалізації - рішення, яке має конкретного постачальника, проектний механізм - каркас, який максимально наближений до реалізації, має конкретне наповнення, чим відрізняється від механізму аналізу.

 

Як приклад розглянемо механізм Persistency - зберігання екземплярів стійких класів у БД. Нехай у проекті системи реєстрації у якості мови програмування використовується Java. Оскільки існуюча система каталога курсів функціонує на основі реляційної СУБД, механізмом проектування, який забезпечує доступ до цієї зовнішньої бази даних, буде RDBMS (Relational Database Management System), реалізувати який можна рішенням від Sun - JDBC (Java Database Connectivity). Класи-учасники:

· DBClass - відповідає за читання і запис даних екземплярів стійких (persistent) класів.

· DriverManager, Connection, Statement, ResultSet - відповідають за реалізацію запиту до БД (виконання оператора SQL) - пакет java.sql.

· PersistentClassList - список об'єктів, які є результатом запиту до БД -DBClass.read().

· Стереотип <<role>> використовується для елементів моделі, які є «заповнювачами» (placeholders), - реальних елементів, які створюються розробником системи.

 

 

Взаємодія екземплярів класів, у рамках механізму описується діаграмами взаємодії, наприклад:

 

 

З діаграми видно, що для створення нових даних (нового екземпляра стійкого класу) об'єкт PersistencyClient запрошує DBClass. DBClass створює новий екземпляр PersistentClass, запитує початкові значення його атрибутів (записані конструктором). Потім DBClass створює новий оператор SQL, використовуючи операцію createStatement() класу Connection. Цей запит повинен додати новий запис у таблицю. У результаті виконання цього запиту дані нового екземпляра стійкого класу поміщаються до БД.

Стійкість може бути забезпечена на основі об'єктної бази даних, при цьому використовується механізм проектування OODBMS (Object-oriented Database Management System) і механізми реалізації від різних постачальників, наприклад, ObjectStore.

Класи-учасники:

· SampleDBManager - менеджер бази даних, відповідає за читання і запис стійких об'єктів.

· Database - є БД ObjectStore (фізичний рівень).

· Session - сесія роботи клієнта з БД.

· Map - хеш-таблиця, контейнер, який зберігає пари <ключ, значення>, є сукупністю стійких об'єктів, з якими працює система.

· Transaction - транзакція, у рамках однієї сесії у кожний момент часу існує не більш однієї транзакції.

· ObjectStore - реалізує операції системного рівня (спільні для всіх БД ObjectStore).

 

На початку роботи системи створюється сесія, у рамках якої проводиться з'єднання з БД, запускається транзакція для ініціалізації: створюється хеш DBRoot, прописується в БД, після чого транзакція завершується.

Читання даних з БД відбувається за наступним сценарієм. Об'єкт класу-клієнта, який бажає отримати дані, викликає метод SampleDBManager::getPersistentClassData. Менеджер БД починає транзакцію, запрошує потрібний об'єкт у DBRoot за ключем, бере дані об'єкта, повернутого DBRoot, завершує транзакцію, повертає отримані дані клієнтові.

 

 

 

Ініціалізація роботи з БД у рамках механізму ObjectStore

 

Читання даних у рамках механізму ObjectStore

 

Зміна даних відбувається за таким же сценарієм, різниця лише в тому, що замість PersistentClass::getData викликається інший метод. При видаленні об'єкта стійкого класу потрібно «двічі» видалити дані: спочатку з хеш-кодування (оперативної пам'яті), потім з бази даних (зовнішньої пам'яті):

 

Видалення стійкого об'єкту у рамках механізму ObjectStore.

 

Наступним етапом є аналіз взаємодій між класами аналізу, виявлення проектних класів, підсистем і інтерфейсів. Першою дією архітектора перетворення класів аналізу в проектні класи.

 

 

По кожному класу аналізу приймається одне з двох рішень:

· клас аналізу відображається у проектний клас, якщо він простий або представляє єдину логічну абстракцію;

· складний клас аналізу може бути розбитий на декілька класів, перетворений у пакет або у підсистему.

Сукупності класів об'єднуються у пакети і підсистеми. При об'єднанні класів у пакети враховується, що:

Пакети - це одиниці управління конфігурацією, тому члени пакета повинні бути однаково стабільні. При збірці системи всі класи пакета або входять у збірку, або ні, отже, класи, які з великою вірогідністю піддаватимуться змінам, бажано відокремити від стабільних класів.

· Пакети - засіб розподілу ресурсів між командами розробників. Робота над пакетом або підсистемою може бути доручена окремій групі розробників і вестися більш-менш незалежно.

· Різні пакети можуть відповідати різним типам користувачів.

· Повторно використовуваний код, вбудований у систему, потрібно оформити як пакет.

Якщо інтерфейс користувача нестабільний, має сенс об'єднати всі класи, які його реалізовують, в окремий пакет. Якщо UI не піддаватиметься істотним змінам, можна об'єднати в окремі пакети класи, які взаємодіють при реалізації різних варіантів використання.

Після виділення пакетів встановлюються залежності між ними і видимість членів пакету. До закритих членів пакету доступ ззовні заборонений. Це дозволяє приховати внутрішній устрій пакета.

 

 

 

Декілька класів можуть бути об'єднані у підсистему якщо:

· класи мають функціональний зв'язок (беруть участь в реалізації варіанту використання і взаємодіють тільки один з одним);

· сукупність класів реалізує функціональність, яка може бути видалена з системи або замінена на альтернативну;

· класи сильно зв'язані;

· класи розміщені на одному вузлі обчислювальної мережі.

 

Приклади можливих підсистем: підсистема безпеки, захисту даних, архівації; підсистема інтерфейсу користувача або інтерфейсу із зовнішніми системами; комунікаційне ПЗ, доступ до баз даних.

При створенні підсистем у моделі виконуються наступні перетворення:

· об'єднувані класи поміщаються в спеціальний пакет з ім'ям підсистеми і стереотипом <<subsystem>>;

· специфікації операцій класів, які створюють підсистему, виносяться в інтерфейс підсистеми - клас із стереотипом <<interface>>;

· характер використання операцій інтерфейсу і порядок їх виконання документується за допомогою діаграм взаємодії, які разом з діаграмою класів підсистеми об'єднуються у кооперацію з ім'ям інтерфейсу і стереотипом <<interface realization>>;

· у підсистемі створюється клас-посередник із стереотипом <<subsystem proxy>>, який керує реалізацією операцій інтерфейсу.

 

 

Всі інтерфейси підсистем повинні бути повністю визначені у процесі проектування архітектури, оскільки вони служитимуть як точки синхронізації при паралельній розробці системи. Опис інтерфейсу включає:

· Ім'я інтерфейсу: коротке (одне-два слова), яке відображає його роль в системі.

· Опис інтерфейсу: повинно відображати його відповідальності (розмір - невеликий абзац).

· Опис операцій: ім'я, яке відображає результат операції, ключові алгоритми, значення, які повертаються, параметри з типами.

· Документування інтерфейсу: характер використання операцій і порядок їх виконання (показується за допомогою діаграм послідовності), тестові плани і сценарії і так далі. Вся ця інформація об'єднується у спеціальний пакет.

Як приклад (для системи реєстрації) приведемо підсистему BillingSystem, яка створена замість граничного класу BillingSystem. Взаємодія з нею здійснюється за допомогою об'єкта-посередника BillingSystem, який реалізовує інтерфейс iBillingSystem. На діаграмі показані зовнішні зв'язки підсистеми.

 

 

 

Наступним етапом є формування архітектурних рівнів. У процесі аналізу було ухвалено попереднє рішення про виділення архітектурних рівнів. У процесі проектування всі проектні елементи системи повинні бути розподілені по даних рівнях. З погляду моделі це означає розподіл проектних класів, пакетів і підсистем по пакетах із стереотипом «layer», які відповідають архітектурним рівням.

Приклад (система реєстрації на курси):

 

 

· виділені 2 архітектурних рівні (пакета із стереотипом <<layer>>);

· на рівень Application (Застосування) поміщений пакет Registration, куди включені граничні та управляючі класи;

· граничні класи BillingSystem і CourseCatalogSystem перетворені у підсистеми рівня бізнес-логіки Business Services;

· у шар Business Services, крім підсистем, включено ще два пакети: пакет External System Interfaces включає інтерфейси підсистем (класи із стереотипом <<interface>>), а пакет University Artifacts - всі класи-сутності.

Бібліотечні класи, які беруть участь у проектних механізмах, включаються в модель і впливають на формування рівнів. Зазвичай, вони поміщаються на рівень проміжного ПЗ (Middleware) або системний рівень (System software).

 

 

Наступний етап - проектування структури потоків управління. Воно виконується за наявності у системі паралельних процесів (паралелізму). Мета проектування - виявлення процесів, які існують у системі, характеру їх взаємодії, створення, знищення і відображення у середовище реалізації. Вимога паралелізму виникає у наступних випадках:

· потрібний розподіл обробки між різними процесорами або вузлами;

· система управляється потоком подій (event-driven system);

· обчислення у системі мають високу інтенсивність;

· у системі одночасно працює багато користувачів.

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

Процес - це ресурсоємний потік управління, який може виконуватися паралельно з іншими потоками. Він виконується у незалежному адресному просторі і у разі високої складності може розділятися на два або більше потоки.

Потік (нитка) - це полегшений потік управління, який може виконуватися паралельно з іншими потоками у рамках одного і того ж процесу у спільному адресному просторі.

Необхідність створення потоків у системі реєстрації курсів диктується наступними вимогами:

· якщо курс виявиться заповненим в той час, коли студент формує свій учбовий графік, який включає даний курс, то він повинен бути сповіщений про це (потрібний незалежний процес, який керує доступом до інформації конкретних курсів);

· існуюча база даних каталога курсів не забезпечує необхідну продуктивність (потрібний процес проміжної обробки - підкачки даних).

Реалізація процесів і потоків забезпечується засобами операційної системи.

Для моделювання структури потоків управління використовуються так звані активні класи - класи із стереотипами <<process>> і <<thread>>. Активний клас володіє власним процесом або потоком і може ініціювати управляючі дії. Зв'язки між процесами моделюються як залежності. Потоки можуть існувати тільки усередині процесів, тому зв'язки між процесами і потоками моделюються як композиції. Модель потоків управління поміщається у пакет Process View.

Активні класи, показані на діаграмі класів, яка описує структуру процесу реєстрації студента на курси, мають наступне призначення:

· StudentApplication - процес, який керує всіма функціями студента-користувача у системі. Для кожного студента, який починає реєструватися на курси, створюється один об'єкт даного класу.

· CourseRegistrationProcess - процес, який керує безпосередньо реєстрацією студента. Для кожного студента, який починає реєструватися на курси, також створюється один об'єкт даного класу.

· CourseCatalogSystemAccess - управляє доступом до системи каталога курсів. Один і той же об'єкт даного класу використовується всіма користувачами при доступі до каталога курсів.

· CourseCache і OfferingCache використовуються для асинхронного доступу до даних у БД з метою підвищення продуктивності системи. Вони є кешем для проміжного зберігання даних про курси, які добуваються з БД.

 

Створення потоків під час ініціалізації застосування моделюється за допомогою діаграм взаємодії. Об'єкти будь-якого проектного класу або підсистеми повинні існувати усередині принаймні одного процесу. Зв'язки між процесами і проектними класами моделюються на діаграмах класів. Нижче приведений приклад для системи реєстрації:

 

 

Зверніть увагу, що на наступній діаграмі залежності між процесами відповідають асоціаціям між класами, екземпляри яких містяться у процесах.

 

 

Наступний етап - проектування конфігурації. Якщо створювана система є розподіленою, то необхідно спроектувати її конфігурацію в обчислювальному середовищі, т. т., описати обчислювальні ресурси, комунікації між ними і використання ресурсів різними системними процесами.

Розподілена мережева конфігурація системи моделюється за допомогою діаграми розміщення. Основні елементи діаграми розміщення:

· вузол (node) - обчислювальний ресурс (процесор або інший пристрій: дискова пам'ять, контроллери різних пристроїв і так далі). Для вузла можна задати процеси, які виконуються на ньому.

· з'єднання (connection) - канал взаємодії вузлів (мережа).

Розподіл процесів, які складають структуру потоків управління, по вузлах мережі проводиться з урахуванням наступних чинників:

· використовувані зразки розподілу (триланкова архітектура клієнт-сервер, «товстий клієнт», «тонкий клієнт», «точка-точка» і т. д.);

· час відгуку;

· мінімізація мережевого трафіку;

· потужність вузла;

· надійність устаткування і комунікацій.

Приклад - діаграма розміщення для системи реєстрації на курси:

 

 

 

Наступний етап - уточнення варіантів використання. Уточнення опису варіантів використання полягає у модифікації їх діаграм взаємодії і діаграм класів з урахуванням класів, які знов з'явилися на кроці проектування, і підсистем, а також проектних механізмів. Вносяться зміни в описи потоків подій варіантів використання (за допомогою скриптів і приміток). Існує наступне правило представлення підсистем на діаграмах взаємодії: на діаграму не слід поміщати інтерфейси, оскільки вони - аналоги абстрактних класів і не можуть мати екземплярів (нагадаємо, що елементами діаграм взаємодії є не класи, а об'єкти), тому замість інтерфейсу підсистеми поміщають об'єкт класа-посередника (subsystem proxy, який грає роль фасада підсистеми).

Далі проводиться уніфікація класів і підсистем за наступними правилами:

· Імена елементів моделі повинні відображати їх функції. Слід уникати подібних імен і синонімів.

· Елементи моделі, які реалізовують схожу поведінку або, які представляють одне і те ж явище, повинні об'єднуватися.

· Класи, які представляють одне і те ж поняття або мають однакові атрибути, повинні об'єднуватися, навіть якщо їх поведінка різна.

· Для абстрактних елементів моделі повинне використовуватися спадкоємство, яке підвищує гнучкість моделі.

· При оновленні елемента моделі повинні оновлюватися відповідні реалізації варіантів використання.

Наступний етап - проектування підсистем, яке здійснюється розробниками. Воно включає наступні дії:

· Розподіл поведінки підсистеми по її елементах

о документування взаємодії елементів підсистеми у вигляді кооперацій («реалізацій інтерфейсу»);

о побудова однієї або більше діаграми взаємодії для кожної операції інтерфейсу подсистеми;

· Документування елементів підсистеми (у вигляді діаграм класів).

· Опис залежностей між підсистемами.

Приклад:

 

 

Діаграма кооперації, яка описує реалізацію інтерфейсної операції getCourseOfferings() у підсистемb CourseCatalogSystem.

Після проектування підсистем проводиться проектування класів, яке включає наступні дії:

· деталізація проектних класів;

· уточнення операцій і атрибутів;

· моделювання станів для класів;

· уточнення зв'язків між класами.

Кожен граничний клас перетвориться у деякий набір класів, залежно від свого призначення. Це може бути набір елементів інтерфейса користувача, який залежить від можливостей середовища розробки, або набір класів, який реалізовує системний або апаратний інтерфейс.

 

Класи-сутності з урахуванням міркувань продуктивності і захисту даних можуть розбиватися на ряд класів. Підставою для розбиття є наявність у класі атрибутів з різною частотою використання або видимістю. Такі атрибути, зазвичай, виділяються в окремі класи.

Що стосується управляючих класів, то класи, які реалізовують просту передачу інформації від граничних класів до сутності, можуть бути видалені. Зберігаються класи, які виконують істотну роботу по управлінню потоками подій (управління транзакціями, розподілена обробка і так далі).

Отримані у результаті уточнення класи підлягають безпосередній реалізації у коді системи.

Обов'язки класів, визначені у процесі аналізу і документовані у вигляді «операцій аналізу», перетворяться в операції, які будуть реалізовані у коді. При цьому:

· кожній операції присвоюється коротке ім'я, яке характеризує її результат;

· визначається повна сигнатура операції;

· створюється короткий опис операції, включаючи зміст всіх її параметрів;

· визначається видимість операції: public, private або protected;

· визначається область дії операції: операція об'єкта або операція класу;

· моделюється реалізація операції - алгоритм у вигляді блок-схеми (діаграми діяльності);

· на діаграмах класів простежуються маршрути доступу до даних, які обробляються при виклику операції, якщо потрібні дані іншого класу - з цим класом повинен бути зв'язок.

Якщо в системі присутні об'єкти з складною поведінкою, то будують діаграми станів. Побудова діаграм станів може стати причиною наступної дії на опис класів:

· події можуть відображатися в операції класу;

· особливості конкретних станів можуть вплинути на деталі виконання операцій;

· опис станів і переходів може допомогти при визначенні атрибутів класу.

Уточнення атрибутів класів полягає у наступному:

· задається його тип атрибуту і значення за умовчанням (необов'язково);

· задається видимість атрибутів: public, private або protected;

· при потребі визначаються похідні (обчислювані) атрибути.

Уточнення зв'язків класів полягає у наступному:

I. Деякі асоціації перетворяться у залежності, так якщо об'єкт є локальною змінною методу іншого об'єкта, якщо він - параметр або результат операції, то асоціація повинна бути замінена залежністю:

 

 

II. Деякі агрегації перетворяться у композиції. У об'єктній моделі є 4 види зв'язків «частина - ціле», перші два відносяться до композиції, інші - до агрегації:

a) неподільно володіє (залежність по існуванню, транзитивність, асиметричність, стаціонарність);

b) володіє (залежність по існуванню, транзитивність, асиметричність);

c) включає (залежність по існуванню, транзитивність);

d) учасник (немає обмежень).

III. Встановлюються напрями зв'язків. Наприклад:

 

 

IV. Класи-асоціації, допустимі тільки у моделях аналізу, перетворяться, оскільки жодна мова програмування їх не підтримує (аналогічно поступають з N-арнимі асоціаціями):

 

 

V. Асоціації потужністю «1 до N» уточнюються за допомогою класів-контейнерів (set - неврегульована множина, list або ordered - впорядкована множина, bag - мультимножина і sequence - впорядкована мультимножина):

 

 

VI. Для необов'язкових зв'язків (потужністю 0..1 або 0..n на будь-якому з полюсів) додаються операції перевірки наявності/відсутності зв'язку:

 

 

 

VII.Додаються кваліфікатори. Кваліфікатор - атрибут або набір атрибутів асоціації, значення яких дозволяє вибрати для конкретного об'єкту кваліфікованого класу один або безліч цільових об'єктів на протилежному полюсі асоціації.

Кваліфікатори не потрібно включати в атрибути цільового класу!

Зв'язки узагальнення можуть перетворюватися у ситуаціях з так званою метаморфозою підтипів, коли об'єкт суперкласу може міняти свій підтип.

 

 

 

 

У даному прикладі метаморфоза дозволяє легше перевести студента з однієї форми навчання на іншу. У попередній моделі необхідно знищити один об'єкт і наново породити об'єкт, але вже іншого підкласу. Після метаморфози досить зробити це з класифікацією студента.

Узагальнення треба проаналізувати, чи не є вони перерахуваннями. Не слід використовувати узагальнення для вказівки значень атрибутів перелічуваних типів.

 

 

Правильно моделювати перерахування так:

 

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

 

Література до лекції 7

 

1. Вендров А. М. Проектирование программного обеспечения экономических информационных систем. 2-е изд. – М.: Финансы и статистика, 2005. – Глава 4.

2. Рамбо Дж., Блаха М. UML 2.0. Объектно-ориентированное моделирование и разработка. 2-е изд.: Пер. с англ. – СПб.: Питер, 2007. – Глава 14.

3. Якобсон А., Буч Г., Рамбо Дж. Унифицированный процесс разработки программного обеспечения.: Пер. с англ. – СПб.: Питер, 2002. – Глава 9.

4. Коналлен Дж. Разработка Web-приложений с использованием UML.: Пер. с англ. – М.: Вильямс, 2001. – Глава 10.