<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Nikolay Fominykh</title>
    <description>The latest articles on DEV Community by Nikolay Fominykh (@tigrus).</description>
    <link>https://dev.to/tigrus</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F398376%2F097a7938-1977-47dd-9369-5b0d5cf81df4.jpeg</url>
      <title>DEV Community: Nikolay Fominykh</title>
      <link>https://dev.to/tigrus</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/tigrus"/>
    <language>en</language>
    <item>
      <title>Где же ты, DDD? </title>
      <dc:creator>Nikolay Fominykh</dc:creator>
      <pubDate>Sun, 09 May 2021 22:53:36 +0000</pubDate>
      <link>https://dev.to/tigrus/ddd-25co</link>
      <guid>https://dev.to/tigrus/ddd-25co</guid>
      <description>&lt;p&gt;..Так получилось, что меня зацепила мысль об использовании DDD. Более того, я даже проинвестировал львиную долю своего и чужого времени в эту тему. &lt;/p&gt;

&lt;p&gt;Но что-то идет не так. Написав с десяток репозиториев, сотню сущностей - ощущения ясности не приходит, каменный цветок не выходит. &lt;/p&gt;

&lt;p&gt;Одна из причин - перерабатывать творчество Эванса и Вернона сложно, курсы Хорикова на pluralsight хоть и классные, но как-то про .NET... Вообще, создается впечатление &lt;del&gt;что в СССР секса нет&lt;/del&gt; что за пределами .NET и Java - DDD не возможен. &lt;/p&gt;

&lt;p&gt;И разные &lt;a href="https://github.com/valignatev/ddd-dynamic" rel="noopener noreferrer"&gt;awesome листы&lt;/a&gt; как раз это подтверждают. Создается стойкое впечатление, что идея классная, книжки крутые по теме написаны, а взять и использовать - невозможно! &lt;/p&gt;

&lt;p&gt;Давайте внезапно возьмем статью про &lt;a href="https://vaadin.com/learn/tutorials/ddd/strategic_domain_driven_design" rel="noopener noreferrer"&gt;Стратегический DDD&lt;/a&gt; и помедитируем на нее. &lt;/p&gt;

&lt;p&gt;Слово &lt;strong&gt;домен&lt;/strong&gt;, само по себе переводится очень плохо и русскому уху скорее напоминает про интернет серфинг. К коему неминуемо хочется прибегнуть, каждый раз встречая это слово. Переводить его как &lt;strong&gt;предмет&lt;/strong&gt; - лишний раз вспоминать про школу. &lt;strong&gt;Предметная область&lt;/strong&gt; - отличное словосочетание для того, чтобы вставить его в заголовок скачанного из интернета реферата. Есть понятное слово - &lt;strong&gt;тема&lt;/strong&gt;. &lt;/p&gt;

&lt;h2&gt;
  
  
  Как моделировать тему?
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Если перевести domain еще можно, то subdomain - совсем жесть&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;Для начала тему надо подробить на &lt;del&gt;БДСМ-&lt;/del&gt;практики. Целиком ее объять невозможно. Только Йода постиг тему полностью и теперь жмет это знание и передает его ученикам по частям. &lt;/p&gt;

&lt;p&gt;Понять, что у нас практикует клиент - сложно. Он обычно говорит на своем языке. Но все же, выделить из речи одно - два предложения и перевести с непонятного на технический - можно. А еще в ходе бесед с клиентом нужно найти &lt;strong&gt;общий язык&lt;/strong&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;/ul&gt;

&lt;p&gt;На примере сервиса для сдачи анализов можно определить практики как следующие: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0asb0vj46h83fwd24kl5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0asb0vj46h83fwd24kl5.png" alt="Иллюстрация"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
  Исходник PlantUML
  &lt;br&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@startuml
("основное" \n Записи Пациента) as P 
("поддержка" \n Расписание) as S 
("поддержка" \n Лаборатория) as L 
("общее" \n Авторизация Пользователей) as A 
("общее" \n Загрузка Файлов) as F 

