{
    "version": "https:\/\/jsonfeed.org\/version\/1.1",
    "title": "Блоги: заметки с тегом system-design",
    "_rss_description": "Автоматически собираемая лента заметок, написанных в блогах на Эгее",
    "_rss_language": "ru",
    "_itunes_email": "",
    "_itunes_categories_xml": "",
    "_itunes_image": false,
    "_itunes_explicit": "no",
    "home_page_url": "https:\/\/blogengine.me\/blogs\/tags\/system-design\/",
    "feed_url": "https:\/\/blogengine.me\/blogs\/tags\/system-design\/json\/",
    "icon": false,
    "authors": [
        {
            "name": "Илья Бирман",
            "url": "https:\/\/blogengine.me\/blogs\/",
            "avatar": false
        }
    ],
    "items": [
        {
            "id": "119847",
            "url": "https:\/\/stefaniuk.website\/all\/repository-pattern\/",
            "title": "Паттерн «Репозиторий»",
            "content_html": "<p>Репозиторий один из самых популярных паттернов для доступа к данным. Он используется для абстрагирования от конкретной реализации и нюансов работы с источником данных, внешних сервисов, файловой системой и т. д.<\/p>\n<p>С одной стороны, это очень простой паттерн, который позволяет скрыть сложность работы с БД. Но с другой стороны, спросите 10 программистов описать этот шаблон и вы получите 10 разных реализаций.<\/p>\n<p>Самая большая проблема этого шаблона — множество вопросов, которые возникают при его реализации и дальнейшей поддержки.<\/p>\n<p>Изначально хотел сам расписать проблемы, но за меня это уже сделали, поэтому настоятельно советую прочитать статью: <a href=\"https:\/\/blog.byndyu.ru\/2011\/01\/domain-driven-design-repository.html\">«Проблемы паттерна Репозиторий».<\/a><\/p>\n<p>Если кратно, то:<\/p>\n<ul>\n<li>Что делать если репозиториям нужно использовать закрытые методы друг друга?<\/li>\n<li>Можно ли использовать один репозиторий на весь проект или делать репозиторий на каждую сущность?<\/li>\n<li>Нужно ли дублировать методы репозитория в сервис или мы можем напрямую использовать репозиторий в контроллерах?<\/li>\n<li>Нужно ли возвращать IQueryable и как это повлияет на дизайн системы в случае с .NET кодом? Если нет, то как правильно изменять сущности без использования Change Tracking?<\/li>\n<li>Как правильно объединить репозиторий и UoW?<\/li>\n<\/ul>\n<p>Отдельно также хочу отметить доклад: <a href=\"https:\/\/www.youtube.com\/watch?v=3yPpL1rEK9o&t=1208s\">Денис Цветцих «Repository и UnitOfWork в 2020 году, must have или антипаттерн?»<\/a>. В нем также поднимаются проблемы репозитория, способы их решения и варианты замены этот шаблона на другой.<\/p>\n<p>Репозиторий — хороший паттерн, который должен быть в арсенале любого программиста, но стоит использовать его с умом и учитывать проблемы, которые он может вызвать.<\/p>\n<p>Для себя я решил что репозиторий хорошо подходит, когда вся логика приложения вписывается в CRUD модель. Но если логика более сложная или приложение подразумевает Task Base UI, тогда лучше прибегнуть к подходу CQRS. Он позволяет разбить сложную бизнес логику включая репозитории на независимые объекты, каждый из которых выполняет только одну бизнес задачу или use case.<\/p>\n<div style=\"max-width: 750px\"><div class=\"e2-text-picture\">\n<img src=\"https:\/\/stefaniuk.website\/pictures\/repository-pattern-orm-db.png\" width=\"1200\" height=\"579\" alt=\"\" \/>\n<\/div>\n<\/div><p>Я кроме все прочего не люблю репозитории за:<\/p>\n<ul>\n<li>Ограничение функциональности ORM, большенство специфических операций недоступны. В зависимости от реализации можем потерять Change Tracking.<\/li>\n<li>Дополнительный мапинг из доменных объектов в DTO.<\/li>\n<li>Дополнительный слой абстракции, который зачастую просто не нужен. Особенно если речь идет о небольших сервисах где логику нужно делать максимально простой и незамысловатой.<\/li>\n<li>Работает только в простых CRUD сценариях.<\/li>\n<\/ul>\n",
            "date_published": "2021-07-08T17:50:13+05:00",
            "date_modified": "2023-06-03T05:19:28+05:00",
            "tags": [
                "system-design",
                "код",
                "программирование"
            ],
            "author": {
                "name": "Bohdan Stefaniuk",
                "url": "https:\/\/stefaniuk.website\/",
                "avatar": "https:\/\/stefaniuk.website\/pictures\/userpic\/userpic@2x.jpg?1565716580"
            },
            "_date_published_rfc2822": "Thu, 08 Jul 2021 17:50:13 +0500",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "119847",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": null,
                "og_images": []
            }
        },
        {
            "id": "119837",
            "url": "https:\/\/stefaniuk.website\/all\/tech-documentation\/",
            "title": "Документация",
            "content_html": "<p>Ох сколько проблем вызывает документация. И зачастую эти проблемы связаны с ее отсутствием. Почти всегда разработчики считаю что написание документации это: лишнее, бюрократия, скучно. Также часто разработчики приводят в пример цитату из скрам гайда: работающий продукт важнее исчерпывающей<br \/>\nдокументации.<\/p>\n<p>Я считаю что документация в том или ином виде должна присутствовать. Зачастую ее ценность понимается не сразу, а по прошествию времени. Например так случилось и в нашей команде, когда старые разработчики ушли и новеньким было очень сложно делать экскурс по системе, а она очень большая!<\/p>\n<p>Но я против детально и огромной документации. Для себя и своих личных проектов я придерживаюсь следующего шаблона. Он достаточно компактный и простой в написании. Да это не ГОСТ, не ISO и не IEEE. Но она понятная и ее написание не занимает много времени.<\/p>\n<p>Какие проблемы я пробую решить своим шаблоном:<\/p>\n<ol start=\"1\">\n<li>Для чего нужен данный модуль или архитектура?<\/li>\n<li>Как ее использовать?<\/li>\n<li>Как вносить изменения?<\/li>\n<li>Как осуществлять диагностику или проверку состояния?<\/li>\n<li>Какие были связаны с ней проблемы?<\/li>\n<li>Какими тестами покрыто? (Проблема очень важная, так как часто при планировании изменений приходилось вспоминать\/идти проверять какими тестами покрыт функционал, что отнимало иногда много времени).<\/li>\n<\/ol>\n<h2>Шаблон документации<\/h2>\n<p><b>Назначение:<\/b> для чего нужен этот модуль, какую задачу решает?<\/p>\n<p><b>Основная задача:<\/b> ссылка на задачу в трекере в рамках которой разрабатывалась данный модуль.<\/p>\n<p><b>Диаграмма:<\/b> графическое отображение архитектуры. Позволит понять что от кого зависит и как взаимодействует с другими частями системы.<\/p>\n<p><b>Зоны ответственности:<\/b> кратко описать элементы модуля и за что они отвечают. Смысл приёма в том, чтобы явно выделить назначение класса. Идеальный результат — получить класс, который можно описать одной фразой или даже одним словом.<\/p>\n<p><b>Пример использования:<\/b> небольшой пример того как использовать данный функционал.<\/p>\n<p><b>Обработка ошибок:<\/b> как обрабатываются ошибки.<\/p>\n<p><b>Логирование:<\/b><\/p>\n<ol start=\"1\">\n<li>В какой файл пишутся логи.<\/li>\n<li>Уровни логирования и какую они могут дать информацию.<\/li>\n<\/ol>\n<p><b>Тесты:<\/b> каким типом тестов покрыта данная функциональность.<\/p>\n<p><b>FAQ: <\/b> вопросы и ответы по данной функциональности. Например: как объединить 2 объекта в сущности?<\/p>\n<p><b>Инциденты и баги:<\/b> ссылки на баги, которые были найдены в данной функциональности и исправленные.<\/p>\n<h2>Статьи по теме<\/h2>\n<ol start=\"1\">\n<li><a href=\"https:\/\/habr.com\/ru\/post\/143920\/\">Еще раз о документации<\/a>.<\/li>\n<li><a href=\"https:\/\/habr.com\/ru\/post\/303760\/\">7 правил написания технической документации мирового класса<\/a>.<\/li>\n<\/ol>\n",
            "date_published": "2019-05-09T14:22:39+05:00",
            "date_modified": "2023-06-03T05:19:07+05:00",
            "tags": [
                "system-design"
            ],
            "author": {
                "name": "Bohdan Stefaniuk",
                "url": "https:\/\/stefaniuk.website\/",
                "avatar": "https:\/\/stefaniuk.website\/pictures\/userpic\/userpic@2x.jpg?1565716580"
            },
            "_date_published_rfc2822": "Thu, 09 May 2019 14:22:39 +0500",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "119837",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": null,
                "og_images": []
            }
        },
        {
            "id": "119838",
            "url": "https:\/\/stefaniuk.website\/all\/logging\/",
            "title": "Логирование",
            "content_html": "<p>Для чего вообще нужно логирование в приложении:<\/p>\n<ol start=\"1\">\n<li>Сказать, что делать система, не прибегая к отладчику.<\/li>\n<li>Найти причины возникновения той или иной ситуации внутри приложения.<\/li>\n<li>Анализ того на что тратится больше всего ресурсов.<\/li>\n<\/ol>\n<p><b>Какие есть требования к логерам?<\/b><\/p>\n<ol start=\"1\">\n<li>Уровни логирования и фильтрация сообщений.<\/li>\n<li>Ротация лог файлов.<\/li>\n<li>Возможность писать сообщения не только в файл.<\/li>\n<li>Thread safety.<\/li>\n<li>Асинхронное логирование.<\/li>\n<li>Формат и конфигурация логов.<\/li>\n<\/ol>\n<h2>Уровни логирования<\/h2>\n<ul>\n<li><b>TRACE<\/b> — вывод всего подряд. На тот случай, если Debug не позволяет локализовать ошибку. В нем полезно отмечать вызовы разнообразных блокирующих и асинхронных операций.<\/li>\n<li><b>DEBUG<\/b> — журналирование моментов вызова «крупных» операций. Старт\/остановка потока, запрос пользователя и т. п.<\/li>\n<li><b>INFO<\/b> — обычные сообщения, информирующие о действиях системы. Реагировать на такие сообщения вообще не надо, но они могут помочь, например, при поиске багов, расследовании интересных ситуаций итд.<\/li>\n<li><b>WARNING<\/b> — нештатные ситуации. Например непредвиденные параметры, странные форматы запроса. Любая информация, которая должна привлечь внимание. Некритичные ошибки.<\/li>\n<li><b>ERROR<\/b> — ошибка в работе системы, требующая вмешательства. Что-то не сохранилось, что-то отвалилось.<\/li>\n<li><b>FATAL<\/b> — критическая ситуация, которая требует немедленной реакции. Обычно значит что система в неработоспособном состоянии. Пишем в лог все до чего можем дотянутся.<\/li>\n<\/ul>\n<p>Замечание! Никогда не отправляйте пустое исключение в лог. Так как обычно не понятно к чему принадлежит этот стэк-трейс, как программа отреагировала на ошибку. Чтобы избежать этого, в дополнение к трейсам  прикладывайте и сообщение, которое обьясняет что именно произошло.<\/p>\n<h2>Интересные статьи на тему<\/h2>\n<ol start=\"1\">\n<li><a href=\"https:\/\/habr.com\/ru\/post\/135242\/\">Архитектура логирования<\/a>.<\/li>\n<li><a href=\"http:\/\/www.thekua.com\/atwork\/2008\/11\/application-logging-principles\/\">Application logging principles<\/a>.<\/li>\n<\/ol>\n",
            "date_published": "2019-04-29T22:58:18+05:00",
            "date_modified": "2023-06-03T05:19:14+05:00",
            "tags": [
                "system-design"
            ],
            "author": {
                "name": "Bohdan Stefaniuk",
                "url": "https:\/\/stefaniuk.website\/",
                "avatar": "https:\/\/stefaniuk.website\/pictures\/userpic\/userpic@2x.jpg?1565716580"
            },
            "_date_published_rfc2822": "Mon, 29 Apr 2019 22:58:18 +0500",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "119838",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": null,
                "og_images": []
            }
        },
        {
            "id": "119854",
            "url": "https:\/\/stefaniuk.website\/all\/sharding\/",
            "title": "Шардинг",
            "content_html": "<p>Шардинг (иногда шардирование) — это другая техника масштабирования работы с данными. Суть его в разделении (партиционирование) базы данных на отдельные части так, чтобы каждую из них можно было вынести на отдельный сервер. Этот процесс зависит от структуры базы данных и выполняется прямо в приложении в отличие от репликации<\/p>\n<h2>Вертикальный шардинг<\/h2>\n<p>Вертикальный шардинг — это выделение таблицы или группы таблиц на отдельный сервер. Например, в приложении есть такие таблицы:<\/p>\n<ul>\n<li><i>users<\/i> — данные пользователей<\/li>\n<li><i>photos<\/i> — фотографии пользователей<\/li>\n<li><i>albums<\/i> — альбомы пользователей<\/li>\n<\/ul>\n<p>Таблицу users Вы оставляете на одном сервере, а таблицы <i>photos<\/i> и <i>albums<\/i> переносите на другой. В таком случае в приложении Вам необходимо будет использовать соответствующее соединение для работы с каждой таблицей<\/p>\n<h2>Горизонтальный шардинг<\/h2>\n<p>Горизонтальный шардинг — это разделение одной таблицы на разные сервера. Это необходимо использовать для огромных таблиц, которые не умещаются на одном сервере. Разделение таблицы на куски делается по такому принципу:<\/p>\n<ul>\n<li>На нескольких серверах создается одна и та же таблица (только структура, без данных).<\/li>\n<li>В приложении выбирается условие, по которому будет определяться нужное соединение (например, четные на один сервер, а нечетные — на другой).<\/li>\n<li>Перед каждым обращением к таблице происходит выбор нужного соединения.<\/li>\n<\/ul>\n<h2>Совместное использование<\/h2>\n<p>Шардинг и репликация часто используются совместно. В нашем примере, мы могли бы использовать по два сервера на каждый шард таблицы<\/p>\n<h2>Key-value базы данных<\/h2>\n<p>Следует отметить, что большинство Key-value баз данных поддерживает шардинг на уровне платформы. Например, Memcache. В таком случае, Вы просто указываете набор серверов для соединения, а платформа сделает все остальное<\/p>\n<h2>Итог<\/h2>\n<p>Не следует применять технику шардинга ко всем таблицам. Правильный подход — это поэтапный процесс разделения растущих таблиц. Следует задумываться о горизонтальном шардинге, когда количество записей в одной таблице переходит за пределы от нескольких десятков миллионов до сотен миллионов.<\/p>\n<h2>P.S.<\/h2>\n<p>Помните, процесс масштабирования данных — это архитектурное решение, оно не связано с конкретной технологией. Не делайте ошибок наших отцов — не переезжайте с известной Вам технологии на новую из-за поддержки или не поддержки шардинга. Проблемы обычно связаны с архитектурой, а не конкретной базой данных<\/p>\n<h2>Ссылки<\/h2>\n<ol start=\"1\">\n<li><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\">Вертикальный шардинг<\/a><\/li>\n<li><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\">Шардинг и репликация<\/a><\/li>\n<\/ol>\n",
            "date_published": "2019-04-05T02:26:34+05:00",
            "date_modified": "2023-06-03T05:29:59+05:00",
            "tags": [
                "system-design",
                "бази даних"
            ],
            "author": {
                "name": "Bohdan Stefaniuk",
                "url": "https:\/\/stefaniuk.website\/",
                "avatar": "https:\/\/stefaniuk.website\/pictures\/userpic\/userpic@2x.jpg?1565716580"
            },
            "_date_published_rfc2822": "Fri, 05 Apr 2019 02:26:34 +0500",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "119854",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": null,
                "og_images": []
            }
        },
        {
            "id": "119853",
            "url": "https:\/\/stefaniuk.website\/all\/db-replication\/",
            "title": "Репликация данных",
            "content_html": "<p>Репликация — одна из техник масштабирования баз данных. Состоит эта техника в том, что данные с одного сервера базы данных постоянно копируются (реплицируются) на один или несколько других. Для приложения появляется возможность использовать не один сервер для обработки всех запросов, а несколько. Таким образом появляется возможность распределить нагрузку с одного сервера на несколько.<\/p>\n<p>Существует два основных подхода при работе с репликацией данных:<\/p>\n<ol start=\"1\">\n<li>Репликация Master-Slave;<\/li>\n<li>Репликация Master-Master.<\/li>\n<\/ol>\n<h2>Master-Slave репликация<\/h2>\n<p>В этом подходе выделяется один основной сервер базы данных, который называется Мастером. На нем происходят все изменения в данных (любые запросы INSERT\/UPDATE\/DELETE). Слейв сервер постоянно копирует все изменения с Мастера. С приложения на Слейв сервер отправляются запросы чтения данных. Таким образом Мастер сервер отвечает за изменения данных, а Слейв за чтение.<\/p>\n<h2>Несколько Слейвов<\/h2>\n<p>Преимущество этого типа репликации в том, что Вы можете использовать более одного Слейва. Обычно следует использовать не более 20 Слейв серверов при работе с одним Мастером.<br \/>\nТогда из приложения выбирает случайным образом один из Слейвов для обработки запросов, тем самым распределяя нагрузку на БД.<\/p>\n<h2>Выход из строя<\/h2>\n<p>При выходе из строя Слейва, достаточно просто переключить все приложение на работу с Мастером. После этого восстановить репликацию на Слейве и снова его запустить.<br \/>\nЕсли выходит из строя Мастер, нужно переключить все операции (и чтения и записи) на Слейв. Таким образом он станет новым Мастером. После восстановления старого Мастера, настроить на нем реплику, и он станет новым Слейвом.<\/p>\n<h2>Master-Master репликация<\/h2>\n<p>В этой схеме, любой из серверов может использоваться как для чтения так и для записи.<\/p>\n<h2>«Ручная» репликация<\/h2>\n<p>Некоторые технологии вообще не имеют встроенной репликации. В таких случаях, следует использовать самостоятельную реализацию репликации. В самом простом случае, приложение будет дублировать все запросы сразу на несколько серверов базы данных.<\/p>\n<h2>Итог<\/h2>\n<p>Репликация используется в большей мере для резервирования баз данных и в меньшей для масштабирования. Master-Slave репликация удобна для распределения запросов чтения по нескольким серверам. Подход ручной репликации позволит использовать преимущества репликации для технологий, которые ее не поддерживают. Зачастую репликация используется вместе с шардингом при решении вопросов масштабирования.<\/p>\n<p>Следует отметить, что репликация сама по себе не очень удобный механизм масштабирования. Причиной тому — рассинхронизация данных и задержки в копировании с мастера на слейв. Зато это отличное средство для обеспечения отказоустойчивости. Вы всегда можете переключиться на слейв, если мастер ломается и наоборот. Чаще всего репликация используется совместно с шардингом именно из соображений надежности.<\/p>\n",
            "date_published": "2019-04-05T02:23:42+05:00",
            "date_modified": "2023-06-03T05:29:49+05:00",
            "tags": [
                "system-design",
                "бази даних"
            ],
            "author": {
                "name": "Bohdan Stefaniuk",
                "url": "https:\/\/stefaniuk.website\/",
                "avatar": "https:\/\/stefaniuk.website\/pictures\/userpic\/userpic@2x.jpg?1565716580"
            },
            "_date_published_rfc2822": "Fri, 05 Apr 2019 02:23:42 +0500",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "119853",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": null,
                "og_images": []
            }
        }
    ],
    "_e2_version": 4079,
    "_e2_ua_string": "Aegea 11.0 (v4079e)"
}