IT-инфраструктура для бизнеса и творчества
Разработка
red_mad_robot

Очень технический выпуск: про DDD и проектирование сложных систем

В свежем выпуске подкаста «Сушите вёсла» обсудили методологии проектирования сложных систем. Много говорили о Domain Driven Design, Event Sourcing и CQRS. Тема непростая, но, как говорится, очень интересная.

Артём Кулаков и Рома Чорыев — разработчики Redmadrobot, они записывают подкаст, где обсуждают различные стороны создания ИТ-продуктов. Ниже ссылка на новый выпуск, тайминг и ответы на душещипательные вопросы. Но для начала небольшой дисклеймер:

Почему все больше и больше ведется разговоров о различных аспектах и методологиях проектирования систем? Потому что наши системы стали действительно большими. Чтобы разобраться, как проектировать такие системы, мы позвали Алексея Мерсона — системного архитектора из Karuna. В выпуске попробовали разобраться, что такое Domain Driven Design, как он связан с Event Sourcing и при чем тут CQRS и микросервисы. Снять удалось только первый слой, да и то неравномерно. Но всем, кто хочет начать погружаться в тему, этот выпуск будет несомненно полезен. И обязательно ознакомьтесь с материалами к выпуску.

Артём Кулаков

архитектор Redmadrobot

Тайминг

02:29 — Гость студии Алексей Мерсон и как он начинал;

05:02 — .Net и DDD;

12:26 — почему сейчас все чаще говорят о DDD;

15:30 — полезная литература о DDD;

23:01 — как начать проектировать систему по DDD;

25:05 — Event storming и Miro;

45:15 — что такое Event sourcing;

55:00 — CQRS и его связь с DDD и Event sourcing;

01:06:10 — с чего начать.

DDD — что это и почему сейчас?

Domain-Driven Design — предметно-ориентированное проектирование. Понятие известно давно, но в последнее время в русскоязычном сообществе о нем говорят всё чаще.

Алексей считает, что возможно, это связано с тем, в Agile-мире запускаются проекты, которые без применения DDD «скатятся в печальное состояние», потому что появится расхождение между предметной областью и реализацией.

В первую очередь Domain-Driven Design — это история о проектировании, и предметная область в нем ставится во главу угла. И основной акцент в этом подходе делается на взаимодействии с бизнесом — с заказчиками ПО и приложений.

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

Как спроектировать сложную систему с нуля?

В студии прозвучал резонный вопрос: «представим, что мы поняли, что у нас сложная система, которую будем делать по DDD и у нас на это даже есть много времени. С чего стоит начать?» Алексей дал несколько советов.

Первое — конечно же, придется стартовать с MVP, то есть с «маленьких кусочков», которые затем будут «разрастаться» во что-то большее. Второе — понять процессы, которые нужно автоматизировать. При этом важно находиться в контакте с теми, кто ставит задачи. Например, с продактами или с кем-то из бизнеса, топ-менеджерами. Дальше — расписать сценарии таким образом, чтобы стал понятен контекст, в котором существуют заданные бизнес-процессы.

И, кстати, многие для этих целей используют системой Event storming — это такой способ собрать разработчиков и бизнес-экспертов в одном месте, чтобы вместе исследовать предстоящую разработку.

В Event Storming собираются все заинтересованные лица и на доске с помощью стикеров выстраивают последовательность событий и тех объектов, которые генерируют эти события. Получается некая визуальная карта, в которой становится понятно, как взаимодействуют различные сущности и как они объединяются в контексты.

Алексей Мерсон
системный архитектор Karuna
Event Storming — фото Daniel Gomes

Изначально активность проводили офлайн, но сейчас подобное можно спокойно провести онлайн, например, в Miro.

Event Sourcing (не путать с Event storming)

Event Sourcing — еще одна популярная сегодня тема. Это архитектурный шаблон, упоминание которого часто всплывает в связи с DDD.

На самом деле, связаны они косвенно, и прямой зависимости между ними нет — дело в том, что Event Storming помогает генерировать события, которые можно потом переложить в Event Sourcing архитектуру. В общем, в студии попытались разобраться, почему об Event Sourcing говорят.

Недавно в сообществе SpbDotNet был митап, где рассказывали о том, как одна команда применяла Event Sourcing. Они применяли его в приложении, которое реализовывало аукционы. Там есть ставки, и они, по сути, являются событиями, которые конкурируют: важно, в какой момент каждое из них произошло, важно получить из них правильную последовательность, чтобы понять конечный статус агрегата, например, лота или аукциона. И в этой ситуации Event Sourcing вполне оправдан.