P -u-&amp;gt; F
P -d-&amp;gt; S
P -d-&amp;gt; L 
L -&amp;gt; F
P -d-&amp;gt; A
L -d-&amp;gt; A 
S -d-&amp;gt; A
@enduml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Основная - практика с которой организация получает основной доход. Пациент к нам приходит и сдает анализы - ему важен результат. &lt;/p&gt;

&lt;p&gt;Поддерживающая - необходима для осуществления основной. Нам материал, который пациент сдал - нужно прогнать через лабораторию и получить этот самый результат. А еще прикольно избегать очередей - для этого потребуется &lt;del&gt;вести журнал усилиями бабушки-вахтерши&lt;/del&gt; создать сервис для планирования временных слотов. &lt;/p&gt;

&lt;p&gt;Общая - то что делают все. Загрузка файлов, сервис с пользователями и прочее. &lt;/p&gt;

&lt;h2&gt;
  
  
  Отделяем мух от котлет - от проблем к решениям
&lt;/h2&gt;

&lt;p&gt;Знание темы и практик в лучшем случае даст нам понимание проблем бизнеса. Но при этом для решения этих проблем - нужно общаться дальше. &lt;/p&gt;

&lt;p&gt;Решения проблем нам дадут эксперты - но прежде необходимо выработать общий с ними язык. С этого момента, все технические решения должны легко переводиться на язык экспертов. &lt;/p&gt;

&lt;p&gt;Естественно в организации существуют разные эксперты с разными знаниями. Эти знания нужно ограничить. Ограничение знаний эксперта и перевод их с экспертного языка на общий - как раз и дает нам ограниченный контекст. &lt;/p&gt;

&lt;p&gt;Теперь немного совы. Контексты между собой взаимодействуют. Поэтому хорошо создать карту их взаимодействия. &lt;a href="https://miro.com/app/board/o9J_lSxQSq4=/" rel="noopener noreferrer"&gt;Примеры - тут&lt;/a&gt;. Главное - не надо кидаться эту карту рисовать. Создаем сначала контексты, потом их объединяем, когда их станет больше трех :) &lt;/p&gt;

&lt;h3&gt;
  
  
  Промежуточный итог
&lt;/h3&gt;

&lt;p&gt;Моделировать тему важно. Это позволит: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Найти ограничения в контекстах. &lt;/li&gt;
&lt;li&gt;Избежать построения супер-моделей, которые превращают любую систему в кошмар. &lt;/li&gt;
&lt;li&gt;Понять, что мы &lt;del&gt;спасаем мир&lt;/del&gt; решаем проблемы конкретной организации, а не просто пишем код. &lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Тактика
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Мы берем и непринужденно заходим в медитацию над &lt;a href="https://vaadin.com/learn/tutorials/ddd/tactical_domain_driven_design" rel="noopener noreferrer"&gt;следующей статьей&lt;/a&gt;.. Река течет, вода льется - давайте ловить рыбу&lt;/em&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;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Данная фраза звучит уже внутри темы "Аптека", задав контекст "Назначение препаратов". При этом "Назначение" - это главная фишка, которая интересует эксперта. Ее в DDD называют "Корень Агрегата" - абракадабра, над которой нужно медитировать пару лет, если честно. И хоть и &lt;a href="https://habr.com/ru/company/dododev/blog/532628/" rel="noopener noreferrer"&gt;появляются статьи&lt;/a&gt;, которые делают эту штуку понятнее - но по классическим трудам эту штука не очень интуитивна. &lt;/p&gt;

&lt;p&gt;Когда встречаются эти мысли про агрегаты, сущность, объект-значение и прочее - хочется выть. Можно проработать с десяток  лет в индустрии и писать всю карьеру обычные модели, да заворачивать их в CRUD. Осознание новых понятий приходит не сразу. Но зато потом - "Я не понимал, не понимал, и вдруг как понял!".. &lt;/p&gt;

&lt;p&gt;Итак, давайте сразу попробуем записать агрегат. Да еще и не на Java, а на Python. Зацепив pydantic.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pydantic&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BaseModel&lt;/span&gt;


