<?xml version="1.0" encoding="utf-8"?> 
<rss version="2.0"
  xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd"
  xmlns:atom="http://www.w3.org/2005/Atom">

<channel>

<title>Блоги: заметки с тегом system-design</title>
<link>https://blogengine.me/blogs/tags/system-design/</link>
<description>Автоматически собираемая лента заметок, написанных в блогах на Эгее</description>
<author></author>
<language>ru</language>
<generator>Aegea 11.0 (v4079e)</generator>

<itunes:subtitle>Автоматически собираемая лента заметок, написанных в блогах на Эгее</itunes:subtitle>
<itunes:image href="" />
<itunes:explicit>no</itunes:explicit>

<item>
<title>Паттерн «Репозиторий»</title>
<guid isPermaLink="false">119847</guid>
<link>https://stefaniuk.website/all/repository-pattern/</link>
<pubDate>Thu, 08 Jul 2021 17:50:13 +0500</pubDate>
<author>Bohdan Stefaniuk</author>
<comments>https://stefaniuk.website/all/repository-pattern/</comments>
<description>
&lt;p&gt;&lt;a href="https://stefaniuk.website/"&gt;Bohdan Stefaniuk&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;Репозиторий один из самых популярных паттернов для доступа к данным. Он используется для абстрагирования от конкретной реализации и нюансов работы с источником данных, внешних сервисов, файловой системой и т. д.&lt;/p&gt;
&lt;p&gt;С одной стороны, это очень простой паттерн, который позволяет скрыть сложность работы с БД. Но с другой стороны, спросите 10 программистов описать этот шаблон и вы получите 10 разных реализаций.&lt;/p&gt;
&lt;p&gt;Самая большая проблема этого шаблона — множество вопросов, которые возникают при его реализации и дальнейшей поддержки.&lt;/p&gt;
&lt;p&gt;Изначально хотел сам расписать проблемы, но за меня это уже сделали, поэтому настоятельно советую прочитать статью: &lt;a href="https://blog.byndyu.ru/2011/01/domain-driven-design-repository.html"&gt;«Проблемы паттерна Репозиторий».&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Если кратно, то:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Что делать если репозиториям нужно использовать закрытые методы друг друга?&lt;/li&gt;
&lt;li&gt;Можно ли использовать один репозиторий на весь проект или делать репозиторий на каждую сущность?&lt;/li&gt;
&lt;li&gt;Нужно ли дублировать методы репозитория в сервис или мы можем напрямую использовать репозиторий в контроллерах?&lt;/li&gt;
&lt;li&gt;Нужно ли возвращать IQueryable и как это повлияет на дизайн системы в случае с .NET кодом? Если нет, то как правильно изменять сущности без использования Change Tracking?&lt;/li&gt;
&lt;li&gt;Как правильно объединить репозиторий и UoW?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Отдельно также хочу отметить доклад: &lt;a href="https://www.youtube.com/watch?v=3yPpL1rEK9o&amp;t=1208s"&gt;Денис Цветцих «Repository и UnitOfWork в 2020 году, must have или антипаттерн?»&lt;/a&gt;. В нем также поднимаются проблемы репозитория, способы их решения и варианты замены этот шаблона на другой.&lt;/p&gt;
&lt;p&gt;Репозиторий — хороший паттерн, который должен быть в арсенале любого программиста, но стоит использовать его с умом и учитывать проблемы, которые он может вызвать.&lt;/p&gt;
&lt;p&gt;Для себя я решил что репозиторий хорошо подходит, когда вся логика приложения вписывается в CRUD модель. Но если логика более сложная или приложение подразумевает Task Base UI, тогда лучше прибегнуть к подходу CQRS. Он позволяет разбить сложную бизнес логику включая репозитории на независимые объекты, каждый из которых выполняет только одну бизнес задачу или use case.&lt;/p&gt;
&lt;div style="max-width: 750px"&gt;&lt;div class="e2-text-picture"&gt;
&lt;img src="https://stefaniuk.website/pictures/repository-pattern-orm-db.png" width="1200" height="579" alt="" /&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Я кроме все прочего не люблю репозитории за:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ограничение функциональности ORM, большенство специфических операций недоступны. В зависимости от реализации можем потерять Change Tracking.&lt;/li&gt;
&lt;li&gt;Дополнительный мапинг из доменных объектов в DTO.&lt;/li&gt;
&lt;li&gt;Дополнительный слой абстракции, который зачастую просто не нужен. Особенно если речь идет о небольших сервисах где логику нужно делать максимально простой и незамысловатой.&lt;/li&gt;
&lt;li&gt;Работает только в простых CRUD сценариях.&lt;/li&gt;
&lt;/ul&gt;
</description>
</item>

