«Как разработать надежное решение».Владимир Мельник,...
TRANSCRIPT
![Page 1: «Как разработать надежное решение».Владимир Мельник, Ruby Developer, DataArt](https://reader033.vdocuments.mx/reader033/viewer/2022051502/58d11edd1a28ab2a738b5295/html5/thumbnails/1.jpg)
Как разработать надежное решениеВладимир Мельник
Харьков, 2016
![Page 2: «Как разработать надежное решение».Владимир Мельник, Ruby Developer, DataArt](https://reader033.vdocuments.mx/reader033/viewer/2022051502/58d11edd1a28ab2a738b5295/html5/thumbnails/2.jpg)
ВинегретВладимир Мельник
Харьков, 2016
![Page 3: «Как разработать надежное решение».Владимир Мельник, Ruby Developer, DataArt](https://reader033.vdocuments.mx/reader033/viewer/2022051502/58d11edd1a28ab2a738b5295/html5/thumbnails/3.jpg)
Надежность - это свойство системы продолжительное время сохранять способность выполнять возложенные на нее функции.
![Page 4: «Как разработать надежное решение».Владимир Мельник, Ruby Developer, DataArt](https://reader033.vdocuments.mx/reader033/viewer/2022051502/58d11edd1a28ab2a738b5295/html5/thumbnails/4.jpg)
Эксплуатация подразумевает под собой не только работу приложения в production-окружении, но и работу с
кодом приложения и решениями предоставляемыми
третей стороной.
![Page 5: «Как разработать надежное решение».Владимир Мельник, Ruby Developer, DataArt](https://reader033.vdocuments.mx/reader033/viewer/2022051502/58d11edd1a28ab2a738b5295/html5/thumbnails/5.jpg)
Надежное программное решение - это решение, которое:
• работает без сбоев
• легко адаптируется к изменениям внешнего мира
• легко адаптируемо к изменениям внешнего мира
![Page 6: «Как разработать надежное решение».Владимир Мельник, Ruby Developer, DataArt](https://reader033.vdocuments.mx/reader033/viewer/2022051502/58d11edd1a28ab2a738b5295/html5/thumbnails/6.jpg)
Доставка нефти
Требование: Отсутствие потерь или минимальные потери при повриждении корпуса.Решение:- двойной корпус,- секционирование контейнера с нефтью
![Page 7: «Как разработать надежное решение».Владимир Мельник, Ruby Developer, DataArt](https://reader033.vdocuments.mx/reader033/viewer/2022051502/58d11edd1a28ab2a738b5295/html5/thumbnails/7.jpg)
Работа без сбоев
![Page 8: «Как разработать надежное решение».Владимир Мельник, Ruby Developer, DataArt](https://reader033.vdocuments.mx/reader033/viewer/2022051502/58d11edd1a28ab2a738b5295/html5/thumbnails/8.jpg)
• 24/7/356 доступность сервисов
• устойчивость к высоким нагрузкам
• обработка ошибок
• целостность данных и их устойчивость к повреждениям
• SOA и микро-сервисная архитектуры
![Page 9: «Как разработать надежное решение».Владимир Мельник, Ruby Developer, DataArt](https://reader033.vdocuments.mx/reader033/viewer/2022051502/58d11edd1a28ab2a738b5295/html5/thumbnails/9.jpg)
• 24/7/356 доступность сервисов
• устойчивость к высоким нагрузкам
• обработка исключительных ситуаций
• целостность данных и их устойчивость к повреждениям
• SOA и микро-сервисная архитектуры
![Page 10: «Как разработать надежное решение».Владимир Мельник, Ruby Developer, DataArt](https://reader033.vdocuments.mx/reader033/viewer/2022051502/58d11edd1a28ab2a738b5295/html5/thumbnails/10.jpg)
Адаптация как саморегуляция
![Page 11: «Как разработать надежное решение».Владимир Мельник, Ruby Developer, DataArt](https://reader033.vdocuments.mx/reader033/viewer/2022051502/58d11edd1a28ab2a738b5295/html5/thumbnails/11.jpg)
• эластичная архитектура
• cloud, fog, etc.
• репликация
• балансирование нагрузки
• мета-программирование
• само-обучающиеся системы
![Page 12: «Как разработать надежное решение».Владимир Мельник, Ruby Developer, DataArt](https://reader033.vdocuments.mx/reader033/viewer/2022051502/58d11edd1a28ab2a738b5295/html5/thumbnails/12.jpg)
• эластичная архитектура
• cloud, fog, etc.
• микро-сервисная архитектура
• реплики
• балансирование нагрузки
• мета-программирование
• само-обучающиеся системы
![Page 13: «Как разработать надежное решение».Владимир Мельник, Ruby Developer, DataArt](https://reader033.vdocuments.mx/reader033/viewer/2022051502/58d11edd1a28ab2a738b5295/html5/thumbnails/13.jpg)
Адаптируемость из вне
![Page 14: «Как разработать надежное решение».Владимир Мельник, Ruby Developer, DataArt](https://reader033.vdocuments.mx/reader033/viewer/2022051502/58d11edd1a28ab2a738b5295/html5/thumbnails/14.jpg)
• Легко изменяемый код или код, которые не требует больших изменений.
• Гарантия отсутствия дефектов и обнаружение регрессии
• Легко и безболезненно изменяемый код
• Независимость от решений предоставляемых третьей стороной
![Page 15: «Как разработать надежное решение».Владимир Мельник, Ruby Developer, DataArt](https://reader033.vdocuments.mx/reader033/viewer/2022051502/58d11edd1a28ab2a738b5295/html5/thumbnails/15.jpg)
Текущая функциональность продукта занимает только второе место в списке приоритетов. На первом месте стоит функциональность вашего продукта
завтра.
![Page 16: «Как разработать надежное решение».Владимир Мельник, Ruby Developer, DataArt](https://reader033.vdocuments.mx/reader033/viewer/2022051502/58d11edd1a28ab2a738b5295/html5/thumbnails/16.jpg)
Легко изменяемый код
![Page 17: «Как разработать надежное решение».Владимир Мельник, Ruby Developer, DataArt](https://reader033.vdocuments.mx/reader033/viewer/2022051502/58d11edd1a28ab2a738b5295/html5/thumbnails/17.jpg)
В тезисах• Гибкая архитектура - это архитектура позволяющая отстрачивать принятие важных и дорогостоящи решений.
• Гибкая архитектура ~ надежная архитектура.
• Гибкие методологии возможны только при гибкой архитектуре.
• Гибкая архитектура - архитектура без жестких зависимостей.
![Page 18: «Как разработать надежное решение».Владимир Мельник, Ruby Developer, DataArt](https://reader033.vdocuments.mx/reader033/viewer/2022051502/58d11edd1a28ab2a738b5295/html5/thumbnails/18.jpg)
Общие принципы
• Low-coupling
• High-cohesion
• SOLID
![Page 19: «Как разработать надежное решение».Владимир Мельник, Ruby Developer, DataArt](https://reader033.vdocuments.mx/reader033/viewer/2022051502/58d11edd1a28ab2a738b5295/html5/thumbnails/19.jpg)
SOLID• Принцип единственной ответственности. Принцип согласно которому функциональность объекта должна быть сильно ограниченной.
• Принцип закрытости к изменению и открытости к расширению. Кратко: больше, но не иначе.
• Принцип подстановки Барбары Лисков - согласно ему, когда B < A, экземпляры класса B должны быть способны заменить экземпляры класса A, то есть сущности типа B не ломают унаследованный интерфейс. Частный случай O/C принципа.
• Принцип разделения интерфейсов - согласно этому принципу множество простых интерфейсов лучше, чем один сложный. Частный случай SR принципа.
• Принцип инверсии зависимостей, согласно которому вышележащие слои не должны зависеть от лежащих ниже.
![Page 20: «Как разработать надежное решение».Владимир Мельник, Ruby Developer, DataArt](https://reader033.vdocuments.mx/reader033/viewer/2022051502/58d11edd1a28ab2a738b5295/html5/thumbnails/20.jpg)
Новый Завет
![Page 21: «Как разработать надежное решение».Владимир Мельник, Ruby Developer, DataArt](https://reader033.vdocuments.mx/reader033/viewer/2022051502/58d11edd1a28ab2a738b5295/html5/thumbnails/21.jpg)
SLOC
![Page 22: «Как разработать надежное решение».Владимир Мельник, Ruby Developer, DataArt](https://reader033.vdocuments.mx/reader033/viewer/2022051502/58d11edd1a28ab2a738b5295/html5/thumbnails/22.jpg)
Система как логика над собственными компонентами• Целое - больше суммы его частей. - Аристотель.
• Система - это её компоненты и логика над ними. - me.
• Компоненты ничего не знают друг о друге, как шестерни в часах не знают ничего о других шестернях.
• Система организует компоненты и описывает взаимодействие между ними.
• Система играет роль композиции и абстракции. Компоненты системы - детали, система - черный ящик.
![Page 23: «Как разработать надежное решение».Владимир Мельник, Ruby Developer, DataArt](https://reader033.vdocuments.mx/reader033/viewer/2022051502/58d11edd1a28ab2a738b5295/html5/thumbnails/23.jpg)
Ассоциации здорового человека
![Page 24: «Как разработать надежное решение».Владимир Мельник, Ruby Developer, DataArt](https://reader033.vdocuments.mx/reader033/viewer/2022051502/58d11edd1a28ab2a738b5295/html5/thumbnails/24.jpg)
Неправильные ассоциации - одна из самых дорогих ошибок в разработке ПО, которая не позволяет в адекватные сроки поставлять запрашиваемую функциональность. Кроме того, при рефакторинге ассоциаций, весь код, что их использует идет в корзину. Ошибки в модели предметной области и архитектуре приводят к бесполезной работе и регрессии.
![Page 25: «Как разработать надежное решение».Владимир Мельник, Ruby Developer, DataArt](https://reader033.vdocuments.mx/reader033/viewer/2022051502/58d11edd1a28ab2a738b5295/html5/thumbnails/25.jpg)
Правила ассоциирования сущностей
• Сущности независимы. Это означает, что сущности напрямую не ссылаются друг на друга и ничего о существовании друг друга не знают.
• Для связывания сущностей используются ассоциации.
• Ассоциации помещаются в агрегаты, которые являются системами над сущностями, а сущности - их компонентами.
![Page 26: «Как разработать надежное решение».Владимир Мельник, Ruby Developer, DataArt](https://reader033.vdocuments.mx/reader033/viewer/2022051502/58d11edd1a28ab2a738b5295/html5/thumbnails/26.jpg)
Danger!
Все примеры подготовлены на основе Rails, что не позволяет добиться максимальной независимости компонентов.
![Page 27: «Как разработать надежное решение».Владимир Мельник, Ruby Developer, DataArt](https://reader033.vdocuments.mx/reader033/viewer/2022051502/58d11edd1a28ab2a738b5295/html5/thumbnails/27.jpg)
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
![Page 28: «Как разработать надежное решение».Владимир Мельник, Ruby Developer, DataArt](https://reader033.vdocuments.mx/reader033/viewer/2022051502/58d11edd1a28ab2a738b5295/html5/thumbnails/28.jpg)
• Экземпляры Product - безусловно сущности.
• OrderItem является ассоциацией. Судя по наличию order_id и product_id - между Order и Product.
• Чем является Order?
![Page 29: «Как разработать надежное решение».Владимир Мельник, Ruby Developer, DataArt](https://reader033.vdocuments.mx/reader033/viewer/2022051502/58d11edd1a28ab2a738b5295/html5/thumbnails/29.jpg)
• Order не заществует самостоятельно. Без customer_id он лишен смысла, как и без OrderItem’ов.
• По этой причине Order не является сущностью, но является купированной ассоциацией между Customer и Product.
• Необходимости в Order нет. Добавлением товаров в корзину Customer лишь устанавливает ассоциацию между собой и товарами. Он их желает, а они желаем им.
![Page 30: «Как разработать надежное решение».Владимир Мельник, Ruby Developer, DataArt](https://reader033.vdocuments.mx/reader033/viewer/2022051502/58d11edd1a28ab2a738b5295/html5/thumbnails/30.jpg)
class Customer < ActiveRecord::Base end
class Product < ActiveRecord::Base end
class OrderedProduct < ActiveRecord::Base belongs_to :customer belongs_to :product end
![Page 31: «Как разработать надежное решение».Владимир Мельник, Ruby Developer, DataArt](https://reader033.vdocuments.mx/reader033/viewer/2022051502/58d11edd1a28ab2a738b5295/html5/thumbnails/31.jpg)
Оплата и доставка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
![Page 32: «Как разработать надежное решение».Владимир Мельник, Ruby Developer, DataArt](https://reader033.vdocuments.mx/reader033/viewer/2022051502/58d11edd1a28ab2a738b5295/html5/thumbnails/32.jpg)
Что здесь не так?
• Отношение пользователя к товару не имеет ничего общего с оплатой и доставкой.
• При использовании реляционных баз данных payment_id и delivery_id у OrderedProduct будут помечены пустыми (NULL).
![Page 33: «Как разработать надежное решение».Владимир Мельник, Ruby Developer, DataArt](https://reader033.vdocuments.mx/reader033/viewer/2022051502/58d11edd1a28ab2a738b5295/html5/thumbnails/33.jpg)
• Оплата - это факт.
• Доставка - это процесс стартующий после оплаты.
![Page 34: «Как разработать надежное решение».Владимир Мельник, Ruby Developer, DataArt](https://reader033.vdocuments.mx/reader033/viewer/2022051502/58d11edd1a28ab2a738b5295/html5/thumbnails/34.jpg)
class PayedOrderedProduct < ActiveRecord::Base belongs_to :ordered_product belongs_to :payment end class Payment < ActiveRecord::Base has_many :payed_ordered_products end class Delivery < ActiveRecord::Base belongs_to :payed_ordered_product end
![Page 35: «Как разработать надежное решение».Владимир Мельник, Ruby Developer, DataArt](https://reader033.vdocuments.mx/reader033/viewer/2022051502/58d11edd1a28ab2a738b5295/html5/thumbnails/35.jpg)
Доставка - это процесс состоящий из фактов. Факт в случае с доставкой - это передача товара одного участника процесса доставки другому. Физически товар может не перемещаться.Пускай доставка состоит из:
• Packaging
• Shipment
• Transport
• Unloading
• Commitment
![Page 36: «Как разработать надежное решение».Владимир Мельник, Ruby Developer, DataArt](https://reader033.vdocuments.mx/reader033/viewer/2022051502/58d11edd1a28ab2a738b5295/html5/thumbnails/36.jpg)
![Page 37: «Как разработать надежное решение».Владимир Мельник, Ruby Developer, DataArt](https://reader033.vdocuments.mx/reader033/viewer/2022051502/58d11edd1a28ab2a738b5295/html5/thumbnails/37.jpg)
![Page 38: «Как разработать надежное решение».Владимир Мельник, Ruby Developer, DataArt](https://reader033.vdocuments.mx/reader033/viewer/2022051502/58d11edd1a28ab2a738b5295/html5/thumbnails/38.jpg)
Отображение процессов на факты и результаты
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
![Page 39: «Как разработать надежное решение».Владимир Мельник, Ruby Developer, DataArt](https://reader033.vdocuments.mx/reader033/viewer/2022051502/58d11edd1a28ab2a738b5295/html5/thumbnails/39.jpg)
Нас не интересует процесс. Нас интересует результат. Наличие результата является фактом, например, если есть CommittedOrderedProduct, то был осуществлен Commiting, то есть имеет место факт - Commitment.
![Page 40: «Как разработать надежное решение».Владимир Мельник, Ruby Developer, DataArt](https://reader033.vdocuments.mx/reader033/viewer/2022051502/58d11edd1a28ab2a738b5295/html5/thumbnails/40.jpg)
Процесс просто агрегирует факты, но у нас нет необходимости в такой агрегации. Delivery - избыточная сущность. Сам процесс описывается ассоциациями.
class Delivery < ActiveRecord::Base belongs_to :payed_ordered_product end
![Page 41: «Как разработать надежное решение».Владимир Мельник, Ruby Developer, DataArt](https://reader033.vdocuments.mx/reader033/viewer/2022051502/58d11edd1a28ab2a738b5295/html5/thumbnails/41.jpg)
class PackagedOrderedProduct < ActiveRecord::Base belongs_to :payed_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
![Page 42: «Как разработать надежное решение».Владимир Мельник, Ruby Developer, DataArt](https://reader033.vdocuments.mx/reader033/viewer/2022051502/58d11edd1a28ab2a738b5295/html5/thumbnails/42.jpg)
Как узнать текущее состояние доставки?
# 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_…
![Page 43: «Как разработать надежное решение».Владимир Мельник, Ruby Developer, DataArt](https://reader033.vdocuments.mx/reader033/viewer/2022051502/58d11edd1a28ab2a738b5295/html5/thumbnails/43.jpg)
Шутка
![Page 44: «Как разработать надежное решение».Владимир Мельник, Ruby Developer, DataArt](https://reader033.vdocuments.mx/reader033/viewer/2022051502/58d11edd1a28ab2a738b5295/html5/thumbnails/44.jpg)
Foreign Key как Natural Primary Key
• packaged_ordered_products.payed_order_id - является одновременно PRIMARY KEY и FOREIGN KEY ссылающимся на PayedOrderedProduct и OrderedProduct.
• shipped_ordered_products.payed_order_id - является одновременно PRIMARY KEY и FOREIGN KEY ссылающимся на PackagedOrderedProduct, PayedOrderedProduct и OrderedProduct.
• transported_ordered_products.payed_order_id - является одновременно PRIMARY KEY и FOREIGN KEY ссылающимся на ShippedOrderedProduct, PackagedOrderedProduct, PayedOrderedProduct и OrderedProduct.
• outloaded_ordered_products.payed_order_id - является одновременно PRIMARY KEY и FOREIGN KEY ссылающимся на TransportedOrderedProduct, ShippedOrderedProduct, PackagedOrderedProduct, PayedOrderedProduct и OrderedProduct.
• commited_ordered_product.payed_order_id - является одновременно PRIMARY KEY и FOREIGN KEY ссылающимся на OutloadedOrderedProduct, TransportedOrderedProduct, ShippedOrderedProduct, PackagedOrderedProducts, PayedOrderedProduct и OrderedProduct.
![Page 45: «Как разработать надежное решение».Владимир Мельник, Ruby Developer, DataArt](https://reader033.vdocuments.mx/reader033/viewer/2022051502/58d11edd1a28ab2a738b5295/html5/thumbnails/45.jpg)
# committed? CommittedOrderedProduct.exists?(ordered_product_id: ordered_product.id)
![Page 46: «Как разработать надежное решение».Владимир Мельник, Ruby Developer, DataArt](https://reader033.vdocuments.mx/reader033/viewer/2022051502/58d11edd1a28ab2a738b5295/html5/thumbnails/46.jpg)
Гарантии отсутствия дефектов и обнаружение регрессии
![Page 47: «Как разработать надежное решение».Владимир Мельник, Ruby Developer, DataArt](https://reader033.vdocuments.mx/reader033/viewer/2022051502/58d11edd1a28ab2a738b5295/html5/thumbnails/47.jpg)
Все просто: их нет, но количество дефектов можно существенно минимизировать.
![Page 48: «Как разработать надежное решение».Владимир Мельник, Ruby Developer, DataArt](https://reader033.vdocuments.mx/reader033/viewer/2022051502/58d11edd1a28ab2a738b5295/html5/thumbnails/48.jpg)
4 предназначения тестов:
• Разработка более удобного API.
• Разработка low-coupling кода.
• Предоставление информации о регрессии после будущих изменений.
• Документирование кода.
![Page 49: «Как разработать надежное решение».Владимир Мельник, Ruby Developer, DataArt](https://reader033.vdocuments.mx/reader033/viewer/2022051502/58d11edd1a28ab2a738b5295/html5/thumbnails/49.jpg)
Тесты позволяют посмотреть на разработку кода глазами его пользователя.
![Page 50: «Как разработать надежное решение».Владимир Мельник, Ruby Developer, DataArt](https://reader033.vdocuments.mx/reader033/viewer/2022051502/58d11edd1a28ab2a738b5295/html5/thumbnails/50.jpg)
BDD не только подразумевает инкрементальный рефакторинг, но и обеспечивают возможность оного.
![Page 51: «Как разработать надежное решение».Владимир Мельник, Ruby Developer, DataArt](https://reader033.vdocuments.mx/reader033/viewer/2022051502/58d11edd1a28ab2a738b5295/html5/thumbnails/51.jpg)
Тесты позволяют обнаружить архитектурные недостатки на ранних стадиях и устранить их.
![Page 52: «Как разработать надежное решение».Владимир Мельник, Ruby Developer, DataArt](https://reader033.vdocuments.mx/reader033/viewer/2022051502/58d11edd1a28ab2a738b5295/html5/thumbnails/52.jpg)
Тесты не гарантируют отсутствия дефектов. Они косвенным образом уменьшают их и позволяют проверить, что покрытые тестами use case’ы продолжают работать после внесенных изменений.
![Page 53: «Как разработать надежное решение».Владимир Мельник, Ruby Developer, DataArt](https://reader033.vdocuments.mx/reader033/viewer/2022051502/58d11edd1a28ab2a738b5295/html5/thumbnails/53.jpg)
Тесты служат самой надежной и актуальной (если их запускают) документацией.
![Page 54: «Как разработать надежное решение».Владимир Мельник, Ruby Developer, DataArt](https://reader033.vdocuments.mx/reader033/viewer/2022051502/58d11edd1a28ab2a738b5295/html5/thumbnails/54.jpg)
Bonus: BDBF - Behaviour-Driven Bug Fixing
• При помощи тестов описываем правильное поведение системы. Тесты падают.
• Экспериментируем с решением проблемы (пишем много грязного кода). Тесты становятся зелеными.
• Рефакторим код, который исправляет поведение системы. Тесты остаются зелеными.
![Page 55: «Как разработать надежное решение».Владимир Мельник, Ruby Developer, DataArt](https://reader033.vdocuments.mx/reader033/viewer/2022051502/58d11edd1a28ab2a738b5295/html5/thumbnails/55.jpg)
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
![Page 56: «Как разработать надежное решение».Владимир Мельник, Ruby Developer, DataArt](https://reader033.vdocuments.mx/reader033/viewer/2022051502/58d11edd1a28ab2a738b5295/html5/thumbnails/56.jpg)
Мутационное тестирование
Позволяет:
• получить более реалистичные метрики покрытия кода тестами,
• обнаружить неиспользуемый код,
• разрабатывать более безопасный код.
![Page 57: «Как разработать надежное решение».Владимир Мельник, Ruby Developer, DataArt](https://reader033.vdocuments.mx/reader033/viewer/2022051502/58d11edd1a28ab2a738b5295/html5/thumbnails/57.jpg)
Спасибо за внимание
![Page 58: «Как разработать надежное решение».Владимир Мельник, Ruby Developer, DataArt](https://reader033.vdocuments.mx/reader033/viewer/2022051502/58d11edd1a28ab2a738b5295/html5/thumbnails/58.jpg)
Вопросы?