Модифицируемость программных систем

35
Модифицируемость программных систем ДЗЮБА ДМИТРИЙ ВЛАДИМИРОВИЧ, СТАРШИЙ ПРЕПОДАВАТЕЛЬ КАФ. 806 [email protected]

Transcript of Модифицируемость программных систем

Page 1: Модифицируемость программных систем

Модифицируемость  программных  системДЗЮБА  ДМИТРИЙ  ВЛАДИМИРОВИЧ,   СТАРШИЙ  ПРЕПОДАВАТЕЛЬ  КАФ.  806  

[email protected]

Page 2: Модифицируемость программных систем

2

Требования  к  модифицируемости

Page 3: Модифицируемость программных систем

Что  затрудняет  изменение  кода?

Класс  А

Класс  БИспользует  Класс  А

Класс  ВИспользует  Класс  А

Класс  ГИспользует  Класс  А

Класс  ДИспользуется  Классом  А

Класс  ЕИспользуется  Классом  А

Класс  ЁИспользуется  Классом  А

Page 4: Модифицируемость программных систем

4

Локализация  модификаций1. Поддержка  семантической  связанности.

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

2. Предвосхищение  ожидаемых  изменений.На  стадии  проектирования  задаются  вопросы,  какие  изменения  в  системе  возможны?  Цель  -­‐ что  бы  однотипные  изменения  приводили  к  доработкам  одних  и  тех  же  модулей.

3. Обобщение  модуля.  Использование  модифицируемых  интерфейсов  (расширяемые  протоколы,  интерпретируемый  формат  данных).  Модуль  разделяется  на  интерпретатор  внешних  запросов  и  сам  модуль.  Позволяет  модифицировать  модуль  меняя  интерпретатор  внешних  запросов  а  не  сам  модуль.  

4. Ограничение  модифицируемости.  Для  каждого  модуля  на  стадии  проектирования  определяются  возможности  модификации.  Что  дает  возможность  уменьшить  влияние  модификаций  (но  и  ухудшить  модифицируемость  продукта).

Page 5: Модифицируемость программных систем

Зависимости  между  модулями  [1/5]Синтаксические  -­‐ сигнатуры  данных  производимых  модулем  А,  должны  соответствовать  ожиданием  модуля  Б,  сигнатуры  вызываемых  методов  -­‐ аналогично.

Пример:◦ Модуль  A вызывает  метод  “int  doHelloWorld(string   name)”◦ Модуль  B реализует  метод  “int  doHelloWorld(string   name)”

5

Page 6: Модифицируемость программных систем

6

Зависимости  между  модулями  [2/5]Семантические  -­‐ смысл  данных  производимых  модулем  А,  совпадает  со  смыслом    ожидаемым  модулем  Б,  аналогично  с  методами.

Пример:◦ Модуль  A вызывает  метод  “int doHelloWorld(string name)”.  Где  имя  передается  в  

формате  «Имя Отчество Фамилия»◦ Модуль  B реализует  метод  “int doHelloWorld(string name)” Где  имя  ожидается  в  

формате  «Имя Отчество Фамилия»

Page 7: Модифицируемость программных систем

7

Зависимости  между  модулями  [3/5]Последовательность  -­‐ если  определена  последовательность  в  которой  передаются  данные,  то  она  должна  пониматься  одинакова  обеими  сторонами.  Так  же  если  второй  вызов  может  идти  вслед  за  первым  в  установленный  промежуток  времени.

Пример

1.  Передается  запрос  на  открытие  сессии.

2.  Передаются  данные

3.  Получаются  данные

4.  Передается  запрос  на  закрытие  сессии.

Page 8: Модифицируемость программных систем

8

Зависимости  между  модулями  [4/5]1. Идентификация  интерфейса.  Модуль  Б  должен  знать  корректную  идентификацию  (имя)  

интерфейса  А.

ПримерЕсли  модуль  B  реализует  интерфейс  IHelloWorld.  То  модуль  А  должен  знать  что  это  интерфейс  IHelloWorld.