Алексей Мерсон
системный архитектор Karuna

Но иногда случается, что Event Sourcing — это просто ненужное усложнение процесса. Ведь его легко сделать неправильно и очень сложно сделать правильно, потому что в нем есть много мест, где можно «свернуть не туда».

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

Подробнее обо всём начинается с 45:15

CQRS — yay or nay?

Ребята обсудили, что CQRS — это, скорее, паттерн, применяемый в технической области. Связан ли CQRS и DDD?

DDD больше заточено на side effects и изменения, а CQRS больше относится к отображению. И это его качество, как раз, применяется в Event Sourcing, потому что фактически есть только набор ивентов, а показывать, как правило, нужно данные, состояния объектов. А для того чтобы данные эти получить, нужно из ивентов делать проекции. В общем, если смотреть на CQRS под этим углом, получается история о синхронном взаимодействии с точки зрения UI/UX.

Подробное обсуждение этого непростого вопроса — с 55:00.

Где и как научиться всему этому? (желательно до выхода на пенсию)

Алексей посоветовал начать с его доклада. Он подметил, что «для того и рассказывал, чтобы дать интро по теме».

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

Можно ещё подписаться на сообщество DDDevotion и спросить там обо всем, что интересует. Подписчики могут проконсультировать в самых разных вопросах. Например, как применять DDD в PHP, а также в других стэках.

Под конец разговора Рома ещё задал интересный вопрос: «Kакая проблема должна стоять перед разработчиком, чтобы он понял, что пришло время углубиться в DDD?» Если коротко, то сложно ответить коротко :)

А подробно рассказали с 1:10:00.

Полезные материалы

Предыдущие выпуски подкаста «Сушите вёсла»

Слушайте нас там, где удобно: Soundcloud, Apple Podcasts, Google Podcasts

Давайте обсудим выпуск в Telegram-чате.

