Slide 1

Slide 1 text

Как разработать надежное решение Владимир Мельник
 Харьков, 2016

Slide 2

Slide 2 text

Винегрет Владимир Мельник
 Харьков, 2016

Slide 3

Slide 3 text

Надежность - это свойство системы продолжительное время сохранять способность выполнять возложенные на нее функции.

Slide 4

Slide 4 text

Эксплуатация подразумевает под собой не только работу приложения в production- окружении, но и работу с кодом приложения и решениями предоставляемыми третей стороной.

Slide 5

Slide 5 text

Надежное программное решение - это решение, которое: • работает без сбоев • легко адаптируется к изменениям внешнего мира • легко адаптируемо к изменениям внешнего мира

Slide 6

Slide 6 text

Доставка нефти Требование: Отсутствие потерь или минимальные потери при повриждении корпуса.
 
 Решение:
 - двойной корпус,
 - секционирование контейнера с нефтью

Slide 7

Slide 7 text

Работа без сбоев

Slide 8

Slide 8 text

• 24/7/356 доступность сервисов • устойчивость к высоким нагрузкам • обработка ошибок • целостность данных и их устойчивость к повреждениям • SOA и микро-сервисная архитектуры

Slide 9

Slide 9 text

• 24/7/356 доступность сервисов • устойчивость к высоким нагрузкам • обработка исключительных ситуаций • целостность данных и их устойчивость к повреждениям • SOA и микро-сервисная архитектуры

Slide 10

Slide 10 text

Адаптация как саморегуляция

Slide 11

Slide 11 text

• эластичная архитектура • cloud, fog, etc. • репликация • балансирование нагрузки • мета-программирование • само-обучающиеся системы

Slide 12

Slide 12 text

• эластичная архитектура • cloud, fog, etc. • микро-сервисная архитектура • реплики • балансирование нагрузки • мета-программирование • само-обучающиеся системы

Slide 13

Slide 13 text

Адаптируемость из вне

Slide 14

Slide 14 text

• Легко изменяемый код или код, которые не требует больших изменений. • Гарантия отсутствия дефектов и обнаружение регрессии • Независимость от решений предоставляемых третьей стороной

Slide 15

Slide 15 text

Текущая функциональность продукта занимает только второе место в списке приоритетов. На первом месте стоит функциональность вашего продукта завтра.

Slide 16

Slide 16 text

Легко изменяемый код

Slide 17

Slide 17 text

В тезисах • Гибкая архитектура - это архитектура позволяющая отстрачивать принятие важных и дорогостоящи решений. • Гибкая архитектура ~ надежная архитектура. • Гибкие методологии возможны только при гибкой архитектуре. • Гибкая архитектура - архитектура без жестких зависимостей.

Slide 18

Slide 18 text

Общие принципы • Low-coupling • High-cohesion • SOLID

Slide 19

Slide 19 text

SOLID • Принцип единственной ответственности. Принцип согласно которому функциональность объекта должна быть сильно ограниченной. • Принцип закрытости к изменению и открытости к расширению. Кратко: больше, но не иначе. • Принцип подстановки Барбары Лисков - согласно ему, когда B < A, экземпляры класса B должны быть способны заменить экземпляры класса A, то есть сущности типа B не ломают унаследованный интерфейс. Частный случай O/C принципа. • Принцип разделения интерфейсов - согласно этому принципу множество простых интерфейсов лучше, чем один сложный. Частный случай SR принципа. • Принцип инверсии зависимостей, согласно которому вышележащие слои не должны зависеть от лежащих ниже.

Slide 20

Slide 20 text

Новый Завет

Slide 21

Slide 21 text

SLOC

Slide 22

Slide 22 text

Система как логика над собственными компонентами • Целое - больше суммы его частей. - Аристотель. • Система - это её компоненты и логика над ними. - me. • Компоненты ничего не знают друг о друге, как шестерни в часах не знают ничего о других шестернях. • Система организует компоненты и описывает взаимодействие между ними. • Система играет роль композиции и абстракции. Компоненты системы - детали, система - черный ящик.

Slide 23

Slide 23 text

Ассоциации здорового человека

Slide 24

Slide 24 text

Неправильные ассоциации - одна из самых дорогих ошибок в разработке ПО, которая не позволяет в адекватные сроки поставлять запрашиваемую функциональность. Кроме того, при рефакторинге ассоциаций, весь код, что их использует идет в корзину. Ошибки в модели предметной области и архитектуре приводят к бесполезной работе и регрессии.