2. Расположение  модуля  Что  бы  Б  запускался  правильно  он  должен  знать  откуда  будет  вызываться  модуль  А.

ПримерПри  вызове  .NET  Remoting необходимо  знать  URL хоста  сервиса.

Page 9: Модифицируемость программных систем

9

Зависимости  между  модулями  [5/5]1. Качество  данных.  Могут  быть  предположения  о  структуре  данных  (определенная  точность).

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

2. Существование  модуля.  Если  модуль  не  существует  то  другой  не  сможет  его  использовать.ПримерВ коде модуля А может быть явно прописана процедура создания экземпляра модуля B (скажем вызов конструктора). Если бы нужный интерфейс реализовывался бы другим модулем, то пришлось бы вызывать другой конструктор.

3. Управление  ресурсами.  Модуль  должен  работать  с  ресурсами  на  основании  предположений  вызывающего  модуля.  Например,  использовать  с  ним  общую  память.

Page 10: Модифицируемость программных систем

10

Тактики:    Уменьшение  связанности модулей1. Скрытие  внутреннего  поведения  модуля. Скрытие  внутренних  функций  в  модуле  с  

обеспечением  доступа  через  public  интерфейсы.

2. Уменьшение  путей  коммуникации. Уменьшение  числа  модулей  которые  разделяют  информацию  с  текущим  модулем.  Это  уменьшает  связи  между  модулями.  И  позволяет  уменьшить  эффект  каскадных  изменений.

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

Page 11: Модифицируемость программных систем

11

Тактики:  Применение  посредниковПрименение  модулей-­‐посредников  позволяет  оградить  один  модуль  от  модификаций  другого  (в  случае,  если  не  меняется  семантика  данных).  

Типы  посредников:◦ Изменение  данных. Создаются  словари  для  преобразования  данных  из  одного  формата  в  другой  формат.  

◦ Изменение  сервисов. Façade,  bridge,  mediator,   strategy,proxy  and  factory  позволяют  создать  и  работать  с  промежуточным   слоем.

◦ Изменение  названия  интерфейса.Паттерн  Broker позволяет  не  менять  вызывающий  модуль,  если  на  сервере  поменялось  название  интерфейса  путем  настроек  брокера.  

◦ Изменение  места  расположения  сервисов. Использование  Name-­‐серверов,  отвечающих  за  определение  места  положения  сервиса  по  имени.

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

◦ Существование  модуля. Factory  может  создавать  как  сам  модуль  так  и  заглушку.

Page 12: Модифицируемость программных систем

12

Тактики:  Отложенное  связывание1. Runtime  registration  использование  механизмов  plugin.

2. Configuration   files  конфигурирование  системы  при  старте.

3. Polymorphism   использование  наследования  для  переопределения  классов.

4. Component   replacement  подмена  компонент  (библиотек)  при  загрузки  системы.

5. Строгое  соблюдение  протокола  позволяет  связывать  в  runtime  независимые  процессы.

Page 13: Модифицируемость программных систем

Уровни  зрелости  модульной  структуры  ПО

1. Level  1:  Ad  Hoc  Ни  какой  специальной  модульной  структуры  нет.Плюсы:  просто  и  дешево.

2. Level  2:  Modules  Модули  отделены  от  друг  друга,  имеют  версию  и  свой  идентификатор.Плюсы:  отделение  модулей  от  кода,  упрощение  работы  с  зависимостями   в  коде  и  версионной  сборки.

3. Level  3:  Modularity  Модуль  может  манятся  автономно,  не  зависимо  от  других  модулей.  Модуль  описывается  своим  «контрактом».Плюсы:  Возможность  предсказать  сложность  внесения   изменений  в  систему.  

4. Level  4:  Loose  coupling  Разделение  интерфейса   и  реализации.  Плюсы:  Независимость   поставщика  и  получателя  интерфейса.  

