Некоторым из этих книг уже очень много лет. Главная книга о паттернах — Design Patterns — увидела свет в 1994-м году, значит, ей уже почти тридцать. По сравнению с ней, Clean Architecture, вышедшая десять лет назад — практически, ребёнок!

Но десять лет для индустрии — гигантский срок. Возможно, эти книги уже устарели и нам они не нужны?

Перечитаем и попробуем разобраться.

Приёмы объектно-ориентированного проектирования

Книга, известная в народе, как GoF или главная книга о паттернах. Я не нашёл в интернете информации, как познакомились авторы и почему они назвали себя бандой четырёх. Знаю, что все они в то или иное время работали в IBM. Эрих Гамма вместе с Кентом Беком разработал JUnit — предтечу всех современных фреймворков модульного тестирования. Если вы пишите модульные тесты, вы знаете, кого за это благодарить. Джон Влисидис умер в 2005-м в возрасте сорока четырёх лет.

Хелм и Джонсон не участвовали в известных мне проектах.

С момента выхода первого издания прошло 28 лет. Что мы узнали за это время?

1. Термин паттерн трактуется слишком широко. Я слышал про паттерны многозвенное приложение, инверсия зависимостей и микросервис-заместитель (proxy microservice). Ничто из этого я бы к паттернам не отнёс. Автор оригинальной концепции Кристофер Александр говорит не просто о паттернах, а об языке паттернов. Язык предполагает общение и понимание, поэтому я против того, чтобы паттернами называли что угодно. Многозвенная архитектура — это модель, а инверсия зависимостей — принцип. Авторы книги дали паттернам узкое определение, ограничившись объектно-ориентированными языками. Они сформулировали ясную нижнюю границу — паттерном не может быть то, что входит в стандартную библиотеку. Нет паттернов массив и поток.

2. Шестнадцать из двадцати трёх оригинальных паттернов могут быть выражены простыми языковыми средствами, что и продемонстрировал Петер Норвиг в своей статье. Языком программирования был не C++, а LISP. Получается, что некоторые паттерны — это просто досадная необходимость, вызванная слишком низким уровнем языка. Впрочем, в функциональных языках могут быть свои паттерны. Кроме того, паттерн может быть всё-таки языковым средством, который говорит о назначении объекта. Видя в коде Хранилище пользователей (User Repository) мы понимаем, что пользователи хранятся в базе, но нам, слава богу, не надо ничего знать об этой базе. Мы концентрируемся на бизнес-логике.

3. Паттерн Одиночка (Singleton) на поверку оказался антипаттерном. Он нарушает принцип единственной ответственности, потому что экземпляр одиночки выполняет свою основную функцию и одновременно управляет временем своей жизни. Избавиться от одиночки можно, передав управление временем жизни в IoC-контейнер. Термин антипаттерн прочно вошёл в наш лексикон вместе с паттерном.

4. Язык паттернов оказался полезным. Я ни разу в жизни не использовал Интерпретатор (Interpreter) и трепещу перед Посетителем (Visitor), считая его сложным. Я с удовольствием использую Единицу работы (Unit of Work), Хранилище (Repository), Корень композиции (Composite Root), Внедрение через свойство (Property Injection) и десятки других паттернов.

Резюме

На определённом этапе профессионального становления книгу надо обязательно прочитать. Названия паттернов надо использовать в своей речи и в своём коде. Важно не путать паттерны друг с другом, потому что это и правда язык. Неправильный язык ведёт к заблуждениям.

Обращайте внимание на источники. Если ваш друг Жора придумал паттерн, это не паттерн. Настоящий паттерн, как элемент общего языка, должен быть описан в популярной книге или в статье на посещаемом ресурсе. Паттерн должен быть описан в классической форме, то есть как в GoF, с разделами Название, Назначение, Реализация, Плюсы и минусы.

Словосочетание паттерн микросервис в какой-то статье из интернета не делает микросервис паттерном.

