Как стать автором
Поиск
Написать публикацию
Обновить

Обзор книги «Паттерны разработки на Python TDD, DDD и событийно-ориентированная архитектура»

Время на прочтение5 мин
Количество просмотров1.1K
Автор оригинала: JR Heard

Недавно я прочёл книгу «Паттерны разработки на Python TDD, DDD и событийно-ориентированная архитектура». Основной акцент в ней сделан на том, как именно нужно структурировать программы, чтобы они по мере роста оставались простыми и удобными в поддержке. Это моя любимая тема из области программирования, поэтому, конечно же, книга мне понравилась. Пожалуй, я не возьмусь использовать именно те приёмы, которые авторы рекомендуют в книге — но они обсуждают классные идеи, напомнившие мне о задачах, встречавшихся в моей практике на предыдущих работах. Кроме того, отмечу, что английская версия книги есть в свободном доступе онлайн, так какие вообще вопросы?

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

Детали

  • Книга читалась относительно быстро — приятная ясная проза, хорошие короткие главы.

  • Книга не сделала меня настоящим экспертом в DDD, но это нормально1.

  • Авторы очень постарались не слишком топить за микросервисы, и я это ценю.

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

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

Ладно, перейдём к хорошему.

Объекты-значения

В книге рекомендуется концептуализировать ключевые бизнес-примитивы в виде «объектов-значений» и использовать для этого классы данных. Вот пример из главы 1:

@dataclass(frozen=True)
class OrderLine:
    order_id: OrderReference
    sku: ProductReference
    quantity: Quantity

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

Это подводит нас к следующей теме, которая тесно связана с рассмотренной выше:

Принцип инверсии зависимостей

Этого термина я ранее не знал. Явно это какая-то штука из объектно-ориентированного программирования (может быть, это D в SOLID?), и не сказать, что исходная формулировка мне сильно помогла, но авторы показывают на её основе одну технику, которую я нахожу очень привлекательной. Эту технику проще всего продемонстрировать в сравнении с предыдущим примером.

В большинстве баз кода, с которыми мне доводилось работать, ключевые примитивы были представлены не в виде объектов-значений, а при помощи вот таких моделей:

class OrderLine(ORMBaseClass):
    order_id = orm.ForeignKey(Order)
    sku = orm.ForeignKey(Product)
    quantity = orm.IntegerField()

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

Авторы советуют выбирать в качестве базовых примитивов вашей системы не такие модели, сосредоточенные на работе с базами данных, а простые, написанные на чистом Python, например, такой замороженный класс данных, который рассмотрен выше. При этом, модели ваших баз данных должны производиться именно от этих моделей на чистом Python. Иными словами:

ORM импортирует (то есть «зависит от» или «знает») модель предметной области, а не наоборот.

Я хотел бы когда-нибудь поработать с системой, которая устроена именно так :)

Чистые функции

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

Например, в главе 3 подробно рассказано о программе для синхронизации файлов между двумя каталогами, и авторы пытаются обрисовать, как упростить тестирование всего этого. Сначала вся программа занимается операциями непосредственно над файловой системой, поэтому при всех тестах авторам приходится поднимать какие-то временные каталоги, записывать в каждый из них набор файлов, вызывать программу, а затем проверять, что она сделала во временных каталогах. Ик!  

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

source_files = {'hash1': 'path1', 'hash2': 'path2'}
dest_files = {'hash1': 'path1', 'hash2': 'pathX'}

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

 ("COPY", "sourcepath", "destpath"),
("MOVE", "old", "new"),

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

На периферии их программы есть и такой код, который а) проверяет файловую систему, создавая эти словари, которые потом будут подаваться на ввод и 2) вносит в файловую систему изменения, исходя из инструкций, содержащихся в этих командах, полученных на вывод — но это просто неизбежный факт. В данном случае действительно важно, что основная часть программы теперь не содержит побочных эффектов. Мило!

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

Заключение

Эта (ссылка на питер ком) книга вышла очень достойной. Я не собираюсь писать событийно-ориентированную систему на основе микросервисов, в которой активно применялись бы техники DDD, но мне было интересно почитать, что авторы рассказывают на все эти темы. Мне также понравилось, как они разобрали обозначенные выше идеи!

  1. Моя настольная книга — “Domain Modeling Made Functional” Скотта Влашина, и, надеюсь, именно эта книга наконец поможет мне составить впечатление о  DDD. Мне нравятся его выступления на YouTube, то и дело к ним возвращаюсь и пересматриваю все подряд. Отличный парень. 

  2. Подробнее о чистых функциях: мне нравится лекция “Hoist Your IO”, а также это упражнение в рефакторинге вдобавок к нему. Вот, кстати,  очень хороший пост

  3. О, боже, только что обнаружил, что прямо пока я писал этот пост, Скотт Влашин выступил с лекцией ровно на эту же тему! Обязательно собираюсь посмотреть! 


Осталось всего 200 экземпляров! Не упустите шанс приобрести книгу «Паттерны разработки на Python TDD, DDD и событийно-ориентированная архитектура» до того, как она закончится на нашем сайте piter.com

Теги:
Хабы:
+6
Комментарии0

Публикации

Информация

Сайт
piter.com
Дата регистрации
Дата основания
Численность
201–500 человек
Местоположение
Россия