Software architecture and design

Download Report

Transcript Software architecture and design

1.
2.
3.
4.
5.
6.
•
•
•
•
•
•
•
•
7.
Основни принципи на моделирането
Разделяне на отговорностите
Принцип на ограниченото знание
Не се повтаряй (DRY)
Минимизиране на предварителния дизайн
Дизайн практики
Слоеве на приложението
Компоненти, модули и функции
Съображения
Модели на софтуерните процеси
Етапи
Водопад
Agile модели
Често срещани проблеми
Обектно ориентиран дизайн
2
“ Walking on water and developing software
from a specification are easy if both are frozen. “
Edward V. Berard
„Ходенето по вода и разработката на софтуер
по спецификация са прости ако и двете са
замръзнали.“
•
Основните принципи ще ви помогнат да:
• Създадете архитектура, базирана на доказали се
принципи
• Минимизирате цената и изискванията за
поддръжка
• Оптимизирате времето за разработка
• Подобрите използваемостта и разширяемостта
на системата
•
Разделяне на отговорностите (Separation of
concerns)
• Разделяйте приложенията на отделни части
с възможно най-малко припокриване на
функционалности
• За постигането на висока кохезия (high
cohesion) и ниско ниво на свързаност (low
coupling) е много важно минимизирането
на броя точки на взаимодействие
• Разделянето на функционалностите на
грешно място може да доведе до високо
ниво на свързаност и висока сложност
между отделните части, дори когато
нямаме значителни припокривания вътре, в
самите части
•
Разделяне на отговорностите (Separation of concerns)
• Целта на софтуерния архитект е да минимизира
сложността, като раздели модела на различни зони на
отговорност
• Например, потребителския интерфейс (UI), бизнес
логиката и достъпа до данните представляват различни
зони на отговорност
• Във всяка зона, компонентите, които моделирате, трябва
да се фокусират вътре в зоната и да не смесват код от
различни зони на отговорност
• Например, компоненти работещи с потребителския
интерфейс не трябва директно да достъпват данните, а да
използват или бизнес компоненти или компоненти за
достъп до данните
•
Принцип на ограниченото знание (Principle of Least
Knowledge)
•
Компонент или обект не трябва да знае за
вътрешните детайли (вътрешно поведение,
структури от данни, комуникация с други
компоненти) на друг компонент или обект
•
Не се повтаряй (DRY)
•
•
При моделирането на системата, конкретна
функционалност трябва да бъде имплементирана
само в един компонент
Функционалността не трябва да се повтаря в никой
друг компонент
•
Минимизиране на предварителния дизайн
(Minimize upfront design)
•
•
•
•
Моделирайте само каквото е необходимо
В някои случаи, когато цената на
разработката или на пропуските в дизайна е
много висока, може да се наложи да
моделирате нещо предварително.
В останалите случаи, особено, когато
следвате Agile процесите е по-добре да
избягвате предварителното моделиране
Ако изискванията към приложението ви са
неясни или има възможност дизайна ви да
еволюира във времето избягвайте да
прилагате големи усилия предварително.
Този принцип е известен още като YAGNI
("You ain’t gonna need it").
•
•
•
•
•
•
Запазете дизайн шаблоните консистентни в рамките на
слоя
Не повтаряйте функционалност в рамките на
приложението
Предпочитайте композицията пред наследяването
Формулирайте стил на програмиране и конвенция за
именуване
Поддържайте качеството на системата, като използвате
автоматизирани QA техники по време на разработката
Съобразявайте се с експлоатацията на приложението
•
Запазете дизайн шаблоните консистентни в рамките на
слоя
•
В рамките на един логически слой е добре да се запази
консистентността на дизайна за определена операция
•
•
Например, ако решите да използвате шаблона Table Data
Gateway за достъп до данните, не би трябвало да
използвате и друг шаблон, като Repository например,
който използва съвсем различна парадигма за достъп до
данните
Въпреки това, може да ви се наложи да използвате
различни шаблони за задачи в слой, към който има
много различни изисквания, като например
приложение, съдържащо бизнес транзакции и справки
върху данните
•
Не повтаряйте функционалност в рамките на
приложението
•
•
•
Само един компонент би трябвало да предоставя
определена функционалност – тази функционалност не
трябва да се дублира в никой друг компонент
Това дава на компонентите ви висока степен на кохезия
и прави лесно оптимизирането им, ако някое
изискване или функционалност се променят
Дублирането на функционалности в приложението
може да доведе до по-трудна имплементация на
промените, по-неясен код и да създаде потенциална
неконсистентност
•
Предпочитайте композицията пред наследяването
•
•
•
•
Където е възможно използвайте композиция вместо
наследяване, когато преизползвате функционалност
Наследяването засилва зависимостите между родителя
и наследника и намалява възможността за
преизползване на наследника
Чрез този метод ще намалите и йерархиите, които
могат да станат доста сложни за проследяване
Композицията позволява по-лесна промяна, когато се
налага
•
Формулирайте стил на програмиране и конвенция
за именуване
•
•
•
•
Проверете дали компанията има установени
правила за стил на кода и именуване
Ако не, то трябва да установите такива
По този начин получавате консистентен модел,
който е лесен за четене от всички членове на
екипа
По-лесна поддръжка
•
Поддържайте качеството на системата, като
използвате автоматизирани QA техники по време на
разработката
•
•
•
Използвайте юнит тестове
Дефинирайте ясни метрики за поведение и
производителност на компонентите и
подсистемите
Използвайте автоматизирани инструменти за
осигуряване на качеството по време на билд
процеса
•
Съобразявайте се с експлоатацията на приложението
•
•
•
Определете какви измерения и експлоатационни
данни са необходими на инфраструктурата, за да се
осигури ефективно разгръщане и експлоатация на
приложението
Проектирането на вашите компоненти и подсистеми с
ясното разбиране за техните индивидуални
експлоатационни изисквания, чувствително ще улесни
процеса на разгръщане (deployment) и експлоатация
Използвайте автоматизирани QA инструменти по
време на разработката, за да сте сигурни в
коректността на експлоатационните данни
•
•
•
•
•
Разделете зоните на отговорност
Определете точно начина, по който слоевете
комуникират помежду си
Използвайте абстракция за да постигнете слаба
свързаност между слоевете
Не смесвайте различни типове компоненти в един
логически слой
Пазете консистентността на данните в рамките на
един слой или компонент
•
Разделете зоните на отговорност
•
Разделете приложението на отделни функционалности,
които се припокриват възможно най-малко
•
•
•
•
•
Една функционалност може да бъде променена или
оптимизирана отделно от останалите
Ако една функционалност откаже, това няма да доведе до
срив в останалите
Функционалностите могат да се използват независимо
една от друга
Това прави приложението по лесно за разбиране и
моделиране
Позволява управлението на сложни системи
•
Определете точно начина, по който слоевете
комуникират помежду си
•
Вземете конкретни решения за зависимостите
между различните слоеве и потока на данни в тях
•
Използвайте абстракция за да постигнете слаба
свързаност между слоевете
•
•
Това може да бъде постигнато чрез използването на
интерфейсни компоненти, като Фасада, с добре
познати входове и изходи, които превеждат заявките
във формат, разбираем за компонентите от съответния
слой
В допълнение може да се използват интерфейси или
абстрактни класове, които да бъдат имплементирани
от интерфейсните компоненти
•
Не смесвайте различни типове компоненти в един
логически слой
•
•
Започнете с идентифицирането на различните
зони на отговорност и след това групирайте
компонентите свързани с всяка от зоните в
логически слоеве
Например, слоя за потребителски интерфейс не
трябва да съдържа компоненти имплементиращи
бизнес процеси, а компоненти обработващи
потребителския вход и заявки
•
Пазете консистентността на данните в рамките на
един слой или компонент
•
•
Смесването на различни формати данни прави
приложението по трудно за имплементация,
разширение и поддръжка
Всеки път, когато се налага да конвертирате данни
от един формат в друг, трябва да имплементирате
конвертиращ метод и получавате допълнителна
обработка
•
•
•
•
•
Компонент или обект не трябва да зависи от
вътрешни детайли на други компоненти или обекти
Не претоварвайте функционалността на
компонентите
Определете начина на комуникация на отделните
компоненти
Дръжте общия код (crosscutting code) колкото се
може по-далеч от бизнес логиката на приложението
Дефинирайте ясен договор за компонентите
•
Компонент или обект не трябва да зависи от
вътрешни детайли на други компоненти или обекти
•
•
Всеки компонент или обект трябва да вика метод
на друг компонент или обект и този метод да
обработи заявката и в случай на необходимост да
се обърне към друг компонент или обект
По този начин приложението става по-адаптивно и
по-лесно за поддръжка
•
Не претоварвайте функционалността на компонентите
•
•
•
•
Например, компонент обработващ заявки от
потребителския интерфейс не би трябвало да съдържа
код за достъп до данните или да се опитва да предлага
допълнителна функционалност
Претоварените компоненти често смесват функциите
осигуряващи бизнес функционалността с общи
функционалности, като воденето на дневници и
обработката на изключения
В резултат на претоварването получаваме модел, който
предразполага към грешки и е сложен за поддръжка
Прилагането на принципите за разделение на
отговорностите и на единичната отговорност ви помага
да избегнете тези проблеми
•
Определете начина на комуникация на отделните
компоненти
•
•
•
Това предполага познаване на деплоймънт
стратегията, която вашето приложение трябва да
поддържа
Трябва да определите дали всички компоненти ще
функционират в рамките на един процес
Трябва да определите дали е необходима
комуникация между различни физически среди и
процеси, например чрез имплементирането на
интерфейс базиран на съобщения
•
Дръжте общия код (crosscutting code) колкото се може
по-далеч от бизнес логиката на приложението
•
•
•
•
Общ код (Crosscutting code) е код отнасящ се до
сигурността, комуникациите или управлението на
експлоатацията, като водене на дневници, обработка
на изключения и др.
Смесването на този код с бизнес логиката може да
доведе до модел, който е труден за разширяване и
поддръжка
При промяна на общия код се налага промяна и на
смесения с него код на бизнес логиката
По добре използвайте framework който да ви помогне с
общия код
•
Дефинирайте ясен договор за компонентите
•
•
•
Компонентите, модулите и функциите трябва да
дефинират договор или спецификация на интерфейс,
който ясно описва употребата и поведението им
Договорът трябва да описва начина, по който други
компоненти могат да използват вътрешната
функционалност на дадения компонент, модул или
функция
Поведението на тези функционалности в смисъл на
предусловия, постусловия, странични ефекти,
изключения, производителност и други фактори
•
Тук са описани някои основни решения, които
трябва да вземете когато започвате и в процеса на
развитие на вашата архитектура
• Определете типа на приложението
• Определете деплоймънт стратегията
• Определете подходящите технологии
• Определете атрибутите на качеството
• Определете общите отговорности (Crosscutting
Concerns)
•
Определете типа на приложението
•
•
Основна част от процеса на моделиране на приложението
Изборът ви се определя от специфичните изисквания и ограниченията
на инфраструктурата
Много приложения трябва да поддържат различни видове клиенти
Примери:
•
•
•
•
•
•
•
•
•
Приложения проектирани за мобилни устройства
Rich client приложения проектирани за персонални компютри
Rich Internet приложения проектирани за достъп през Интернет, които
поддържат разширен потребителски интерфейс и мултимедия
Сервизни приложения проектирани да осъществяват комуникацията между
слабо свързани компоненти
Уеб приложения проектирани да се изпълняват основно върху сървъра при
хипотеза на постоянна свързаност
Hosted и cloud-based приложения и услуги
Други типове (Office приложения, SharePoint приложения, …)
•
Определете деплоймънт стратегията
•
Вашето приложение може да бъде разгърнато в
различни среди, всяка от които със специфични
ограничения, като:
•
•
•
•
•
Физическо разделяне на компонентите на различни
сървъри
Ограничения на мрежовите протоколи
Защитна стена и конфигурация на маршрутизаторите
Трябва да намерите точния баланс между изискванията
на приложението и деплоймънт стратегията
поддържана от хардуера
Тези фактори ще се отразят на архитектурния дизайн
•
Определете подходящите технологии
•
Когато избирате технологии за приложението си,
основните фактори, които трябва да вземете под
внимание, са типа на приложението и
предпочитанието ви за деплоймънт топология и
архитектурен стил.
Избора ви на технологии се влияе и от
•
•
•
•
•
Политиката на компанията
Ограниченията на инфраструктурата
Уменията на екипите
Трябва да сравните възможностите на избраните
технологии и изискванията към приложението
•
Определете атрибутите на качеството
•
•
•
•
•
Атрибутите на качеството, като сигурност, производителност и
използваемост могат да бъдат използвани да ви насочат към
критичните задачи, които вашият модел трябва да реши
В зависимост от изискванията може да се наложи да вземете
предвид всеки или някои от тези атрибути
Например, всеки модел трябва да взема предвид сигурността и
производителността, но не всеки се интересува от оперативната
съвместимост и мащабируемостта
Уточнете изискванията и деплоймънт стратегията, за да
определите кои атрибути на качеството са важни за вашия
модел
Помнете, че атрибутите на качеството могат да са в
противоречие. Например, сигурността често изисква компромис
с производителността и исползваемостта
•
Определете атрибутите на качеството 2
•
•
•
•
•
Създавайки модела отговарящ на определени атрибути
на качеството, имайте предвид:
Атрибути на качеството са системни атрибути, които са
отделни от функционалността на системата
От техническа гледна точка, взимането в предвид на
атрибутите на качеството отличава добрата система от
лошата
Има два вида атрибути на качеството: едни, които се
мерят по време на изпълнение на приложението и
други, които могат да бъдат измерени само чрез
наблюдение
Анализирайте компромисите между различните
атрибути
•
Определете общите отговорности (Crosscutting Concerns)
•
•
•
•
•
•
•
Общите отговорности представляват ключови области от вашия
модел, които не са свързани с определен слой на приложението
Например, трябва да имплементирате централизирани или
общи решения за следните задачи:
Механизъм за водене на дневници позволяващ записване в
един общ дневник (log) или отделни дневници
Механизъм за автентификация и авторизация, който предоставя
идентичност (identity) на различните слоеве, за да позволи
делегирането на права за ресурси
Механизъм за управление на изключенията (exceptions), който
работи във всеки един слой и между слоевете при
разпространението на изключенията в рамките на системата
Механизъм за комуникация между отделните слоеве
Механизъм за кеширане на данни позволяващ кеширане в
презентационния слой, бизнес слоя и слоя за достъп до данните
•
Етапи
•
Комуникация (Communication)
•
•
Планиране (Planning)
•
•
•
Включва извличане на изискванията, оценка на
възможностите, преговори и договори
Съставяне на примерен график
Изготвяне на план за управление на проекта
Обикновено архитектите не участват в тези два етапа,
освен ако, до някаква степен, не играят роля на
ръководител проект
•
Етапи
•
Моделиране (Modeling)
•
•
•
•
•
Анализ на изискванията
Трябва да бъдат направени предположения за липсващите
изисквания. Те могат да бъдат уточнени на по-късен етап.
Модел на системата
Архитектурата ще продължи да се променя през следващите етапи
поради изменения в изискванията и промяна в насочеността на
проекта
Изграждане (Construction)
•
•
•
Имплементация
Тестване
Деплоймънт (Deployment)
•
•
•
Доставка
Поддръжка
Обратна връзка
•
•
Водопад
Най-познатия и стар модел е Водопад.
Според него проекта преминава от един
етап в друг строго последователно, т.е.
минавате на етап N+1, когато N е напълно
завършен и всичко с него е наред
•
Водопад
•
•
След като екипа завърши анализа на изискванията
започва моделирането на архитектурата. След това се
пристъпва към имплементацията. После започва
тестването и така докато системата не бъде предадена
Водопада е прост и добре подреден модел, но е
нереалистичен за нетривиални проекти. Защо? Защото
почти никога нямате всички изисквания
предварително.
•
Agile модели – Модел с повторения (The iterative model)
•
•
•
•
•
Agile модели - Модел с повторения (The iterative model)
Разработката с повторения (Iterative development) е цикличен
процес, който е бил разработен, като отговор на метода
Водопад и акцентира върху постепенното изграждане на
софтуера
След началния етап, проекта минава през серия от итерации,
която включва моделиране, писане на код и тестване
Всяка итерация създава непълна, но работеща версия на
системата
На всяка итерация екипа прави промяна в дизайна и добавя
нови функционалности до достигане на пълния набор от
функции по спецификация
•
Agile модели – Модел с повторения (The iterative model)
•
Agile модели – Модел Спирала (Spiral model)
•
Недостъпния архитект
•
•
•
•
•
Един от основните проблеми е свързан с разликата между
онези, които предпочитат да моделират и тези, които
предпочитат да пишат код
Софтуерния архитект трябва да е сигурен, че обсъждането на
предложения дизайн предхожда дейностите по разработката
Много често в различни проекти софтуерния архитект бива
информиран, че промяната в дизайна не може да бъде
направена, тъй като кода вече е написан
Проблемът с развитието на кода без участието на софтуерния
архитект или неговия екип е още по-чувствителен за
отдалечените екипи
Софтуерния архитект трябва да провежда регулярни технически
срещи с тези екипи, за да следят промените в модела и да
оценят до къде е стигнал кода
•
Парализа на анализа
•
•
•
Отделя се прекалено много време на анализ и
моделиране, а писането на код не започва на време
Ръководителите на екипа от разработчици прекалено
дълго обсъждат абстрактни концепции
Както софтуерния архитект е отговорен за предаването
на модела навреме на екипа от разработчици, така и
дизайнерите на този екип трябва да предоставят на
разработчиците своя модел навреме.
•
Проектиране за преизползване
•
•
Въпреки, че преизползването е хубаво нещо, то не
трябва да се превръща в самоцел.
Губенето на прекалено много време за проектиране за
преизползване и други дейности, които са дори понепродуктивни, може да намали чувствително времето
за разработка и тестване.
•
График
•
Докато екипа на софтуерния архитект е фокусиран
върху техническите проблеми, те не трябва да изпускат
от очи графика и да се опитат да спазват времевите
рамки за анализ и моделиране и да не нарушават
общия график на проекта.
Single Responsibility Principle
Opened Closed Principle
Liscov Substitution Principle
Interface Segregation Principle
Dependency Inversion Principle
„НИКОГА НЕ ТРЯБВА ДА
ИМА ПОВЕЧЕ ОТ ЕДНА
ПРИЧИНА КЛАСА ДА СЕ
ПРОМЕНЯ“
•
Принцип на единичната отговорност (Single Responsibility
Principle)
• Всеки компонент или модул е отговорен само за
една специфична функционалност или за група от
еднородни функционалности
• Ако имате компонент, който има повече от една
причина да бъде променен, той трябва да бъде
разделен на няколко компонента в зависимост от
тяхната отговорност
• Всяка отговорност е посока на промяна
• Кода става обвързан ако класовете имат повече от
една отговорност
“СОФТУЕРНИТЕ ЕДИНИЦИ
(КЛАСОВЕ, МОДУЛИ,
ФУНКЦИИ И ДР.) ТРЯБВА
ДА БЪДАТ ОТВОРЕНИ ЗА
РАЗШИРЕНИЕ НО
ЗАТВОРЕНИ ЗА
ПРОМЯНА.”
•
Принцип отворен затворен (Opened Closed Principle)
• Трябва да можете да разширите поведението на
класа без да го променяте
• “Open For Extension” :
• Това означава, че поведението на модула/класа може
да бъде разширено и ние можем да накараме модула
да се държи по нов начин, когато изискванията се
променят или класа трябва да се интегрира с друго
приложение.
• “Closed for Modification” :
• Изходния код на такъв модул е ненарушим. Никой няма
право да го променя.
“ПОДТИПОВЕТЕ ТРЯБВА
ДА МОГАТ ДА БЪДАТ
ЗАМЕНЕНИ С БАЗОВИЯ
ТИП“
•
Принцип на подмяната на Лисков (Liscov Substitution
Principle)
• Компоненти, които имат референции към базови
класове, трябва да могат да използват обекти,
наследници на тези класове, без да знаят за тях
• В теорията на Обектно Ориентирания Дизайн,
класическото наследяване се описва като „е“ (“is
a”) връзка
• Такава „е“ връзка е много важна, но може да
бъде подвеждаща и да доведе до лошо
наследяване.
“КЛИЕНТИТЕ НЕ ТРЯБВА
ДА БЪДАТ ЗАДЪЛЖАВАНИ
ДА ЗАВИСЯТ ОТ
ИНТЕРФЕЙСИ, КОИТО НЕ
ИЗПОЛЗВАТ”
•
Принцип на разделяне на интерфейсите (Interface
Segregation Principle)
• Интерфейси с много методи е по-трудно да бъдат
преизползвани.
• Такива „тлъсти интерфейси“, с излишни методи,
водят до непреднамерено обвързване (coupling) на
класове.
• Това, също така, добавя ненужна сложност и
намалява възможността за поддръжка и
устойчивостта на системата.
• Спазването на този принцип осигурява интерфейси,
всеки от които е със собствена област на отговорност
и поради това е преизползваем.
“МОДУЛИ ОТ ВИСОКО
НИВО НЕ ТРЯБВА ДА
ЗАВИСЯТ ОТ МОДУЛИ ОТ
НИСКО НИВО. И ДВЕТЕ
ТРЯБВА ДА ЗАВИСЯТ ОТ
АБСТРАКЦИИ.”
•
Принцип на инверсия на зависимостите (Dependency
Inversion Principle)
• Модули от високо ниво не трябва да зависят от модули от
ниско ниво. И двете трябва да зависят от абстракции.
Абстракциите не трябва да зависят от детайлите.
Детайлите трябва да зависят от абстракциите
• Базов клас в йерархията от наследявания не трябва
да знае за никой от наследниците си
• Не трябва да сме зависими от модули с детайлна
имплементация, а те трябва да са зависими от
абстракция
•
•
•
•
•
Основни принципи на моделирането
Разделяне на отговорностите
Принцип на ограниченото знание
Не се повтаряй (DRY)
Минимизиране на предварителния дизайн
•
•
•
•
Дизайн практики
Слоеве на приложението
Компоненти, модули и функции
Съображения
•
Модели на софтуерните процеси
•
•
•
•
•
Етапи
Водопад
Agile модели
Често срещани проблеми
Обектно ориентиран дизайн
6
0
IN 16 BULGARIAN TOWNS
Course Name, Topic Name