&lt;span class="n"&gt;PatientId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;NewType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;PatientId&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;PrescriptionId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;NewType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;PrescriptionId&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Patient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BaseModel&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Данные о пациенте:
    - имя
    - фамилия
    - телефон для связи
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;patient_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;PatientId&lt;/span&gt;
    &lt;span class="n"&gt;first_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; 
    &lt;span class="n"&gt;last_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; 
    &lt;span class="n"&gt;phone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ActiveComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BaseModel&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Действующее вещество: 
    - Название 
    - Единицы измерения 
    - Количество
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; 
    &lt;span class="n"&gt;unit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; 
    &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Medicine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BaseModel&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Коммерческий препарат. 

    - Название 
    - Действующее вещество
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; 
    &lt;span class="n"&gt;active_component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ActiveComponent&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Prescription&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BaseModel&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; 
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Назначение

    - Пациент 
    - Список препаратов
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;prescription_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;PrescriptionId&lt;/span&gt;
    &lt;span class="n"&gt;assign_date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Date&lt;/span&gt;
    &lt;span class="n"&gt;patient&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Patient&lt;/span&gt;
    &lt;span class="n"&gt;medicine&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Medicine&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Является ли "Назначение" агрегатом? И да, и нет. Обратите внимание, в рамках моделирования - нам не обязательно прикреплять id ко всем сущностям. Достаточно только к ключевым, а ими тут являются "Назначение" и "Пациент". Сами препараты - мы должны жестко зафиксировать в "Назначении". &lt;/p&gt;

&lt;p&gt;Назначение пока что представляет собой анемичную модель. Видно, что без внешнего воздействия - ничего с ним не сделать. &lt;/p&gt;

&lt;p&gt;Давайте его оживим:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Prescription&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BaseModel&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; 
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Назначение

    - Пациент 
    - Список препаратов
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;prescription_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;PrescriptionId&lt;/span&gt;
    &lt;span class="n"&gt;assign_date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Date&lt;/span&gt;
    &lt;span class="n"&gt;patient_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;PatientId&lt;/span&gt;
    &lt;span class="n"&gt;medicines&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Medicine&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;add_medicine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;medicine&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; 
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;medicines&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;medicine&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_patient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;patient_repository&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IPatientRepository&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;patient_repository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;patient_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_alternative_medicines&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;medicine_repository&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IMedicineRepository&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;medicine&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;medicines&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; 
            &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="n"&gt;medicine_repository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_by_active_component_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;medicine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;active_component&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Стало поживее, одновременно передача репозиториев внутрь агрегата - спорная тема. А получение списка альтернативных препаратов - выглядит совсем кошмарно. Но это лишь для того, чтобы подумать о &lt;a href="https://enterprisecraftsmanship.com/posts/domain-model-purity-completeness/" rel="noopener noreferrer"&gt;трилемме DDD&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;/ul&gt;

&lt;p&gt;Остаются открытыми вопросы: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;А пациент точно должен фигурировать в назначении? Он не из другого контекста? &lt;/li&gt;
&lt;li&gt;А если мы склеим пациентов с назначениями через сервис - это DDD или уже нет? &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;И я их не закрою :) &lt;/p&gt;

&lt;h3&gt;
  
  
  Полезные правила при дизайне агрегатов:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Агрегаты должны быть небольшими. Это объект, который можно выгрузить в память целиком и система при этом не пострадает. &lt;/li&gt;
&lt;li&gt;К другим агрегатам и сущностям из агрегата нужно ссылаться через Id. &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;em&gt;Все помнят анекдот - "Чем круче джип - тем дальше идти за трактором". Не многие скорбят о тех, кто трактор не нашел.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;С агрегатами все хорошо, до тех пор пока не требуется взаимодействие между ними и их не становится 100500. &lt;/p&gt;

&lt;p&gt;Как только пациенту становится интересно о том, что в назначение добавлен новый препарат - карточный домик рушится. &lt;/p&gt;