Шаблоны корпоративных приложений

Основной автор книги — Мартин Фаулер. У него пять соавторов, про которых я ничего не слышал. Google подсказывает, что у одного из них есть забытый профиль на GitHub, другой последние десять лет работает управленцем, а третий что-то там из Oracle.

Не смотря на таинственность авторов, книгу следует признать самой полезной книгой о паттернах. У неё есть сокращённое название P of EAA, то есть Patterns of Enterprise Application Architecture. Если GoF вводит нас в тему, то P of EAA погружает нас в самую пучину.

Рассмотрим на примере. В Entity Framework доступ к данным осуществляется через класс DbContext.

В DbContext изменения в базу вносятся не тогда, когда вы обновляете поля сущностей или вызываете методы удаления, а когда вызываете SaveChanges. Объект накапливает сделанные вами изменения и затем разом их вносит. Вам не приходится следить за тем, чтобы записи добавлялись или удалялись в правильном порядке — DbContext делает это за вас. Все ваши составные операции атомарны — если одна из них завершится ошибкой, будут отвергнуты все накопленные изменения.

На уровне базы данных мы называем такие операции транзакциями, но транзакции слишком детальны для слоя бизнес-логики — мы можем игнорировать всё, что относиться к уровням изоляции или к вложенности. Паттерн Единица работы (Unit of Work) нужен как раз для этого и DbContext его реализует.

Почему в DbContext нет групповой операции удаления? Потому что в Unit of Work нет такой операции. Как обычно, паттерн хорош в одних сценариях, и не очень хорош в других. Полезно знать его ограничения, чтобы делать свою программу эффективной.

Entity Framework умеет преобразовывать деревья выражений в SQL-запросы. Дерево выражений в данном случае — это Объект-запрос (Query Object), паттерн, описанный Фаулером.

После загрузки данных, Entity Framework заполняет поля объектов из базы. Задача эта нетривиальная. Фаулер описывает набор классов, необходимых для заполнения полей, как паттерн Преобразователь данных (Data Mapper). Наряду с преобразователям, в программах регулярно встречаются Активная запись (Active Record), Шлюз к данным записи (Row Data Gateway), Шлюз к данным таблицы (Table Data Gateway) и другие. Их нет в Entity Framework, но вы найдёте их в ADO.NET или zend-db.

Резюме

Эту книгу надо прочитать, чтобы понимать, что встречается в современной бизнес-разработке. Не обязательно уметь готовить все эти паттерны, достаточно иметь представление о разнообразии решений.

Внедрение зависимостей в .NET

Инверсия зависимостей (Dependency Inversion) — не самая простая концепция. Её трудно объяснить на пальцах, и если вы поняли её на пальцах, возможно, вы поняли её неправильно.

Инверсия зависимостей — старая идея, которую можно встретить даже в стандартной библиотеке C, а именно в функциях bsearch и qsort. Наверняка, это не самый ранний пример, но языку C в 2022-м году исполнилось 53 года, и это значит, что DI, как принцип, известен в мире программирования уже очень давно.

Чтобы принцип работал, нужно придумать, как внедрять зависимости. В C это делается через указатель на функцию с известной сигнатурой, в объектно-ориентированных языках — через параметры конструктора, свойства класса или параметры методов. Паттерны Constructor Injection, Property Injection и Method Injection как раз об этом.

Помимо общих принципов важны, конечно, и детали. Симан показывает, как внедрять зависимости вручную, как внедрять их через Castle, Autofac, Unity. Этого достаточно, чтобы перестать беспокоиться о конкретных библиотеках. Они похожи.

Резюме

Локатор служб (Service Locator) — это антипаттерн, а не паттерн. Книгу надо прочитать, если вы пишете на C#. Если вы пишете на другом объектно-ориентированном языке, она тоже может быть полезна.

Искусство автономного тестирования с примерами на C#