{ "author_name": "red_mad_robot", "author_type": "editor", "tags": ["\u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435","\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f","\u043f\u043e\u0434\u043a\u0430\u0441\u0442\u044b","\u0438\u043d\u0442\u0435\u0440\u0432\u044c\u044e","redmadrobot","karuna","ddd"], "comments": 0, "likes": 14, "favorites": 34, "is_advertisement": false, "subsite_label": "dev", "id": 208975, "is_wide": true, "is_ugc": false, "date": "Mon, 15 Feb 2021 16:10:00 +0300", "is_special": false }
(function () { let cdnUrl = `https://specialsf378ef5-a.akamaihd.net/SelectelBranding/images/` let previousArticleNumber = null let currentArticleNumber = 0 let platform = 'Desktop' let articles = [ { name: 'camera', url: `${cdnUrl}CameraCat`, text: 'умную камеру для\u00A0наблюдения за\u00A0котиками', link: 'https://vc.ru/selectel/306690', num: 3 }, { name: 'chill', url: `${cdnUrl}ChillCat`, text: 'трекер, который подскажет, когда пора отдохнуть', link: 'https://vc.ru/promo/288561-eye-tracker', num: 1 }, { name: 'cloud', url: `${cdnUrl}CloudCat`, text: 'котика: даёшь ему «пять», а\u00A0он делает бэкап в облако', link: 'https://vc.ru/dev/294799-maneki-neko', num: 2 } ] let buttonCycle = document.querySelector('.button--cycle') let buttonChoose = document.querySelector('.button--choose') let buttonMobile = document.querySelector('.button--mobile') let textField = document.querySelector('.selectel-footer-subtitle') let imageAgent = document.querySelector('.image--agent') let banner = document.querySelector('.selectel-footer') buttonCycle.addEventListener('click', cycleClick) buttonChoose.addEventListener('click', () => sendEvent(`Promo ${articles[currentArticleNumber].num} Left`, 'Click')) buttonMobile.addEventListener('click', () => sendEvent(`Promo ${articles[currentArticleNumber].num} Left`, 'Click')) let media = window.matchMedia("(max-width: 570px)") media.addEventListener('change', matchMedia) function matchMedia() { if (media.matches) { platform = 'Mobile' } else { platform = 'Desktop' } update() } matchMedia() function cycleClick(event) { sendEvent(`Promo ${articles[currentArticleNumber].num} Right`, 'Click') if (event) { event.preventDefault() event.stopPropagation() } window.open('https://vc.ru/tag/selectelDIY', '_blank') //cycle(event) } function cycle(event) { // incrementArticleNumber() textField.innerHTML = generatedText() imageAgent.src = articles[currentArticleNumber].url + platform + '.svg?3' imageAgent.setAttribute("class", "") imageAgent.classList.add('image--agent', articles[currentArticleNumber].name) banner.href = articles[currentArticleNumber].link } function update() { banner.href = articles[currentArticleNumber].link imageAgent.src = articles[currentArticleNumber].url + platform + '.svg' textField.innerHTML = generatedText() } function incrementArticleNumber() { previousArticleNumber = currentArticleNumber if (currentArticleNumber >= articles.length - 1) { currentArticleNumber = 0 } else { currentArticleNumber++ } } const sendEvent = (label, action = 'Click') => { const value = `SelectelDIY — loc: Footer — ${label} — ${action}`; if (window.dataLayer !== undefined) { window.dataLayer.push({ event: 'data_event', data_description: value, }); } }; function generatedText() { let defaultText if (platform === 'Desktop') { defaultText = `Мы тут собрали %text%. Хотите научим?` } else { defaultText = `Мы тут собрали %text%.` } return defaultText.replace('%text%', articles[currentArticleNumber].text) } function getRandom(min, max) { min = Math.ceil(min) max = Math.floor(max) return Math.floor(Math.random() * (max - min + 1)) + min } (function create() { currentArticleNumber = getRandom(0, articles.length - 1) cycle() let page = document.querySelector('.page--entry') if (page) { function insertAfter() { let parents = page.querySelectorAll('[data-id="7"]') let referenceNode = parents[0] referenceNode.parentNode.insertBefore(banner, referenceNode.nextSibling); loaded() } setTimeout(() => insertAfter(), 0) } }()) function loaded() { banner.classList.add('loaded') } loadImages([ `${cdnUrl}CameraCatDesktop.svg`, `${cdnUrl}ChillCatDesktop.svg`, `${cdnUrl}CloudCatDesktop.svg`, `${cdnUrl}CameraCatMobile.svg`, `${cdnUrl}ChillCatMobile.svg`, `${cdnUrl}CloudCatMobile.svg?3`, ]) function loadImages(urls) { return Promise.all(urls.map(function (url) { return new Promise(function (resolve) { var img = document.createElement('img'); img.onload = resolve; img.onerror = resolve; img.src = url; }); })); } }())
0
0 комментариев
Популярные
По порядку
Читать все 0 комментариев
Почему индексные фонды стали популярными. Рассказывает персональный брокер
Adobe представила веб-версии Photoshop и Illustrator с ограниченными возможностями для совместной работы Статьи редакции

Пользователи смогут вместе работать над проектом, не открывая и не скачивая десктопные приложения. Подписка Creative Cloud для просмотра не нужна.

Что означает выражение «цена на нефть»

Что есть «мировые цены на нефть», о которых говорится в СМИ, где они формируются и почему нефтяные бенчмарки зачастую не являются в строгом смысле ценами на нефть.

Как программист-интроверт стал СЕО стартапа, сделал MVP за один месяц и заработал 12 млн за год – история Revvy

SaaS-сервис Revvy, который помогает бизнесу общаться с клиентами и умеет «перехватывать» негатив.

Пример позитивного отзыва и “перехвата” негатива
Как имиджевый проект о безопасном вождении привлёк лиды и расширил маркетинговую воронку страховой компании

А игра с виртуальной фарфоровой статуэткой помогла 6,5 тысячам водителей не превышать скорость.

На OZON.ru для оплаты предлагаются чужие банковские карты

Сегодня вечером я разместил заказ на OZON.ru, перешел к оплате и обнаружил сохраненную карту, чему я несколько удивился, т.к. обычно их нигде не сохраняю. Тем не менее, я ввёл CVV код и перешел к подтверждению платежа. Но push и смс от банка упорно не приходили. Я вернулся на шаг назад и понял, что OZON предлагает оплатить мой заказ неизвестной…

Здоровый сон взрослого человека — это засыпать за 15 минут и не вставать ночью попить и пописать

Послушала на днях 2х-часовое выступление «Здоровый сон» врача-невролога, сомнолога Елены Царевой. Самые важные поинты 1 минуту чтения:

«2ГИС» представил обновлённый навигатор с мини-картой на экране, данными о камерах и парковках Статьи редакции

Его уже подключил «Ситимобил».

Обновлённый интерфейс навигатора  «2ГИС»
Волна «Кальмара»: как бренды прокатились на тренде и какие выводы можно сделать маркетологам

С выхода южнокорейского сериала «Игра в кальмара» прошёл месяц. Шумиха вокруг него утихает, и можно подводить итоги.

Онлайн-кинотеатр IVI объявил дату премьеры сериала «Везёт» с Евгением Цыгановым​
null