<item>
<title>Документация</title>
<guid isPermaLink="false">119837</guid>
<link>https://stefaniuk.website/all/tech-documentation/</link>
<pubDate>Thu, 09 May 2019 14:22:39 +0500</pubDate>
<author>Bohdan Stefaniuk</author>
<comments>https://stefaniuk.website/all/tech-documentation/</comments>
<description>
&lt;p&gt;&lt;a href="https://stefaniuk.website/"&gt;Bohdan Stefaniuk&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;Ох сколько проблем вызывает документация. И зачастую эти проблемы связаны с ее отсутствием. Почти всегда разработчики считаю что написание документации это: лишнее, бюрократия, скучно. Также часто разработчики приводят в пример цитату из скрам гайда: работающий продукт важнее исчерпывающей&lt;br /&gt;
документации.&lt;/p&gt;
&lt;p&gt;Я считаю что документация в том или ином виде должна присутствовать. Зачастую ее ценность понимается не сразу, а по прошествию времени. Например так случилось и в нашей команде, когда старые разработчики ушли и новеньким было очень сложно делать экскурс по системе, а она очень большая!&lt;/p&gt;
&lt;p&gt;Но я против детально и огромной документации. Для себя и своих личных проектов я придерживаюсь следующего шаблона. Он достаточно компактный и простой в написании. Да это не ГОСТ, не ISO и не IEEE. Но она понятная и ее написание не занимает много времени.&lt;/p&gt;
&lt;p&gt;Какие проблемы я пробую решить своим шаблоном:&lt;/p&gt;
&lt;ol start="1"&gt;
&lt;li&gt;Для чего нужен данный модуль или архитектура?&lt;/li&gt;
&lt;li&gt;Как ее использовать?&lt;/li&gt;
&lt;li&gt;Как вносить изменения?&lt;/li&gt;
&lt;li&gt;Как осуществлять диагностику или проверку состояния?&lt;/li&gt;
&lt;li&gt;Какие были связаны с ней проблемы?&lt;/li&gt;
&lt;li&gt;Какими тестами покрыто? (Проблема очень важная, так как часто при планировании изменений приходилось вспоминать/идти проверять какими тестами покрыт функционал, что отнимало иногда много времени).&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Шаблон документации&lt;/h2&gt;
&lt;p&gt;&lt;b&gt;Назначение:&lt;/b&gt; для чего нужен этот модуль, какую задачу решает?&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Основная задача:&lt;/b&gt; ссылка на задачу в трекере в рамках которой разрабатывалась данный модуль.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Диаграмма:&lt;/b&gt; графическое отображение архитектуры. Позволит понять что от кого зависит и как взаимодействует с другими частями системы.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Зоны ответственности:&lt;/b&gt; кратко описать элементы модуля и за что они отвечают. Смысл приёма в том, чтобы явно выделить назначение класса. Идеальный результат — получить класс, который можно описать одной фразой или даже одним словом.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Пример использования:&lt;/b&gt; небольшой пример того как использовать данный функционал.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Обработка ошибок:&lt;/b&gt; как обрабатываются ошибки.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Логирование:&lt;/b&gt;&lt;/p&gt;
&lt;ol start="1"&gt;
&lt;li&gt;В какой файл пишутся логи.&lt;/li&gt;
&lt;li&gt;Уровни логирования и какую они могут дать информацию.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;b&gt;Тесты:&lt;/b&gt; каким типом тестов покрыта данная функциональность.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;FAQ: &lt;/b&gt; вопросы и ответы по данной функциональности. Например: как объединить 2 объекта в сущности?&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Инциденты и баги:&lt;/b&gt; ссылки на баги, которые были найдены в данной функциональности и исправленные.&lt;/p&gt;
&lt;h2&gt;Статьи по теме&lt;/h2&gt;
&lt;ol start="1"&gt;
&lt;li&gt;&lt;a href="https://habr.com/ru/post/143920/"&gt;Еще раз о документации&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://habr.com/ru/post/303760/"&gt;7 правил написания технической документации мирового класса&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;
</description>
</item>

