Как разработать надежное решение

Как разработать надежное решение

E317f99efbd38a2a7e1733f67b6a8cf1?s=128

Volodymyr Melnyk

February 09, 2016
Tweet

Transcript

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

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

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

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

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

    сбоев • легко адаптируется к изменениям внешнего мира • легко адаптируемо к изменениям внешнего мира
  6. Доставка нефти Требование: Отсутствие потерь или минимальные потери при повриждении

    корпуса.
 
 Решение:
 - двойной корпус,
 - секционирование контейнера с нефтью
  7. Работа без сбоев

  8. • 24/7/356 доступность сервисов • устойчивость к высоким нагрузкам •

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

    обработка исключительных ситуаций • целостность данных и их устойчивость к повреждениям • SOA и микро-сервисная архитектуры
  10. Адаптация как саморегуляция

  11. • эластичная архитектура • cloud, fog, etc. • репликация •

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

    • реплики • балансирование нагрузки • мета-программирование • само-обучающиеся системы
  13. Адаптируемость из вне

  14. • Легко изменяемый код или код, которые не требует больших

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

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

  17. В тезисах • Гибкая архитектура - это архитектура позволяющая отстрачивать

    принятие важных и дорогостоящи решений. • Гибкая архитектура ~ надежная архитектура. • Гибкие методологии возможны только при гибкой архитектуре. • Гибкая архитектура - архитектура без жестких зависимостей.
  18. Общие принципы • Low-coupling • High-cohesion • SOLID

  19. SOLID • Принцип единственной ответственности. Принцип согласно которому функциональность объекта

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

  21. SLOC

  22. Система как логика над собственными компонентами • Целое - больше

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

  24. Неправильные ассоциации - одна из самых дорогих ошибок в разработке

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

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

    добиться максимальной независимости компонентов.
  27. 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
  28. • Экземпляры Product - безусловно сущности. • OrderItem является ассоциацией.

    Судя по наличию order_id и product_id - между Order и Product. • Чем является Order?
  29. • Order не заществует самостоятельно. Без customer_id он лишен смысла,

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

    class OrderedProduct < ActiveRecord::Base
 belongs_to :customer
 belongs_to :product
 end
  31. Оплата и доставка 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
  32. Что здесь не так? • Отношение пользователя к товару не

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

    стартующий после оплаты.
  34. 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
  35. Доставка - это процесс состоящий из фактов. Факт в случае

    с доставкой - это передача товара одного участника процесса доставки другому. Физически товар может не перемещаться.
 
 Пускай доставка состоит из:
 • Packaging • Shipment • Transport • Unloading • Commitment
  36. None
  37. None
  38. Отображение процессов на факты и результаты 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
  39. Нас не интересует процесс. Нас интересует результат. Наличие результата является

    фактом, например, если есть CommittedOrderedProduct, то был осуществлен Commiting, то есть имеет место факт - Commitment.
  40. Процесс просто агрегирует факты, но у нас нет необходимости в

    такой агрегации. Delivery - избыточная сущность. Сам процесс описывается ассоциациями.
 class Delivery < ActiveRecord::Base
 belongs_to :paid_ordered_product
 end
  41. 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
  42. Как узнать текущее состояние доставки? # 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_…
  43. Шутка

  44. 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.
  45. # committed?
 CommittedOrderedProduct.exists? (ordered_product_id: ordered_product.id)

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

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

  48. 4 предназначения тестов: • Разработка более удобного API. • Разработка

    low-coupling кода. • Предоставление информации о регрессии после будущих изменений. • Документирование кода.
  49. Тесты позволяют посмотреть на разработку кода глазами его пользователя.

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

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

    их.
  52. Тесты не гарантируют отсутствия дефектов. Они косвенным образом уменьшают их

    и позволяют проверить, что покрытые тестами use case’ы продолжают работать после внесенных изменений.
  53. Тесты служат самой надежной и актуальной (если их запускают) документацией.

  54. Bonus: BDBF - Behaviour- Driven Bug Fixing • При помощи

    тестов описываем правильное поведение системы. Тесты падают. • Экспериментируем с решением проблемы (пишем много грязного кода). Тесты становятся зелеными. • Рефакторим код, который исправляет поведение системы. Тесты остаются зелеными.
  55. 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
  56. Мутационное тестирование Позволяет: • получить более реалистичные метрики покрытия кода

    тестами, • обнаружить неиспользуемый код, • разрабатывать более безопасный код.
  57. Спасибо за внимание

  58. Вопросы?