[Вопросы для собеседования](README.md)
# ООП + Микросервисы
+ [Что такое _ООП_?](#Что-такое-ООП)
+ [Назовите основные принципы _ООП_.](#Назовите-основные-принципы-ООП)
+ [Что такое _«инкапсуляция»_?](#Что-такое-инкапсуляция)
+ [Что такое _«наследование»_?](#Что-такое-наследование)
+ [Что такое _«полиморфизм»_?](#Что-такое-полиморфизм)
+ [Что такое _«абстракция»_?](#Что-такое-абстракция)
+ [Что представляет собой _«обмен сообщениями»_?](#Что-представляет-собой-обмен-сообщениями)
+ [Расскажите про основные понятия ООП: _«класс»_, _«объект»_, _«интерфейс»_.](#Расскажите-про-основные-понятия-ООП-класс-объект-интерфейс)
+ [В чем заключаются преимущества и недостатки объектно-ориентированного подхода в программировании?](#В-чем-заключаются-преимущества-и-недостатки-объектно-ориентированного-подхода-в-программировании)
+ [Что подразумевают в плане принципов ООП выражения _«является»_ и _«имеет»_?](#Что-подразумевают-в-плане-принципов-ООП-выражения-является-и-имеет)
+ [В чем разница между _композицией_ и _агрегацией_?](#В-чем-разница-между-композицией-и-агрегацией)
+ [Что такое _статическое_ и _динамическое связывание_?](#Что-такое-статическое-и-динамическое-связывание)
+ [Принцип SOLID?](#Принцип-SOLID)
+ [Что такое Монолит, Микросервис?](#Что-такое-Монолит,-Микросервис)
+ [Что такое Continuous Integration, Continuous Delivery/Deployment?](#Что-такое-Continuous-Integration,-Continuous-Delivery/Deployment)
+ [Что выбрать Монолит или Микросервис?](#Что-выбрать-Монолит-или-Микросервис)
+ [Взаимодействие между микросервисами](#Взаимодействие-между-микросервисами)
+ [OpenAPI](#OpenAPI)
+ [Тестирование микросервисов](#Тестирование-микросервисов)
+ [Распределенная трассировка](#Распределенная-трассировка)
## Что такое _ООП_?
__Объектно-ориентированное программирование (ООП)__ — методология программирования, основанная на представлении программы в виде совокупности объектов, каждый из которых является экземпляром определенного класса, а классы образуют иерархию наследования.
+ объектно-ориентированное программирование использует в качестве основных логических конструктивных элементов объекты, а не алгоритмы;
+ каждый объект является экземпляром определенного класса
+ классы образуют иерархии.
Программа считается объектно-ориентированной, только если выполнены все три указанных требования. В частности, программирование, не использующее наследование, называется не объектно-ориентированным, а программированием с помощью абстрактных типов данных.
Согласно парадигме ООП программа состоит из объектов, обменивающихся сообщениями. Объекты могут обладать состоянием, единственный способ изменить состояние объекта - послать ему сообщение, в ответ на которое, объект может изменить собственное состояние.
[к оглавлению](#ООП)
## Назовите основные принципы _ООП_.
+ _Инкапсуляция_ - сокрытие реализации.
+ _Наследование_ - создание новой сущности на базе уже существующей.
+ _Полиморфизм_ - возможность иметь разные формы для одной и той же сущности.
+ _Абстракция_ - набор общих характеристик.
+ _Пересылка сообщений_ - форма связи, взаимодействия между сущностями.
+ _Переиспользование_- все что перечислено выше работает на повторное использование кода.
Это единственно верный порядок парадигм ООП, так как каждая последующая использует предыдущие.
[к оглавлению](#ООП)
## Что такое _«инкапсуляция»_?
__Инкапсуляция__ – это свойство системы, позволяющее объединить данные и методы, работающие с ними, в классе и скрыть детали реализации от пользователя, открыв только то, что необходимо при последующем использовании.
Цель инкапсуляции — уйти от зависимости внешнего интерфейса класса (то, что могут использовать другие классы) от реализации. Чтобы малейшее изменение в классе не влекло за собой изменение внешнего поведения класса.
[к оглавлению](#ООП)
## Что такое _«наследование»_?
__Наследование__ – это свойство системы, позволяющее описать новый класс на основе уже существующего с частично или полностью заимствующейся функциональностью.
Класс, от которого производится наследование, называется _предком_, _базовым_ или _родительским_. Новый класс – _потомком_, _наследником_ или _производным_ классом.
[к оглавлению](#ООП)
## Что такое _«полиморфизм»_?
__Полиморфизм__ – это свойство системы использовать объекты с одинаковым интерфейсом без информации о типе и внутренней структуре объекта. Т.е. использовать разные объекты одинаково, через общий интерфейс.
Пример: у нас есть метод draw(). Для круга он рисует окружность, для квадрата — квадрат. Но мы обращаемся к ним одинаково: figure.draw().
Преимуществом полиморфизма является то, что он помогает снижать сложность программ, разрешая использование одного и того же интерфейса для задания единого набора действий. Выбор же конкретного действия, в зависимости от ситуации, возлагается на компилятор языка программирования. Отсюда следует ключевая особенность полиморфизма - использование объекта производного класса, вместо объекта базового (потомки могут изменять родительское поведение, даже если обращение к ним будет производиться по ссылке родительского типа).
Полиморфизм бывает _динамическим_ (переопределение методов в потомках) и _статическим_ (перегрузка методов -одинаковое имя, разные параметры).
_Полиморфная переменная_, это переменная, которая может принимать значения разных типов, а _полиморфная функция_, это функция у которой хотя бы один аргумент является полиморфной переменной.
Выделяют два вида полиморфных функций:
+ _ad hoc_, функция ведет себя по разному для разных типов аргументов (например, функция `draw()` — рисует по разному фигуры разных типов);
+ _параметрический_, функция ведет себя одинаково для аргументов разных типов (например, функция `add()` — одинаково кладет в контейнер элементы разных типов).
[к оглавлению](#ООП)
## Что такое _«абстракция»_?
_Абстрагирование_ – это способ выделить набор общих характеристик объекта, исключая из рассмотрения частные и незначимые. Соответственно, __абстракция__ – это набор всех таких характеристик.
Пример: когда мы говорим «машина», нам важно, что у неё есть двигатель и колёса, а цвет ковриков внутри — неважно.
[к оглавлению](#ООП)
## Что представляет собой _«обмен сообщениями»_?
Объекты взаимодействуют, посылая и получая сообщения. Сообщение — это запрос на выполнение действия + данные.
В ООП посылка сообщения (вызов метода) — это единственный путь передать управление объекту. Если объект должен «отвечать» на это сообщение, то у него должна иметься соответствующий данному сообщению метод. Так же объекты, используя свои методы, могут и сами посылать сообщения другим объектам.
[к оглавлению](#ООП)
## Расскажите про основные понятия ООП: _«класс»_, _«объект»_, _«интерфейс»_.
__Класс__ – шаблон описания сущности, определяющий состояние и поведение, зависящее от этого состояния, а также правила для взаимодействия с данной сущностью (контракт).
С точки зрения программирования класс можно рассматривать как набор данных (полей, атрибутов, членов класса) и функций для работы с ними (методов).
С точки зрения структуры программы, класс является сложным типом данных.
__Объект (экземпляр)__ – это отдельный представитель класса, имеющий конкретное состояние и поведение, полностью определяемое классом. Каждый объект имеет конкретные значения атрибутов и методы, работающие с этими значениями на основе правил, заданных в классе.
__Интерфейс__ – это набор методов класса, доступных для использования. Интерфейсом класса будет являться набор всех его публичных методов в совокупности с набором публичных атрибутов. По сути, интерфейс специфицирует класс, чётко определяя все возможные действия над ним.
[к оглавлению](#ООП)
## В чем заключаются преимущества и недостатки объектно-ориентированного подхода в программировании?
✅ Ближе к человеческому восприятию мира.
✅ Код разбивается на логичные части.
✅ Удобнее поддерживать и расширять.
✅ Код можно переиспользовать.
✅ Легко добавлять новые объекты и изменять поведение программы.
❌ Иногда сложно понять, где что наследуется.
❌ Методы могут быть «размазаны» по разным классам.
❌ Документировать сложнее. Поскольку любой метод может быть переопределен, в документации должно говориться не только о том, что делает данный метод, но и о том, в каком контексте он вызывается.
❌ Дополнительные расходы памяти и производительности.
❌ Избыточность. Часто содержится больше методов, чем это реально необходимо текущей программе. А поскольку лишние методы не могут быть удалены, они становятся мертвым грузом.
[к оглавлению](#ООП)
## Что подразумевают в плане принципов ООП выражения _«является»_ и _«имеет»_?
__«является»__ подразумевает наследование. Класс _cat_ является потомком класса _animal_
__«имеет»__ агрегация или композиция. Класс _car_ имеет класс _engine_
[к оглавлению](#ООП)
## В чем разница между _композицией_ и _агрегацией_?
Ассоциация обозначает связь между объектами.
Агрегация — «часть» может существовать отдельно и принадлежать нескольким «целым». (Книга находится в библиотеке, её можно перенести в другую).
Композиция — «часть» жёстко привязана к «целому». (Страница принадлежит конкретной книге).
[к оглавлению](#ООП)
## Что такое _статическое_ и _динамическое связывание_?
Связывание означает наличие связи между ссылкой и кодом. Например, переменная, на которую вы ссылаетесь, привязана к коду, в котором она определена. Аналогично, вызываемый метод привязан к месту в коде, где он определен.
_Статическим_ или _ранним связыванием (early binding)_ — компилятор заранее знает, какой метод будет вызван. (Напр. перегрузка методов).
_Позднее связывание (late binding) или динамическое_ проводимое непосредственно во время выполнения программы, в зависимости от типа объекта (Напр. переопределение методов в наследниках). Механизм позднего связывания зависит от конкретного языка
Итак, фундаментальное различие между статическим и динамическим связыванием в Java состоит в том, что первое происходит рано, во время компиляции на основе типа ссылочной переменной, а второе – позднее, во время выполнения, с использованием конкретных объектов.
В Java почти все методы — динамические, кроме `static`, `final` и `private`.
Ключевые различия между ранним и поздним связыванием в языке Java:
1) Статическое связывание используется в языке Java для разрешения перегруженных методов, в то время как динамическое связывание используется в языке Java для разрешения переопределенных методов.
2) Аналогично, приватные, статические и терминальные методы разрешаются при помощи статического связывания, поскольку их нельзя переопределять, а все виртуальные методы разрешаются при помощи динамического связывания.
3) В случае статического связывания используются не конкретные объекты, а информация о типе, то есть для обнаружения нужного метода используется тип ссылочной переменной. С другой стороны, при динамическом связывании для нахождения нужного метода в Java используется конкретный объект.
[к оглавлению](#ООП)
## Принцип SOLID?
Пять основных принципов дизайна классов:
+ Single Responsibility Principle (Принцип единственной ответственности).
+ Open Closed Principle (Принцип открытости/закрытости).
+ Liskov’s Substitution Principle (Принцип подстановки Барбары Лисков).
+ Interface Segregation Principle (Принцип разделения интерфейса).
+ Dependency Inversion Principle (Принцип инверсии зависимостей).
__Принцип единственной ответственности (SRP)__
Никогда не должно быть больше одной причины изменить класс.
Класс должен быть ответственен лишь за что-то одно. Если класс отвечает за решение нескольких задач, его подсистемы, реализующие решение этих задач, оказываются связанными друг с другом. Изменения в одной такой подсистеме ведут к изменениям в другой.
Представьте себе модуль, который обрабатывает заказы. Если заказ верно сформирован, он сохраняет его в базу данных и высылает письмо для подтверждения заказа. Принцип единственной обязанности подразумевает, что три аспекта этой проблемы на самом деле — три разные обязанности. А значит, должны находиться в разных классах или модулях. Объединение нескольких сущностей, которые могут меняться в разное время и по разным причинам, считается плохим проектным решением. Гораздо лучше разделить модуль на три отдельных, каждый из которых будет выполнять одну единственную функцию.
__Принцип открытости/закрытости (OCP)__
Программные сущности (классы, модули, функции и т.п.) должны быть открыты для расширения, но закрыты для изменения.
Это означает, что должна быть возможность изменять внешнее поведение класса, не внося физические изменения в сам класс. Следуя этому принципу, классы разрабатываются так, чтобы для подстройки класса к конкретным условиям применения было достаточно расширить его и переопределить некоторые функции. Поэтому система должна быть гибкой, с возможностью работы в переменных условиях без изменения исходного кода. Используются интерфейсы
__Принцип подстановки Барбары Лисков (LSP)__
Объекты в программе можно заменить их наследниками без изменения свойств программы.
Это означает, что класс, разработанный путем расширения на основании базового класса, должен переопределять его методы так, чтобы не нарушалась функциональность с точки зрения клиента. То есть, если разработчик расширяет ваш класс и использует его в приложении, он не должен изменять ожидаемое поведение переопределенных методов. Если оказывается, что в коде проверяется тип класса, значит принцип подстановки нарушается.
__Принцип разделения интерфейса (ISP)__
Клиенты не должны быть вынуждены реализовывать методы, которые они не будут использовать.
Принцип разделения интерфейсов говорит о том, что слишком «толстые» интерфейсы необходимо разделять на более мелкие и специфические, чтобы клиенты мелких интерфейсов знали только о методах, необходимых в работе.
Рассмотрим пример. Разработчик Алекс создал интерфейс "отчет" и добавил два метода: generateExcel() и generatedPdf(). Теперь клиент А хочет использовать этот интерфейс, но он намерен использовать отчеты только в PDF-формате, а не в Excel. Он должен будет реализовать два метода, один из которых по большому счету не нужен и существует только благодаря Алексу — дизайнеру программного обеспечения. Клиент воспользуется либо другим интерфейсом, либо оставит поле для Excel пустым. Так в чем же решение? Оно состоит в разделении существующего интерфейса на два более мелких. Один — отчет в формате PDF, второй — отчет в формате Excel. Это даст пользователю возможность использовать только необходимый для него функционал.
__Принцип инверсии зависимостей (DIP)__
Зависимости внутри системы строятся на основе абстракций. Объектом зависимости должна быть абстракция, а не что-то конкретное. Модули верхнего уровня не зависят от модулей нижнего уровня. Абстракции не должны зависеть от деталей. Детали должны зависеть от абстракций. Программное обеспечение нужно разрабатывать так, чтобы различные модули были автономными и соединялись друг с другом с помощью абстракции.
Классическое применение этого принципа — Spring framework. В рамках Spring framework все модули выполнены в виде отдельных компонентов, которые могут работать вместе. Они настолько автономны, что могут быть быть с такой же легкостью задействованы в других программных модулях помимо Spring framework. Это достигнуто за счет зависимости закрытых и открытых принципов. Все модули предоставляют доступ только к абстракции, которая может использоваться в другом модуле.
[к оглавлению](#ООП)
## Что такое Монолит, Микросервис?
Монолитная архитектура - система с одним сервисом, который отвечает за работу со всей предметной областью бизнеса (приложения)
При начале работы над монолитным проектом Достоинства:
✅ Быстрая разработка
✅ Возможность внесения радикальных изменений (например изменить архитетуру, класс-дизайн, схему бд)
✅ Безболезненое тестирование
✅ Легкое развертывание
✅ Простое hardware масштабирование
С увеличением размера проекта и команды разработки появляются Минусы:
❌ Медленное внесение изменений
Команды А и Б работают не пересекаясь. Выкатывается новая версия проекта с багами в коде команды Б. Откатывается на предыдущуюю версию весь код и команды Б и команды А.
❌ Уязвимая надежность - если падает часть кода, то не работает все приложение.
❌ Трудности в hardware масштабировании.
Одна часть требует оперативу, другая ядра. Приходится апгрейдить "вертикально" - покупать больше оперативных планок и процессоры с большим кол-вом ядер для всех сервисов. А не по потребностям
❌ Дороговизна обновления технологического стека. Например переход на новую версию Java. Чтобы проверить эффективность, нужно переписывать весь проект
Микросервисная архитектура — система, которая содержит больше одного обособленнго сервиса. Размер значения не имеет.
Обособленный сервис — является независимой единицей развертывания, имеет своё хранилище, свою БД (?), отвечает за свою часть предметной области
Достоинства:
✅ Возможность масштабирования разработки
✅ Дешевизна эксперементов с новым стеком
✅ Инкрементальное обновление технолошического стека
✅ Повышенная надежность и отказоустойчивость
Минусы:
❌ Сложность проектирования архитектуры
❌ Долгое внесение радикальных изменений
❌ Нетривиальное тестирование
❌ Повышенные требования к Continuous Integration/Continuous Delivery (деплою)
Сложности проектирования Микросервисов
+ Сложно разделить предметную область на части
Не стоит делить монолит на микросервисы по функциональным возможностям. Это приведет к распределенному монолиту - архитектура, включающая недостатки и того и другого. Монолит нужно разбивать по пренадлежности к какой-то области бизнеса. Отличить одно от другого довольно сложно. Т.е. по принципу единой ответственности.
Соответствие принципам Low coupling, high cohesion способствует быстрому внесению изменений и легкому тетсированию.
Сильная связанность high cohesion - части системы, которые изменяются вместе, должны находиться ближе друг к другу
Слабая связанность low coupling - части системы, которые изменяются параллельно, должны иметь как можно меньше зависимостей друг на друга b внутри сервиса и между сервисами

+ Задержки при межсервисном взаимодействии влияют на производительность + сеть ненадежна
+ Межсервисное взаимодействие влияет на доступность
+ Сложно добиться согласованности данных
[к оглавлению](#ООП)
## Что такое Continuous Integration, Continuous Delivery/Deployment?
Непрерывная интеграция (CI) — процесс автоматического принятия изменений. Первичный процесс обновления ПО, в рамках которого все изменения на уровне кода вносятся в единый центральный репозиторий. Такое внесение принято называть слиянием. После каждого слияния (которое проходит по несколько раз в день) в изменяемой системе происходит автоматическая сборка (часто приложение упаковывается в Docker) и тестирование (проверка конкретных модулей кода, UI, производительности, надёжности API). Таким образом разработчики страхуются от слишком поздних обнаружений проблем в обновлениях.
+ Возможность локальной сборки проекта
+ На каждый коммит в кдаленный репо запускаем сборки проекта в системе (Jenkins, TravisCI)
+ Сломанная сборка запрещает слияние
Непрерывная доставка (CD) — CI + CD. Автоматизированый процесс доставки изменений до продакшена. Теперь новая версия не только создаётся и тестируется при каждом изменении кода, регистрируемом в репозитории, но и может быть оперативно запущена по одному нажатию кнопки развёртывания. Однако запуск развёртывания всё ещё происходит вручную — ту самую кнопку всё же надо кому-то нажать. Этот метод позволяет выпускать изменения небольшими партиями, которые легко изменить или устранить в случае необходимости.
+ Поддерживаем артефакты стабильными
+ Развертываем по кнопке
[к оглавлению](#ООП)
## Что выбрать Монолит или Микросервис?
Микро если:
+ Предметная область хорошо делится на части
+ Много направлений, которые нужно развивать параллельно
+ "Особенности" монолита не устраивают бизнес
Монолит если:
+ Нужно быстро сделать прототип
+ Вашу задачу можно решить одним сервисом
+ Непонятно, как разделить предметную область
+ Низкие нагрузки, мало разработчиков, нет ресурсов на поддержание микросервисов
https://microservices.io/
https://martinfowler.com/
"microservices patterns" chris richardson
"clean architecture" robert martin
[к оглавлению](#ООП)
## Взаимодействие между микросервисами
Межсервисное взаимодействие = сетевое взаимодействие, т.е. система управляется сообщениями
+ Производительность = задержки и пропускная способность
+ Доступность и отказоустойчивость
+ Архитектура
__Транспорт__
+ стандарт JSON внутри HTTP (REST, RPC, GraphQL). Простой, множество инструментов, человекочитаемость. Из-за текстового формата большие объемы и нужно оптимизировать
+ бинарные протоколы: gRPC, Thrift, Avro и т.д.
Выше производительность, оптимизированно представление данных, можно определить схему сообщения из коробки, но меньше инструментов и не читаемы человеком
Что выбрать?
+ Начинать с HTTP
+ Бинарные не бесплатные
+ Большинство проблем не из-за протокола!
+ Для публичных API всегда HTTP либо несколько реализаций одна из которых HTTP
__API__
Application Programming Interface - интерфейс, определяющий способ и схему взаимодействия с сервисом
+ Remote Procedure Call (RPC)
Только POST метод. Все параметры в теле запроса. Любой статус !=200, считается ошибкой
Выбирают: Простая реализация, Внутренние API, HTTP только как транспорт
+ Representational State Transfer (REST)
Архитектурный стиль, в основе которого лежат ресурсы и их идентификация, изменение их состояния через представление. REST != HTTP
Выбирают: Своего рода стандарт, Внутренние API, Публичные API, HTTP как протокол
+ GraphQL
Язык запросов для API. Например можно задать конкретный набор полей, которые хотим получить в ответе на запрос
Выбирают: Типо-безопасность, API для Web и мобильных клиентов, тут свой инструментарий
__Проектирвоание__
+ Клиент-сервер
+ Stateless - сервис не должен хранить состояние в памяти, это важно для масштабирования
+ Кеширование
__Типы сообщений__
+ Команды
+
Императивное управление (звучит как "сделать что-то"), вызывают сильную связанность, зато понятны - названия обычно отражают логику

+ События
+
Декларативное управление (звучит как "что-то произошло"), снижают связанность, менее понятны - не знаем что скрыто в notifyOrderCreated

__Виды взаимодействия__
+ Синхронные - отправляем запрос и блокируемся, ожидая результата.
Просто и понятно, быстрые операции и низкие задержки (ок), низкая пропускная способность (не ок), вызывает низкую доступность (не ок)
+ Ассинхронные - не блокируемся ожидая ответ
Сложнее в реализации, выше задержки (не ок), выше пропускная способность (ок), повышает доступность (ок)
Short polling - вызываем операцию и получаем ссылку на ресурс с результатом операции. Переодически опрашиваем этот ресурс на предмет текущего статуса операции

Пользователь должен ждать как можно меньше, и нужно выполнять как можно меньше запросов на опрос
Стратегии опроса:
+ Фиксированное время (раз в секунду) - просто, но время запроса может чуть отличаться, что приведет к лишним запросам
+ Прогрессия (геометрическая/алгебраическая) - сокращает кол-во запросов, но возможен вариант когда придется долго ждать
+ На основе статистического распределения - например, знаем, что запрос выполняется 50% за 1.5с, 90% за 3с и 99% за 5с, мы можем распределить запросы во времени
Callbacks - вызываем операцию и получаем идентификатор операции. Сервис, выполняющий операцию, отправляет уведомление вызвавшему сервису о результате выплонения операции

__Способы взаимодействия__
+ Прямой обмен А->Б - просто, легкая эксплуатация, но сильная связанность сервисов. Хорошо для Команд
+ Обмен через брокеры сообщений А->Брокер->Б - сложнее, позволяет снизить связанность сервисов. Хорошо для Событий
На основе callback: RabbitMQ

На основе polling: Kafka

Микросервисы могут работать одновеременно с разными диалектами БД. При этом есть __сильная согласованность__, когда изменения сразу видны всем, с момента их применения и __конечная согласованность__ когда изменения будут видно, но не сразу, а доставляются асинхронно
__Сильная согласованность__ - всегда актуальные данные, но высокие задержки при получении
В таких случаях используются __Распределенные транзакции__. Но это сложно, дорого и есть не везде. Можно эмулировать распределенную транзакцию с помощью вложенных локальных транзакций

При этом возврат ошибки не гарантирует, что запись не была вставленна в БД. А откат первой транзакции не приводит к откату второй.
Saga паттерн: Для решения нужно разбивать одну большую распределенную транзакцию на последовательность локальных транзакций и предоставить возможность отката всех локальных транзакций.

Особенности: нужно уметь восстанавливаться после сбоев любого участка и повторять сагу с определенного шага + отличать финальные ошибки от нефинальных
Хореография

+ Нет единой точки отказа
+ Легко менять кусочек процесса
+ Сложно понять процесс целиком и отслеживать ошибки
Оркестрация

+ Есть единая точка отказа
+ Сложнее вносить изменения в места
+ Легко понять процесс и отслеживать ошибки

__Конечная согласованность__ - могут быть неактуальные данные, зато низкие задержки

__Взаимоисключения__
Иногда требуется выполнять какой-то процесс эксклюзивно. Например используя распределенный консенсус - алгоритмы, которые сложно и медленно работают. etcd, Consul, Zookeeper. Зато отказоустойчивы
Альтернатива - red lock, когда БД используется в качестве хранилища блокировок. Блокировка не захватывается, а арендуется на время. Чтобы в случае блокировки и отказа системы блокировка не осталась навсегда Добавляем версию блокировки для контроля ее корректности

[к оглавлению](#ООП)
## OpenAPI
OpenAPI - спецификация для описания REST API.
https://habr.com/ru/post/541592/
Swagger - это фреймворк для спецификации RESTful API, цель которого - поддерживать документацию в актуальном виде. Его прелесть заключается в том, что он дает возможность не только интерактивно просматривать спецификацию, но и отправлять запросы – так называемый Swagger UI.
+ Code first - сначала пишем код, потом генерируем спецификацию
+ Schema first - сперва спецификация, затем генерируем по ней код
+ Публикуем спецификацию (отделный артефак или Swagger)
+ Строго следовать этой спецификации
Документирование БД
Database Schema as a Code - текущая схема должна быть представлена последовательностью патчей, хранимых как код
+ Возможность восстановить БД на любом окружении
+ Аудит, контроль, валидация
+ Flyway, Liquibase
[к оглавлению](#ООП)
## Тестирование микросервисов
+ Компонентные тесты проверяют работу сервисов и их взаимодействие
+ Модульные тесты для тестирования отдельных функций
Компонентных должно быть больше, чем модульных, т.к. изменяемая среда, много зависимочти между классами
Тесты должны быть независимыми и уметь работать параллельно.
Для тестирования API лучше делать реальные HTTP вызовы, валидировать ответ согласно схеме (JSON). RESTAssured как пример инструмента.
При тестирование взаимодействия с БД на каждый запуск тестов локально поднимается БД. Embedded или TestContainers. Тесты не должны очищать БД или буффер брокера сообщений перед/после своего запуска/завершения
При тестировании взаимодействия микросервисов на каждый запуск тестов локально HTTP-сервер, создаем моки операций сервисов, выполняем, моки валидируем. WireMock, MockServer
При тестировании аинхронных процессов стараемся приблизить тестовый сценарий к реальному, запускаем операцию и ждем завершения выполнения. Awaitility
Для автоматизации развиваем Continuous Integration/Continuous Delivery - помогает быстрее развивать сервисы и доставлять их на production. Но дорого.
[к оглавлению](#ООП)
## Распределенная трассировка
При межсервисном взаимодействии сложно отследить весь путь запроса по системе
+ К каждому внешнему запрсос прикрепляем "идентификатор операции"
+ Пробрасываем его по всей системе
+ Добавляем его в логовые сообщения для отслеживания. Elastic APM, OpenTracing
Для HTTP: Прикрепляем HTTP-заголовок с этим идентификатором - Используем его при обработке запроса - Поллинг делаем с тем же индентификаторо - Обраный вызов с ним же - В брокер сообщений также отправляем этот индентификатор
Для Саги: Исходный запрос теряется при обработке асинхронных процессов - В задачу на продолжение саги кладем исходный идентификатор операции (в БД) - При возобновлении саги используем этот идентификатор
Визуализация трасс помогает построить схему взаимодействия между сервисами. Можно это делать атоматически и динамически. Zipkin, Jaeger
[к оглавлению](#ООП)
# Источники
+ [DevColibri](http://devcolibri.com/720)
+ [Хабрахабр](https://habrahabr.ru/post/87119/)
+ [Википедия](https://ru.wikipedia.org/wiki/Объектно-ориентированное_программирование)
[Вопросы для собеседования](README.md)