<item>
<title>Логирование</title>
<guid isPermaLink="false">119838</guid>
<link>https://stefaniuk.website/all/logging/</link>
<pubDate>Mon, 29 Apr 2019 22:58:18 +0500</pubDate>
<author>Bohdan Stefaniuk</author>
<comments>https://stefaniuk.website/all/logging/</comments>
<description>
&lt;p&gt;&lt;a href="https://stefaniuk.website/"&gt;Bohdan Stefaniuk&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;Для чего вообще нужно логирование в приложении:&lt;/p&gt;
&lt;ol start="1"&gt;
&lt;li&gt;Сказать, что делать система, не прибегая к отладчику.&lt;/li&gt;
&lt;li&gt;Найти причины возникновения той или иной ситуации внутри приложения.&lt;/li&gt;
&lt;li&gt;Анализ того на что тратится больше всего ресурсов.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;b&gt;Какие есть требования к логерам?&lt;/b&gt;&lt;/p&gt;
&lt;ol start="1"&gt;
&lt;li&gt;Уровни логирования и фильтрация сообщений.&lt;/li&gt;
&lt;li&gt;Ротация лог файлов.&lt;/li&gt;
&lt;li&gt;Возможность писать сообщения не только в файл.&lt;/li&gt;
&lt;li&gt;Thread safety.&lt;/li&gt;
&lt;li&gt;Асинхронное логирование.&lt;/li&gt;
&lt;li&gt;Формат и конфигурация логов.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Уровни логирования&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;TRACE&lt;/b&gt; — вывод всего подряд. На тот случай, если Debug не позволяет локализовать ошибку. В нем полезно отмечать вызовы разнообразных блокирующих и асинхронных операций.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;DEBUG&lt;/b&gt; — журналирование моментов вызова «крупных» операций. Старт/остановка потока, запрос пользователя и т. п.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;INFO&lt;/b&gt; — обычные сообщения, информирующие о действиях системы. Реагировать на такие сообщения вообще не надо, но они могут помочь, например, при поиске багов, расследовании интересных ситуаций итд.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;WARNING&lt;/b&gt; — нештатные ситуации. Например непредвиденные параметры, странные форматы запроса. Любая информация, которая должна привлечь внимание. Некритичные ошибки.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;ERROR&lt;/b&gt; — ошибка в работе системы, требующая вмешательства. Что-то не сохранилось, что-то отвалилось.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;FATAL&lt;/b&gt; — критическая ситуация, которая требует немедленной реакции. Обычно значит что система в неработоспособном состоянии. Пишем в лог все до чего можем дотянутся.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Замечание! Никогда не отправляйте пустое исключение в лог. Так как обычно не понятно к чему принадлежит этот стэк-трейс, как программа отреагировала на ошибку. Чтобы избежать этого, в дополнение к трейсам  прикладывайте и сообщение, которое обьясняет что именно произошло.&lt;/p&gt;
&lt;h2&gt;Интересные статьи на тему&lt;/h2&gt;
&lt;ol start="1"&gt;
&lt;li&gt;&lt;a href="https://habr.com/ru/post/135242/"&gt;Архитектура логирования&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.thekua.com/atwork/2008/11/application-logging-principles/"&gt;Application logging principles&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;
</description>
</item>