Как писать модульные тесты (unit tests)? Есть несколько рекомендаций, которые, к сожалению, трудно применять на практике. Когда я начинал осваивать автоматическое тестирование, я по два часа зависал на тестах. Мне казалось, что для тестирования вот этой вот штуки мне потребуется другая штука, которую тоже нужно написать.

С тестами не задавалось. После того, как они были написаны, их приходилось постоянно переписывать. Да, я знаю, что тесты должны быть устойчивы. Спасибо.

Оказалось, что модульное тестирование, если его готовить правильно, требует серьёзного изучения. На помощь, конечно, приходит книга, и в случае юнит-тестов это — книга Роя Ошероува. Причём здесь архитектура, спросите вы? Архитектура притом, что при написании тестов вам придётся делать классы маленькими и слабо сцепленными.

Резюме

Книга полезна и для того, чтобы практически освоить искусство написания модульных тестов, и для того, чтобы практически освоить принципы SOLID.

Чистая архитектура

Последняя в списке, но не по значению.

Роберт Мартин, он же дядюшка Боб, известен нам с давних пор. Был такой журнал — C++ Report, который выходил c 1989 по 2002 год. Время рассвета C++. Именно там появились первые современные практики проектирования — до того, как придумали Java.

Дядюшка Боб был редактором этого журнала. Он сформулировал принципы SOLID. Он участвовал в обсуждении Манифеста гибкой разработки.

Он написал книгу о чистой архитектуре. Главная идея книги — кто управляет зависимостями, тот управляет миром. Чтобы проект оставался подконтрольным, снижайте количество зависимостей. Организуйте зависимости, без которых нельзя.

Важное знание, которое я получил из книги — никто не знает будущего. Никто не знает, что потребуется от программы через два года. И никакие ваши усилия не позволят вам придумать архитектуру, способную поддержать изменения, которые потребуются через два года. Каким бы умным вы ни были, вы ошибётесь.

Резюме

Книгу стоит перечитывать время от времени. С каждым новым проектом ваш опыт растёт, и этот опыт надо реструктурировать с помощью специальной литературы. Дело не в том, чтобы узнать новое. Дело в том, чтобы устаканить то, что уже есть в голове.

Заключение

И какой вывод? Устарели книги? Удивительно, но нет. В нашей индустрии тридцать лет — это почти бесконечность, но, кажется, авторам удалось создать что-то фундаментальное. Не будем убирать эти книги на дальнюю полку. Время ещё не пришло.