5. Level  5:  Devolution  (ограниченная  автономия)Артефакты  модулей  храниться  в  репозиториях.  Модули  собираются  из  артефактов  в  зависимости   от  необходимых  сервисов.Плюсы: уменьшение   дублирования,  улучшенная  независимость   модулей.

6. Level  6:  Dynamism  Динамическое   управление  жизненным  циклом  модуля.  Поддержка  операций  добавления./              изменения   модуля.Плюсы: Динамическое   развитие  системы  и  управление.

13

Page 14: Модифицируемость программных систем

Объектно-­‐ориентированное  программированиеАбстракция  выделяет  существенные  характеристики  некоторого  объекта,  отличающие  его  от  всех  других  видов  объектов  и,  таким  образом,  четко  определяет  его  концептуальные  границы  с  точки  зрения  наблюдателя.

1. Абстракция  сущностиОбъект  представляет  собой  полезную  модель  некой  сущности  в  предметной  области  

2. Абстракция  поведенияОбъект  состоит  из  обобщенного  множества  операций  

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

4. Произвольная  абстракцияОбъект  включает  в  себя  набор  операций,  не  имеющих  друг  с  другом  ничего  общего  

Page 15: Модифицируемость программных систем

Абстракция  сущностиDomain  Driven  DesignПодход,  позволяющий  быстро  проектировать  стабильную  архитектуру  приложения,  основываясь  на  терминах  предметной  области.

Основные  способы  определения  модулей:◦ Layers◦ Entity◦ Value  Object◦ Services◦ Repository

15

Page 16: Модифицируемость программных систем

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

Например:  ◦ Слой  пользовательского  интерфейса;◦ Слой  бизнес-­‐логики;◦ Слой  информации  о  домене  сущностей;◦ Слой  доступа  к  данным;

Должно  быть  четкое  разделение  слоев.

Должны  быть  определены  правила  взаимодействия  слоев  (интерфейсы).

16

Page 17: Модифицируемость программных систем

Сущности  – объекты  реального  мираПредставляют  объекты  реального  мира;

Обладают  идентификацией  (например,  номер  паспорта  +  дата  и  место  выдачи  для  человека)

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

Обладают  поведением.

17

Page 18: Модифицируемость программных систем

Объект-­‐значениеНе  обладают  идентификацией  Могут  копироваться  и  передаваться  от  функции  к  функции  без  ограничений.

Не  обладают  жизненным  цикломСоздаются  когда  надо  и  удаляются,  когда  ни  кем  не  используются

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

Атрибуты  составляющие  Value  Object  должны  быть  концептуально  полными  (соответствовать  какой-­‐либо  абстракции)

18

Page 19: Модифицируемость программных систем

СервисыОсновные  свойства:◦ Описывают  процессы,  работающие  с  Entity и  Value  Object в  терминах  предметной  области◦ Не  имеют  состояния;◦ Не  заменяют  операции,  которые  принадлежат  Entity,  а  дополняет  их.  Обычно  сервис  является  важным  процессом  с  точки  зрения  домена;

Разделяют  сервисы,  принадлежащие  уровню  домена  и  сервисы,  принадлежащие  инфраструктуре  (например,  доступ  к  данным)Command  Query  Separation“every  method  should  either  be  a  command  that  performs  an  action,  or  a  query  that  returns  data  to  the  caller,  but  not  both.  In  other  words,  asking  a  question  should  not  change  the  answer”  Bertrand  Meyer

19

Page 20: Модифицируемость программных систем

Модули1. Modules

Состоят  из  элементов,  логически  связанных  друг  с  другом.

2. АгрегатыГруппа  связанных  объектов,  которые  могут  рассматриваться  как  одно  целое

3. ФабрикиИнкапсулирую  процесс  создания  сложных  объектов  или  группы  объектов

4. РепозиторииРеализуют  логику  получения  ссылки  на  объекты  предметной  области  по  разным  критериям

20

Page 21: Модифицируемость программных систем

21

Итого