&lt;p&gt;Давайте попробуем напрямую сказать пациенту о том, что новые супер-таблетки появились в назначении:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Prescription&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BaseModel&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; 
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Назначение

    - Пациент 
    - Список препаратов
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;prescription_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;PrescriptionId&lt;/span&gt;
    &lt;span class="n"&gt;assign_date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Date&lt;/span&gt;
    &lt;span class="n"&gt;patient_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;PatientId&lt;/span&gt;
    &lt;span class="n"&gt;medicines&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Medicine&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;add_medicine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;medicine&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;patient_repository&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; 
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;medicines&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;medicine&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;patient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_patient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;patient_repository&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;patient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;notify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;medicine&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_patient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;patient_repository&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IPatientRepository&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;patient_repository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;patient_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Метод &lt;strong&gt;add_medicine&lt;/strong&gt; стал выглядеть совсем больно, не так ли? Давайте уберем боль:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PrescriptionEventType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;enum&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Enum&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;MEDICINE_ADDED&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PrescrtionEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BaseModel&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;PrescriptionEventType&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;



&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Prescription&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BaseModel&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; 
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Назначение

    - Пациент 
    - Список препаратов
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;prescription_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;PrescriptionId&lt;/span&gt;
    &lt;span class="n"&gt;assign_date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Date&lt;/span&gt;
    &lt;span class="n"&gt;patient_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;PatientId&lt;/span&gt;
    &lt;span class="n"&gt;medicines&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Medicine&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;PrescrtionEvent&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;add_medicine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;medicine&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; 
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;medicines&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;medicine&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;PrescrtionEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;PrescriptionEventType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MEDICINE_ADDED&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; 
                &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;patient&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;patient_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;medicine&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;medicine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Итак, события вынесены в лог. А кто его будет читать? По хорошему - любая штука, которая использует агрегат. В python есть множество имплементаций в эту сторону, от развесистого &lt;a href="https://eventsourcing.readthedocs.io/" rel="noopener noreferrer"&gt;event sourcing&lt;/a&gt; до плотно завязанных на иные паттерны решений. В книге cosmic python - целая половина книги про &lt;a href="https://www.cosmicpython.com/book/part2.html" rel="noopener noreferrer"&gt;события&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Интуитивно подскажу следующее: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Посмотрите как события &lt;a href="https://docs.microsoft.com/en-us/dotnet/architecture/microservices/microservice-ddd-cqrs-patterns/domain-events-design-implementation" rel="noopener noreferrer"&gt;реализованы в .NET&lt;/a&gt; и возможно это поможет. &lt;/li&gt;
&lt;li&gt;В 2021м году - искать готовые удобные библиотеки в python для DDD не надо. Их нет. &lt;/li&gt;
&lt;li&gt;Решение вида:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;fastapi&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BackgroundTasks&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;FastAPI&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;FastAPI&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;handle_prescription_event&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prescription_event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;PrescriptionEvent&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;prescription_event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;PrescriptionEventType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MEDICINE_ADDED&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; 
        &lt;span class="bp"&gt;...&lt;/span&gt;

&lt;span class="nd"&gt;@app.post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/add_medicine/{prescription_id}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;add_medicine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;medicine&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Medicine&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prescription_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;PrescriptionId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;background_tasks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;BackgroundTasks&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;prescription&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;prescription_service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_prescription&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prescription_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;prescription&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_medicine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;medicine&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;prescription_service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prescription&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;prescription&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; 
        &lt;span class="n"&gt;background_tasks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;handle_prescription_event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;medicine_added&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;вполне себе работает. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Используя свойство оптимистичности агрегатов - можно немного расслабиться по поводу проблем с конкурентностью событий. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Я не уверен, на каком именно параграфе данной статьи убежал эксперт по теме. Но давайте заглянем дальше, туда, куда ему точно смотреть не стоит. &lt;/p&gt;