Slide 25

Slide 25 text

Правила ассоциирования сущностей • Сущности независимы. Это означает, что сущности напрямую не ссылаются друг на друга и ничего о существовании друг друга не знают. • Для связывания сущностей используются ассоциации. • Ассоциации помещаются в агрегаты, которые являются системами над сущностями, а сущности - их компонентами.

Slide 26

Slide 26 text

Danger! Все примеры подготовлены на основе Rails, что не позволяет добиться максимальной независимости компонентов.

Slide 27

Slide 27 text

class Customer < ActiveRecord::Base
 end
 
 class Product < ActiveRecord::Base
 end
 
 class Order < ActiveRecord::Base
 belongs_to :customer
 has_many :items, class_name: “OrderItem”
 end
 
 class OrderItem < ActiveRecord::Base
 belongs_to :order
 belongs_to :product
 end

Slide 28

Slide 28 text

• Экземпляры Product - безусловно сущности. • OrderItem является ассоциацией. Судя по наличию order_id и product_id - между Order и Product. • Чем является Order?

Slide 29

Slide 29 text

• Order не заществует самостоятельно. Без customer_id он лишен смысла, как и без OrderItem’ов. • По этой причине Order не является сущностью, но является купированной ассоциацией между Customer и Product. • Необходимости в Order нет. Добавлением товаров в корзину Customer лишь устанавливает ассоциацию между собой и товарами. Он их желает, а они желаем им.

Slide 30

Slide 30 text

class Customer < ActiveRecord::Base
 end class Product < ActiveRecord::Base
 end class OrderedProduct < ActiveRecord::Base
 belongs_to :customer
 belongs_to :product
 end

Slide 31

Slide 31 text

Оплата и доставка class Payment < ActiveRecord::Base
 belongs_to :customer
 has_many :ordered_products
 end
 
 class Delivery < ActiveRecord::Base
 has_many :ordered_products
 end
 
 class OrderedProduct < ActiveRecord::Base
 belongs_to :order
 belongs_to :product
 belongs_to :payment
 belongs_to :delivery
 end

Slide 32

Slide 32 text

Что здесь не так? • Отношение пользователя к товару не имеет ничего общего с оплатой и доставкой. • При использовании реляционных баз данных payment_id и delivery_id у OrderedProduct будут помечены пустыми (NULL).

Slide 33

Slide 33 text

• Оплата - это факт. • Доставка - это процесс стартующий после оплаты.

Slide 34

Slide 34 text

class PaidOrderedProduct < ActiveRecord::Base
 belongs_to :ordered_product
 belongs_to :payment
 end
 
 class Payment < ActiveRecord::Base
 has_many :paid_ordered_products
 end
 
 class Delivery < ActiveRecord::Base
 belongs_to :paid_ordered_product
 end

Slide 35

Slide 35 text

Доставка - это процесс состоящий из фактов. Факт в случае с доставкой - это передача товара одного участника процесса доставки другому. Физически товар может не перемещаться.
 
 Пускай доставка состоит из:
 • Packaging • Shipment • Transport • Unloading • Commitment

Slide 36

Slide 36 text

No content

Slide 37

Slide 37 text

No content

Slide 38

Slide 38 text

Отображение процессов на факты и результаты Process Result Fact Packaging PackagedOrderedProduct Ordered product is packaged Shipping ShippedOrderedProduct Ordered product is shipped Transporting TransportedOrderedProduct Ordered product is transported Unloading UnloadedOrderedProduct Ordered product is unloaded Committing CommittedOrderedProduct Ordered Product is committed

Slide 39

Slide 39 text

Нас не интересует процесс. Нас интересует результат. Наличие результата является фактом, например, если есть CommittedOrderedProduct, то был осуществлен Commiting, то есть имеет место факт - Commitment.

Slide 40

Slide 40 text

Процесс просто агрегирует факты, но у нас нет необходимости в такой агрегации. Delivery - избыточная сущность. Сам процесс описывается ассоциациями.
 class Delivery < ActiveRecord::Base
 belongs_to :paid_ordered_product
 end

Slide 41

Slide 41 text