<item>
<title>Шардинг</title>
<guid isPermaLink="false">119854</guid>
<link>https://stefaniuk.website/all/sharding/</link>
<pubDate>Fri, 05 Apr 2019 02:26:34 +0500</pubDate>
<author>Bohdan Stefaniuk</author>
<comments>https://stefaniuk.website/all/sharding/</comments>
<description>
&lt;p&gt;&lt;a href="https://stefaniuk.website/"&gt;Bohdan Stefaniuk&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;Шардинг (иногда шардирование) — это другая техника масштабирования работы с данными. Суть его в разделении (партиционирование) базы данных на отдельные части так, чтобы каждую из них можно было вынести на отдельный сервер. Этот процесс зависит от структуры базы данных и выполняется прямо в приложении в отличие от репликации&lt;/p&gt;
&lt;h2&gt;Вертикальный шардинг&lt;/h2&gt;
&lt;p&gt;Вертикальный шардинг — это выделение таблицы или группы таблиц на отдельный сервер. Например, в приложении есть такие таблицы:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;i&gt;users&lt;/i&gt; — данные пользователей&lt;/li&gt;
&lt;li&gt;&lt;i&gt;photos&lt;/i&gt; — фотографии пользователей&lt;/li&gt;
&lt;li&gt;&lt;i&gt;albums&lt;/i&gt; — альбомы пользователей&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Таблицу users Вы оставляете на одном сервере, а таблицы &lt;i&gt;photos&lt;/i&gt; и &lt;i&gt;albums&lt;/i&gt; переносите на другой. В таком случае в приложении Вам необходимо будет использовать соответствующее соединение для работы с каждой таблицей&lt;/p&gt;
&lt;h2&gt;Горизонтальный шардинг&lt;/h2&gt;
&lt;p&gt;Горизонтальный шардинг — это разделение одной таблицы на разные сервера. Это необходимо использовать для огромных таблиц, которые не умещаются на одном сервере. Разделение таблицы на куски делается по такому принципу:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;На нескольких серверах создается одна и та же таблица (только структура, без данных).&lt;/li&gt;
&lt;li&gt;В приложении выбирается условие, по которому будет определяться нужное соединение (например, четные на один сервер, а нечетные — на другой).&lt;/li&gt;
&lt;li&gt;Перед каждым обращением к таблице происходит выбор нужного соединения.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Совместное использование&lt;/h2&gt;
&lt;p&gt;Шардинг и репликация часто используются совместно. В нашем примере, мы могли бы использовать по два сервера на каждый шард таблицы&lt;/p&gt;
&lt;h2&gt;Key-value базы данных&lt;/h2&gt;
&lt;p&gt;Следует отметить, что большинство Key-value баз данных поддерживает шардинг на уровне платформы. Например, Memcache. В таком случае, Вы просто указываете набор серверов для соединения, а платформа сделает все остальное&lt;/p&gt;
&lt;h2&gt;Итог&lt;/h2&gt;
&lt;p&gt;Не следует применять технику шардинга ко всем таблицам. Правильный подход — это поэтапный процесс разделения растущих таблиц. Следует задумываться о горизонтальном шардинге, когда количество записей в одной таблице переходит за пределы от нескольких десятков миллионов до сотен миллионов.&lt;/p&gt;
&lt;h2&gt;P.S.&lt;/h2&gt;
&lt;p&gt;Помните, процесс масштабирования данных — это архитектурное решение, оно не связано с конкретной технологией. Не делайте ошибок наших отцов — не переезжайте с известной Вам технологии на новую из-за поддержки или не поддержки шардинга. Проблемы обычно связаны с архитектурой, а не конкретной базой данных&lt;/p&gt;
&lt;h2&gt;Ссылки&lt;/h2&gt;
&lt;ol start="1"&gt;
&lt;li&gt;&lt;a href="https://ruhighload.com/%D0%92%D0%B5%D1%80%D1%82%D0%B8%D0%BA%D0%B0%D0%BB%D1%8C%D0%BD%D1%8B%D0%B9+%D1%88%D0%B0%D1%80%D0%B4%D0%B8%D0%BD%D0%B3"&gt;Вертикальный шардинг&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ruhighload.com/%D0%A8%D0%B0%D1%80%D0%B4%D0%B8%D0%BD%D0%B3+%D0%B8+%D1%80%D0%B5%D0%BF%D0%BB%D0%B8%D0%BA%D0%B0%D1%86%D0%B8%D1%8F"&gt;Шардинг и репликация&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
</description>
</item>