&lt;p&gt;Итак, есть вещи которые при беседе с экспертом можно упоминать, но в детали лучше не вдаваться, а именно: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Репозитории. Это слово можно использовать вместо базы данных. А можно использовать "база данных" вместо "репозиторий" - и это будет продуктивнее. Еще можно попробовать слово "хранилище". Цель этого понятия простая - мы достаем агрегат в помощью хранилища и после работы с ним - кладем его обратно в хранилище. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Выглядит репозиторий примитивно:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;IPatientRepository&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;object&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_patient_by_phone&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;phone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; 
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;NotADirectoryError&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_patients&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; 
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;NotADirectoryError&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PatientRepository&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IPatientRepository&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; 
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; 
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt; 

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_patient_by_phone&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;phone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; 
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;patients_by_phone&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{}).&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;phone&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_patients&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; 
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;patient&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;patients&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;values&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
            &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="n"&gt;patient&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Суть в том, что вместо вызовов ORM или прямых обращений в БД - мы работаем с ней через репозиторий. Тестируемость кода при таком подходе растет. Репозиторий - один из наиболее часто применяемых дизайн паттернов. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Сервисы. Конструкция которая содержит в себе всю логику, которая не вошла в агрегат. Может использовать несколько репозиториев, вызывать сторонние системы и т.д.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Фабрика позволяет создавать агрегаты принимая на вход простые инструкции. Эдакий синтаксический сахар для агрегатов. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Модули. В случае java, python и go - это packages. В случае с .NET - namespaces. Суть также простая - не надо класть все репозитории, сущности и т.д. в один модуль. &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Очень часто DDD идет бок о бок с гексагональной архитектурой. Об этом есть &lt;a href="https://rannts.ru/meetups/7/hexagonal/" rel="noopener noreferrer"&gt;хорошие доклады&lt;/a&gt;. Я же избегу воспеваний гексагональной архитектуры - уверен, что находясь в этой точке мы уже достаточно запутаны и упоминание о том, что DDD позволяет использовать 10 фреймворков одновременно на одном тематическом ядре - нас запутает еще больше :) &lt;/p&gt;

&lt;p&gt;P.S.: Я пишу эту статью в специально сумбурном стиле, чтобы приблизительно показать архитекторам &lt;del&gt;душ&lt;/del&gt;, какая ерунда творится в голове среднего разработчика от прочитанного о DDD. До сих пор не существует мягкого входа в тему, в то время как разработка приложений в традиционном стиле ведет к лапше разного качества. &lt;/p&gt;

&lt;p&gt;Спасибо. &lt;/p&gt;

</description>
      <category>ddd</category>
      <category>python</category>
    </item>
    <item>
      <title>Что в процессе тебе моем?</title>
      <dc:creator>Nikolay Fominykh</dc:creator>
      <pubDate>Thu, 18 Feb 2021 09:05:50 +0000</pubDate>
      <link>https://dev.to/tigrus/-62g</link>
      <guid>https://dev.to/tigrus/-62g</guid>
      <description>&lt;h2&gt;
  
  
  Вместо вступления
&lt;/h2&gt;

&lt;p&gt;Один из самых бесполезных вопросов, который можно встретить на собеседовании - "Чем отличается процесс от потока?". &lt;/p&gt;

&lt;p&gt;Чем вопрос плох? Ответ на него &lt;a href="https://stackoverflow.com/questions/200469/what-is-the-difference-between-a-process-and-a-thread"&gt;гуглится&lt;/a&gt; очень быстро. Люди, читавшие книги на подобии &lt;a href="https://www.ozon.ru/context/detail/id/26420096/"&gt;Linux - Системное Программирование&lt;/a&gt; и &lt;a href="https://www.ozon.ru/context/detail/id/31649356/"&gt;Современные Операционные Системы&lt;/a&gt; ответ на него формируют долго. Дело в том, что не ясно, чего хочет услышать вопрошающий. Я, как человек, совершающий цикл собеседований раз в полгода-год - первые 2-3 собеседования заваливаю, чтобы понять как мне подстроится под текущее понимание процессов и потоков у вопрошающих. Чего они хотят на этот раз услышать от человека, который пары по операционным системам не прогуливал, но делал это очень давно? &lt;/p&gt;

&lt;h2&gt;
  
  
  In Real Life
&lt;/h2&gt;