class PackagedOrderedProduct < ActiveRecord::Base
 belongs_to :paid_ordered_product
 end class ShippedOrderedProduct < ActiveRecord::Base
 belongs_to :packaged_ordered_product
 end class TransportedOrderedProduct < ActiveRecord::Base
 belongs_to :shipped_ordered_product
 end class UnloadedOrderedProduct < ActiveRecord::Base
 belongs_to :transported_ordered_product
 end class CommittedOrderedProduct < ActiveRecord::Base
 belongs_to :unloaded_ordered_product
 end

Slide 42

Slide 42 text

Как узнать текущее состояние доставки? # packaged?
 !!op.try :packaged_ordered_product
 
 # shipped?
 !!try(…).try :shipped_ordered_product
 
 # transported?
 !!try(…).try(…).try :transported_ordered_product
 
 # unloaded?
 !!try(…).try(…).try(…).try :unloaded_ordered_product
 
 # commited?
 !!try(…).try(…).try(…).try(…).try :committed_…

Slide 43

Slide 43 text

Шутка

Slide 44

Slide 44 text

Foreign Key как Natural Primary Key • packaged_ordered_products.payed_order_id - является одновременно PRIMARY KEY и FOREIGN KEY ссылающимся на PaidOrderedProduct и OrderedProduct. • shipped_ordered_products.payed_order_id - является одновременно PRIMARY KEY и FOREIGN KEY ссылающимся на PackagedOrderedProduct, PaidOrderedProduct и OrderedProduct. • transported_ordered_products.payed_order_id - является одновременно PRIMARY KEY и FOREIGN KEY ссылающимся на ShippedOrderedProduct, PackagedOrderedProduct, PaidOrderedProduct и OrderedProduct. • outloaded_ordered_products.payed_order_id - является одновременно PRIMARY KEY и FOREIGN KEY ссылающимся на TransportedOrderedProduct, ShippedOrderedProduct, PackagedOrderedProduct, PaidOrderedProduct и OrderedProduct. • commited_ordered_product.payed_order_id - является одновременно PRIMARY KEY и FOREIGN KEY ссылающимся на OutloadedOrderedProduct, TransportedOrderedProduct, ShippedOrderedProduct, PackagedOrderedProducts, PaidOrderedProduct и OrderedProduct.

Slide 45

Slide 45 text

# committed?
 CommittedOrderedProduct.exists? (ordered_product_id: ordered_product.id)

Slide 46

Slide 46 text

Гарантии отсутствия дефектов и обнаружение регрессии

Slide 47

Slide 47 text

Все просто: их нет, но количество дефектов можно существенно минимизировать.

Slide 48

Slide 48 text

4 предназначения тестов: • Разработка более удобного API. • Разработка low-coupling кода. • Предоставление информации о регрессии после будущих изменений. • Документирование кода.

Slide 49

Slide 49 text

Тесты позволяют посмотреть на разработку кода глазами его пользователя.

Slide 50

Slide 50 text

BDD не только подразумевает инкрементальный рефакторинг, но и обеспечивают возможность оного.

Slide 51

Slide 51 text

Тесты позволяют обнаружить архитектурные недостатки на ранних стадиях и устранить их.

Slide 52

Slide 52 text

Тесты не гарантируют отсутствия дефектов. Они косвенным образом уменьшают их и позволяют проверить, что покрытые тестами use case’ы продолжают работать после внесенных изменений.

Slide 53

Slide 53 text

Тесты служат самой надежной и актуальной (если их запускают) документацией.

Slide 54

Slide 54 text

Bonus: BDBF - Behaviour- Driven Bug Fixing • При помощи тестов описываем правильное поведение системы. Тесты падают. • Экспериментируем с решением проблемы (пишем много грязного кода). Тесты становятся зелеными. • Рефакторим код, который исправляет поведение системы. Тесты остаются зелеными.

Slide 55

Slide 55 text

RSpec.describe Something, type: :some_type do
 describe “class” do
 subject { described_class }
 
 describe “.new” do
 context “when good args” do
 it “returns something” do
 …
 end
 end
 
 context “when bad args” do
 it “raises ArgumentError” do
 …
 end
 end
 end
 end
 
 describe “instance” do
 subject { described_class.new … }
 …
 end
 end

Slide 56

Slide 56 text

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

Slide 57

Slide 57 text

Спасибо за внимание

Slide 58

Slide 58 text

Вопросы?