<item>
<title>Репликация данных</title>
<guid isPermaLink="false">119853</guid>
<link>https://stefaniuk.website/all/db-replication/</link>
<pubDate>Fri, 05 Apr 2019 02:23:42 +0500</pubDate>
<author>Bohdan Stefaniuk</author>
<comments>https://stefaniuk.website/all/db-replication/</comments>
<description>
&lt;p&gt;&lt;a href="https://stefaniuk.website/"&gt;Bohdan Stefaniuk&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;Репликация — одна из техник масштабирования баз данных. Состоит эта техника в том, что данные с одного сервера базы данных постоянно копируются (реплицируются) на один или несколько других. Для приложения появляется возможность использовать не один сервер для обработки всех запросов, а несколько. Таким образом появляется возможность распределить нагрузку с одного сервера на несколько.&lt;/p&gt;
&lt;p&gt;Существует два основных подхода при работе с репликацией данных:&lt;/p&gt;
&lt;ol start="1"&gt;
&lt;li&gt;Репликация Master-Slave;&lt;/li&gt;
&lt;li&gt;Репликация Master-Master.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Master-Slave репликация&lt;/h2&gt;
&lt;p&gt;В этом подходе выделяется один основной сервер базы данных, который называется Мастером. На нем происходят все изменения в данных (любые запросы INSERT/UPDATE/DELETE). Слейв сервер постоянно копирует все изменения с Мастера. С приложения на Слейв сервер отправляются запросы чтения данных. Таким образом Мастер сервер отвечает за изменения данных, а Слейв за чтение.&lt;/p&gt;
&lt;h2&gt;Несколько Слейвов&lt;/h2&gt;
&lt;p&gt;Преимущество этого типа репликации в том, что Вы можете использовать более одного Слейва. Обычно следует использовать не более 20 Слейв серверов при работе с одним Мастером.&lt;br /&gt;
Тогда из приложения выбирает случайным образом один из Слейвов для обработки запросов, тем самым распределяя нагрузку на БД.&lt;/p&gt;
&lt;h2&gt;Выход из строя&lt;/h2&gt;
&lt;p&gt;При выходе из строя Слейва, достаточно просто переключить все приложение на работу с Мастером. После этого восстановить репликацию на Слейве и снова его запустить.&lt;br /&gt;
Если выходит из строя Мастер, нужно переключить все операции (и чтения и записи) на Слейв. Таким образом он станет новым Мастером. После восстановления старого Мастера, настроить на нем реплику, и он станет новым Слейвом.&lt;/p&gt;
&lt;h2&gt;Master-Master репликация&lt;/h2&gt;
&lt;p&gt;В этой схеме, любой из серверов может использоваться как для чтения так и для записи.&lt;/p&gt;
&lt;h2&gt;«Ручная» репликация&lt;/h2&gt;
&lt;p&gt;Некоторые технологии вообще не имеют встроенной репликации. В таких случаях, следует использовать самостоятельную реализацию репликации. В самом простом случае, приложение будет дублировать все запросы сразу на несколько серверов базы данных.&lt;/p&gt;
&lt;h2&gt;Итог&lt;/h2&gt;
&lt;p&gt;Репликация используется в большей мере для резервирования баз данных и в меньшей для масштабирования. Master-Slave репликация удобна для распределения запросов чтения по нескольким серверам. Подход ручной репликации позволит использовать преимущества репликации для технологий, которые ее не поддерживают. Зачастую репликация используется вместе с шардингом при решении вопросов масштабирования.&lt;/p&gt;
&lt;p&gt;Следует отметить, что репликация сама по себе не очень удобный механизм масштабирования. Причиной тому — рассинхронизация данных и задержки в копировании с мастера на слейв. Зато это отличное средство для обеспечения отказоустойчивости. Вы всегда можете переключиться на слейв, если мастер ломается и наоборот. Чаще всего репликация используется совместно с шардингом именно из соображений надежности.&lt;/p&gt;
</description>
</item>


</channel>
</rss>