&lt;p&gt;Мне доводилось использовать в работе и процессы, и потоки, и конечно же асихронщину. Как правило сценарий в реальной работе выглядит следующим образом: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Эта штука работает час, при этом занято одно ядро из 16. Дай-ка я применю модуль &lt;a href="https://docs.python.org/3/library/multiprocessing.html"&gt;multiprocessing&lt;/a&gt;. Хотя нет, граблей много - лучше сразу возьму &lt;a href="https://loky.readthedocs.io/en/stable/"&gt;loky&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Эта штука ничего не делает, но до неё не достучатся. Давайте применим &lt;a href="https://docs.python.org/3/library/threading.html"&gt;threading&lt;/a&gt;. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Менеджер прочел статью о том, что threading это отстой, и сейчас повсюду асинхронщина. Давайте втащим &lt;a href="https://docs.python.org/3/library/asyncio.html"&gt;asyncio&lt;/a&gt; или перепишем всё на go. &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Issues
&lt;/h2&gt;

&lt;p&gt;Счастье от ускоренного параллельным кодом длится не долго. Совсем. Приезжают следующие проблемы: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Кто-то подумал за нас и втащил в airflow multiprocessing. Это нормально. Но при неосторожном коде внутри dag - у нас плодятся &lt;a href="https://linuxreviews.org/Defunct_process"&gt;zombie-процессы&lt;/a&gt; и под утро сервер скорее мертв, чем жив. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Стремление ускорить всё через threading приносит с собой счастье вроде &lt;a href="http://www.dabeaz.com/GIL/gilvis/index.html"&gt;GIL&lt;/a&gt;. И случайное поведение из-за каких-нибудь глобальных переменных - &lt;a href="https://stackoverflow.com/questions/1408171/thread-local-storage-in-python#13240093"&gt;Threading local&lt;/a&gt; зачастую плохо гуглится из-за нежелания. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Код написанный в асинхронном стиле, внезапно, оказывается уязвим к утечкам памяти. А современные data science инструменты текут только так. &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Вернемся к собеседованиям
&lt;/h2&gt;

&lt;p&gt;Теперь давайте вернемся к собеседованиям. Чего хотят авторы вопросов про многопоточность и мультипроцессность обычно? На самом деле я не знаю. &lt;/p&gt;

&lt;p&gt;Больше всего склоняюсь к мысли, что авторы спрашивают о том, что недавно узнали сами и это может быть что-то из следующего списка: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Thread'ы провоцируют GIL. Но он же сейчас скажет про &lt;a href="https://vovkd.github.io/gevent-tutorial/"&gt;гринлеты&lt;/a&gt;! &lt;/li&gt;
&lt;li&gt;Multiprocessing из 20 процессов на 5 ядрах - это внезапно плохо, и переключение контекста жрет до хрена. &lt;/li&gt;
&lt;li&gt;Event loop течет. &lt;/li&gt;
&lt;li&gt;Если запустить 100500 go routine читать один файл с жесткого диска - внезапно станет очень плохо. &lt;/li&gt;
&lt;li&gt;Ах да, есть понятие thread safe и оно касается всего. От глобальных переменных до select for update в БД. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Нужны ли на самом деле вопросы про process vs thread на собеседовании? Как вы думаете? &lt;/p&gt;

&lt;p&gt;Моё мнение приблизительно следующее. Я конечно спрошу человека про thread vs process, и мне лично будет достаточно услышать что потоки бегут внутри процесса, а процессы могут взаимодействовать через &lt;a href="https://ru.wikipedia.org/wiki/%D0%9C%D0%B5%D0%B6%D0%BF%D1%80%D0%BE%D1%86%D0%B5%D1%81%D1%81%D0%BD%D0%BE%D0%B5_%D0%B2%D0%B7%D0%B0%D0%B8%D0%BC%D0%BE%D0%B4%D0%B5%D0%B9%D1%81%D1%82%D0%B2%D0%B8%D0%B5"&gt;IPC&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;При этом, я полностью осознаю глупость данного вопроса. Это один из немногих вопросов, которые можно отнести к "открытым", развить в дискуссию, но.. Только если дискуссия не случилась раньше, по более интересным вопросам. &lt;/p&gt;

</description>
      <category>python</category>
      <category>go</category>
      <category>threading</category>
      <category>asyncio</category>
    </item>
  </channel>
</rss>