Page 22: Модифицируемость программных систем

SOLIDкак  организовать   структуру  классов?• SRP  Принцип  единственной  обязанности.

На  каждый  объект  должна  быть  возложена  одна  единственная  обязанность.  

• OCP  Принцип  открытости/закрытости.Программные  сущности  должны  быть  открыты  для  расширения,  но  закрыты  для  изменения.  

• LSP  Принцип  подстановки  Барбары  Лисков.Объекты  в  программе  могут  быть  заменены  их  наследниками  без  изменения  свойств  программы.  

• ISP  Принцип  разделения  интерфейса.Много  специализированных  интерфейсов  лучше,  чем  один  универсальный.  

• DIP  Принцип  инверсии  зависимостей.Зависимости  внутри  системы  строятся  на  основе  абстракций.  Модули  верхнего  уровня  не  зависят  от  модулей  нижнего  уровня.  Абстракции  не  должны  зависеть  от  деталей.  Детали  должны  зависеть  от  абстракций.  

Page 23: Модифицируемость программных систем

SRP:  Single  Responsibility  Principle  (принцип  единственной  обязанности)Не  должно  существовать  более  одного  мотива  для  изменения  данного  класса

class  01  SRP  OFF

Customer

+   GetName():  const  char*

Order

Product

+   CalculateTax():  double+   GetName():  const  char*+   GetPrice():  double+   MakeReservation():  bool

class  01  SRP  ON

Customer

+   GetName():  const  char*

Order

Product

+   GetName():  const  char*+   GetPrice():  double

TaxCalculator

+   CalculateTax(Product):  double

ProductReservation

+   ReserveProduct(Product):  bool

*антипаттерн

Page 24: Модифицируемость программных систем

OCP:  Open/Closed  Principle  (принцип  открытия/закрытия)Объекты  проектирования  (классы,  функции,  модули  и  т.д.)  должны  быть  открыты  для  расширения,  но  закрыты  для  модификации.class  02  OCP  OFF

Customer

+   GetName():  const  char*

Order

Product

+   GetName():  const  char*+   GetPrice():  double

TaxCalculator

+   CalculateTax(Product):  double

ProductReservation

+   ReserveProduct(Product):  bool

Catalogue

+   FindByName(const  char*):  Product

class  02  OCP  ON

Customer

+   GetName():  const  char*

Order

Product

+   GetName():  const  char*+   GetPrice():  double

TaxCalculator

+   CalculateTax(Product):  double

ProductReservation

+   ReserveProduct(Product):  boolCatalogue

+   FindByName(IFindSpecification):  Product

«interface»IFindSpecification

+   isIt(Product):  bool

FindByNameSpecification

+   isIt(Product):  bool

FindByGroupSpecification

+   isIt(Product):  bool

*антипаттерн

Page 25: Модифицируемость программных систем

LSP:  Liskov Substitution  Principle   (принцип  замещения  Лисков)пример   SOLID_LSPФункции,  которые  используют  ссылки  на  базовые  классы,  должны  иметь  возможность  использовать  объекты  производных  классов,  не  зная  об  этом

class Rectangle

{

protected:

int width;

int height;

public:

Rectangle(int w, int h) : width(w), height(h) {};

virtual void SetWidth(int value) { width = value; }

virtual void SetHeight(int value) { height = value; }

virtual int GetSquare() { return width * height; }

};

class Square : public Rectangle

{

public:

Square(int w, int h) : Rectangle(w,w) {};

virtual void SetWidth(int value) { width = value; height = value; }

virtual void SetHeight(int value) { width = value; height = value; }

};

Page 26: Модифицируемость программных систем

LSP:  Нарушение  принципа  LSP  (class  diagram)антипаттернclass  03  LSP

Rectangle

#   height:  int#   width:  int

+   GetSquare():  int+   Rectangle(int,  int)+   SetHeight(int):  void+   SetWidth(int):  void

Square

+   SetHeight(int):  void+   SetWidth(int):  void+   Square(int,  int)