Комментарии (31)


  1. elmanaw
    15.06.2022 20:23
    +5

    Отличный подбор! Вспомнился ещё Эрик Эванс с его несгибаемой синей книгоой Domain-Driven Design: Tackling Complexity in the Heart of Software. Ей не почти 20 лет, но тоже живее всех живых в своей области.


    1. zartarn
      18.06.2022 02:21

      Сама по себе она тяжеловата. Но есть еще Вон Вернон — «Реализация методов предметно-ориентированного проектирования». Там уже идет обощение опыта применения идей Эрика Эванса, и вещи которые появились в данной области после


  1. funca
    15.06.2022 20:52
    +13

    Если ваш друг Жора придумал паттерн, это не паттерн.

    GoF писали текстовый редактор на Java и оттуда насобирали идей на целую книжку. Почему в наше время Жора не может проделать тот же трюк с другой предметной областью или языком?

    В GoF на первых же страницах писали, что главная их задача в книжке - показать принцип, - а сами паттерны это просто иллюстрация и призывали искать свои.

    Но все восприняли эти примеры как догмы (ведения же ни кто ни читает) и принялись тиражировать как обезьяны по поводу и без повода.


    1. markshevchenko Автор
      17.06.2022 12:24

      У меня просто есть история про разное понимание паттерна Unit of Work. Один участник дискуссии думал, что UoW это то же самое, что и транзакция и может быть вложенной. А другой опирался на описание паттерна в книге Фаулера. Там про вложенность ничего нет.

      Вместо того, чтобы сократить время разговора, паттерн стал причиной спора. Поэтому не соглашусь с вами. Паттерны нужны для передачи информации о проектных решениях в коде. Если программисты будут понимать их по разному, неизбежны проблемы.


  1. Filipp42
    15.06.2022 21:11
    +6

    А как же SICP?


    1. omxela
      15.06.2022 21:31
      +2

      Тоже промелькнула эта мысль. Виноват ТС - дал статье слишком общее название. Хочется сразу много нестареющих и не устаревших книжек сюда подпихнуть. Даже перечислять не буду.


      1. WASD1
        16.06.2022 17:53

        А вот перечислите, реально было бы интересно.

        SICP, Code Complete, Clean Code, Design Patterns, Dragon Book - с ходу.

        Остальное - либо не дотягивает, либо слишком технология-ориентировано, либо надо вспоминать.


    1. markshevchenko Автор
      17.06.2022 11:59

      Вы правы, что хороших книг гораздо больше, чем здесь написано. Но объять необъятное нельзя, Козьма Прутков это точно установил.

      Я сначала в заголовке написал, что речь про ООП и даже про .NET, но потом решил, что длинный заголовок зло, и перенёс ООП и .NET в хабы. Мне казалось, они бросаются в глаза и задают какой-то контекст.

      Что касается SICP, то у меня несколько материалов, навеянных этой книгой. В частности, предыдущая статья на хабре.


  1. funca
    15.06.2022 21:52
    +3

    Инверсия зависимостей (Dependency Inversion) — не самая простая концепция. Её трудно объяснить на пальцах ... Чтобы принцип работал, нужно придумать, как внедрять зависимости.

    Не совсем. Принцип проектирования Dependency Inversion Principe (DIP) показывает как можно ослабить зависимости слоев высокого уровня от деталей реализации. На бытовом уровне: вместо того чтобы соглашаться на условиях поставщика услуг, вы предлагаете ему заключить контракт на собственных условиях (ломая позицию исполнителя "у нас стандартный договор"). В этом случае вы будете зависеть только от условий своего же контракта, а не прихотей конкретного исполнителя. Противоположность - прямая зависимость, когда слой высокого уровня использует интерфейсы более низкого.

    Dependency Injection (DI) это шаблон проектирования, предлагающий типовые варианты для настройки объекта в рантайме, при котором значения полей задаются внешней сущностью. Это одна из реализаций принципа Inversion of Control Principe (IoC, aka Hollywood Principe - "Don't call us, we'll call you"). Противоположность - создание или запрос зависимостей самостоятельно, как например в паттерне Factory Method или Service Locator.

    Принципы DIP и IoC на уровне идей чем-то похожи. Здесь первый подсказывает как менять отношение между объектами, а второй - поведение. DI просто один из способов собирать все вместе.


  1. OlegZH
    15.06.2022 22:09
    +1

    Звучит как приглашение прочитать. Я бы присоединил к первой книжке ещё Гради Буча, Джефа Элджера и, наверное, ещё и Шлеер С, Меллор С. Объектно-ориентированный анализ: моделирование мира в состояниях.


    1. markshevchenko Автор
      17.06.2022 12:08

      Может быть, вы и правы. Но я Гради Буча очень давно не перечитывал, поэтому в фундаментальные книги и не записал. Мне кажется, его подход оказался слишком громоздким — предтечей современного кровавого энтерпрайза.


  1. erzi
    15.06.2022 22:12
    +4

    Хм, визитор всегда казался понятным и самым элегантным, а вот всякие там фабричные строители избыточными и ненужными


  1. VYudachev
    15.06.2022 23:05
    +2

    Статья в первую очередь вокруг ООП, поэтому я бы добавил Бертран Мейер. Объектно-ориентированное конструирование программных систем.


  1. aelaa
    16.06.2022 00:48
    +12

    Настоящий паттерн, как элемент общего языка, должен быть описан в популярной книге или в статье на посещаемом ресурсе

    Настоящий паттерн существует в написанном так или иначе коде независимо от того, описан он где-то или нет.

    Культ карго, как и принято в ООП. И набор книг сугубо вокруг него.


    1. Neikist
      16.06.2022 22:17

      Да все же нет. Ключевое в паттернах все таки не то что их надо писать (уже и не надо многие классические), а общая терминология с другими разработчиками. А для этого нужно чтобы паттерн был известен многим.


    1. markshevchenko Автор
      17.06.2022 12:10

      Не соглашусь. Паттерны придумывают люди для каких-то целей. И паттерны это всегда результат осмысления существующего кода, результат поиска закономерностей.

      Описание паттерна очень важно для передачи смысла. Если вы дадите классу название OrderRepository, читатель вас поймёт. А вот если назовёте его OrderManager — то, скорее всего, нет. Manager может быть чем угодно.


      1. aelaa
        17.06.2022 12:13

        Вопрос сущего или должного опустим. Одинаковая нотация полезна и даже важна в профессиональной среде, но в живой природе можно встретить и альтернативные. Главное - понимать что ты перед собой видишь в своей терминологии.


        1. markshevchenko Автор
          17.06.2022 12:22

          С таким утверждением сложно спорить. :)


          1. aelaa
            17.06.2022 12:24

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


  1. Racheengel
    16.06.2022 00:50
    +4

    Главное не пытаться все 23 паттерна использовать одновременно. К сожалению, встречал подобное,и это даже говнокодом трудно было назвать :(


  1. dyadyaSerezha
    16.06.2022 01:29
    +2

    А как насчёт "The art of computer programming", Knuth, 1968? В четырёх томах, однако.


    1. nameless323
      16.06.2022 02:30
      +4

      Я бы сюда же еще добавил "Introduction to Algorithms", Thomas H. Cormen, 1990. А Кнут конечно для сильных духом, я лет 10 назад не смог толком осилить, а сейчас как-то руки всё не доходят.


      1. MockBeard
        16.06.2022 10:50

        Знаю только одного человека, который прочитал три тома Кнута еще будучи студентом. Он реально крут и глядя на него я понял, что не учился в универе, а валял дурака ))


    1. markshevchenko Автор
      17.06.2022 12:12

      Да, тоже очень хорошая книга. Время от времени перечитываю любимые места. К сожалению, кажется, она всё-таки устарела даже как учебный курс. Но я бы рекомендовал её читать для расширения кругозора. Кнут очень эрудированный автор, кстати, владеет русским языком. И эта эрудиция очень заметна.


  1. myklegrig
    16.06.2022 05:25

    А как же Кнут, Кормен и подобные?


  1. event1
    16.06.2022 17:15
    +1

    Я бы дополнил несколькими классическими трудами: "Искусство программирования", "Алгоритмы + структуры данных = программы" и книгой красного дракона


  1. v-nechaev
    16.06.2022 22:45

    Не знал, что дядюшка Боб был редактором журнала о программировании)


    1. markshevchenko Автор
      17.06.2022 12:13

      Ты думал, он только занудствует на тему тестов и чистоты кода? :)


  1. theLastOfCats
    17.06.2022 19:41
    +1

    Сейчас бы в 2к22 продолжать рекомендовать Clean Code

    https://qntm.org/clean


    1. markshevchenko Автор
      17.06.2022 21:42

      В статье рекомендуется другая книга — Clean Archicteture.


    1. WASD1
      18.06.2022 15:43

      О_О отличная статья.
      Прям хорошо разъяснила почему зачастую глядя на (clean code или "clean code") хочется его выкинуть весь и написать как в ссылке на репозиторий.

      Чтобы все действия в одном месте, а не замаскированные размазывания преобразований по 15 функциям.