Upgrade to Pro — share decks privately, control downloads, hide ads and more …

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

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

Volodymyr Melnyk

February 09, 2016
Tweet

More Decks by Volodymyr Melnyk

Other Decks in Programming

Transcript

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

    Харьков, 2016

    View Slide

  2. Винегрет
    Владимир Мельник

    Харьков, 2016

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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


    Решение:

    - двойной корпус,

    - секционирование
    контейнера с нефтью

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  20. Новый Завет

    View Slide

  21. SLOC

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  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

    View Slide

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

    View Slide

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

    View Slide

  30. class Customer < ActiveRecord::Base

    end
    class Product < ActiveRecord::Base

    end
    class OrderedProduct < ActiveRecord::Base

    belongs_to :customer

    belongs_to :product

    end

    View Slide

  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

    View Slide

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

    View Slide

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

    View Slide

  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

    View Slide

  35. Доставка - это процесс состоящий из фактов. Факт в случае с
    доставкой - это передача товара одного участника процесса
    доставки другому. Физически товар может не перемещаться.


    Пускай доставка состоит из:

    • Packaging
    • Shipment
    • Transport
    • Unloading
    • Commitment

    View Slide

  36. View Slide

  37. View Slide

  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

    View Slide

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

    View Slide

  40. Процесс просто агрегирует факты, но у нас нет
    необходимости в такой агрегации. Delivery - избыточная
    сущность. Сам процесс описывается ассоциациями.

    class Delivery < ActiveRecord::Base

    belongs_to :paid_ordered_product

    end

    View Slide

  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

    View Slide

  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_…

    View Slide

  43. Шутка

    View Slide

  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.

    View Slide

  45. # committed?

    CommittedOrderedProduct.exists?
    (ordered_product_id: ordered_product.id)

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  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

    View Slide

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

    View Slide

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

    View Slide

  58. Вопросы?

    View Slide