Page 27: Модифицируемость программных систем

ISP:  Interface  Segregation  Principle   (принцип  изоляции  интерфейса)пример   SOLID_ISP

Клиент  не  должен  вынужденно  зависеть  от  элементов  интерфейса,  которые  он  не  использует.

Другими  словами  этот  принцип  можно  сформулировать  так:  зависимость  между  классами  должна  быть  ограничена  как  можно  более  узким  интерфейсом.class IBusinessMenu{protected:

virtual const char* GetFirstItem() =0 ;virtual const char* GetSecondItem() =0;virtual const char* GetCompot() =0 ;

public:void PrintMenu(){if (GetFirstItem() != nullptr) std::cout << "Item:" << GetFirstItem() << std::endl;if (GetSecondItem() != nullptr) std::cout << "Item:" << GetSecondItem() << std::endl;if (GetCompot() != nullptr) std::cout << "Item:" << GetCompot() << std::endl;}

};

Page 28: Модифицируемость программных систем

ISP:  Class  Diagramантипаттерн

class  04  ISP

CoffeMenu

-­   bulka:  std::string-­   coffe:  std::string

+   CoffeMenu(std::string,  std::string)#   GetCompot():  char*#   GetFirstItem():  char*#   GetSecondItem():  char*

BusinessMenu

-­   compot:  std::string-­   first:  std::string-­   second:  std::string

+   BusinessMenu(std::string,  std::string,  std::string)#   GetCompot():  char*#   GetFirstItem():  char*#   GetSecondItem():  char*

IBusinessMenu

#   GetCompot():  char*#   GetFirstItem():  char*#   GetSecondItem():  char*+   PrintMenu():  void

Page 29: Модифицируемость программных систем

ISP:  Sequence  Diagramантипаттернsd  04  ISP

BusinessMenu CoffeMenu

main

PrintMenu()

PrintMenu()

Page 30: Модифицируемость программных систем

DIP:  Dependency   Inversion  Principle  (принцип  обращения   зависимости)пример SOLID_DIP

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

class IItem{public:virtual void print() = 0;};

class Menu{private:

std::vector<IItem*> items;public:

void add(IItem *i) { items.insert(items.end(),i); }

void menu() { for (auto i : items) i->print(); }

};Стратегия  Menu  применяется  к  интерфейсу  IItem.  Этим  мы  устранили  недостатки  предыдущего  варианта.

Page 31: Модифицируемость программных систем

DIP:  Class  Diagramclass  05  DIP

ItemBulka

+   print():  void

IItem

+   print():  void

ItemCoffe

+   print():  void

Menu

-­   items:  std::vector<IItem*>

+   add(IItem*):  void+   menu():  void

Page 32: Модифицируемость программных систем

DIP:  Sequence  Diagramsd  05  DIP

IItemMenu

main

ItemBulka

ItemCoffe

menu()

add(IItem*)

add(IItem*)

*print()

Page 33: Модифицируемость программных систем

Tell  Don’t  Askпример SOLID_TDA,  CQS

Один  из  основополагающих  принципов  ООП:  Необходимо  делегировать  объекту  действия,  вместо  того,  что  запрашивать  его  детали  реализации. Это  помогает  достичь  многократного  использование  класса  (поскольку  ни  кто  не  знает  его  деталей  реализации).

Command  Query  Separation  – принцип  разделение  методов,  которые  выполняют  какие-­‐либо  действия  (tell)  и  методов,  которые  осуществляют  запросы  данных  (ask).

Law  of  Demeter  – объект  может  вызывать  методы  только:

• Себя

• Своих  параметров

• Объектов,  созданных  внутри  метода

Page 34: Модифицируемость программных систем

Модифицируемость  vs  PerformanceРазделение  данных  на  домены  ведет  к  увеличению  распределенности  объектов  между  сервисами,  что  ухудшает  производительность.

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

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

34

Page 35: Модифицируемость программных систем

Спасибо!