Я программист-самоучка, а это на самом деле означает, что большинство моих инструкторов застыли во времени в форме письменного слова.

Роберт С. Мартин, он же дядя Боб, - один из таких инструкторов.

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

Что дядя Боб говорит о фреймворках

Я просмотрел почти все видео, которые можно найти на YouTube, где Роберт Мартин рассказывает о чистом коде или чистой архитектуре. Конечно, это в основном один и тот же разговор, записанный в разных местах.

Я не против.

Это все равно, что читать книгу несколько раз в разных версиях. Я всегда ухожу с чем-то новым.

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

Однако оба разговора начинаются на одной и той же ноте. В своем коротком анекдоте он рассказывает, как однажды сын показал ему структуру папок. Взглянув на структуру папок, он понял, что приложение написано на Ruby on Rails.

Если вы когда-либо работали с фреймворками, этот сценарий, вероятно, вам знаком. Я могу открыть любое приложение Laravel и сразу узнать, какой фреймворк оно использует - если не версию. То же самое и с CakePHP. Или Зенд. Или любое множество доступных нам фреймворков.

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

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

Где дядя Боб ошибается

Идея о том, что структура папок должна описывать намерение приложения, является отличной концепцией, и я полностью согласен с ней, когда мы говорим о коде вашего приложения.

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

Опять же, это не так уж плохо. Он абсолютно прав относительно каждого сказанного им слова. Но он ошибается, в частности, в одном:

Веб-фреймворки не являются частью нашего приложения, они являются слоем абстракции.

Мартин, похоже, смотрит на веб-устройство ввода-вывода, как на STDIN / STDOUT. Проблема в том, что в то время как стандартный ввод / вывод имеет абстракцию на уровне операционной системы почти для всех языков, ввод-вывод веб-сайта - нет.

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

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

Потому что маршрутизация - последнее препятствие для веб-устройства ввода-вывода.

Точно так же, как было бы глупо утверждать, что ваша установка Apache или Nginx является частью вашего основного приложения, мы должны столь же критически относиться к любому, кто утверждает, что наша веб-платформа является частью нашего основного приложения.

Почему я делаю упор на ядро? Потому что было бы глупо вообще не рассматривать это как часть нашего приложения. Так же, как библиотеки динамической компоновки являются частью приложений, написанных для собственных операционных систем, но не являются их основной функциональностью, мы включаем фреймворки в качестве наших библиотек абстракции для Интернета.

Структура папки - это не архитектура

В начале своей конференции 2012 года Мартин показывает список, который, по его словам, отражает то, чем отвечает большое количество людей, когда их спрашивают, какова их «архитектура». Это список: Java, Eclipse, Spring, Tomcat, Hibernate, MySQL и MVC.

Он утверждает, что это не ваша архитектура, а ваши инструменты. И хотя я согласен, что список - это не архитектура, это также не просто инструменты. Это смесь инструментов и сырья.

Он использует параллель: просят у вас вашу архитектурную схему, а вы даете ему список молотков и пил. Но, хотя в его списке есть несколько молотков и пил - например, Eclipse - есть также некоторые пиломатериалы - Java - и утилиты - MySQL - с небольшим оттенком эстетики - MVC.

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

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

Дядя Боб во многом прав

Однако Мартин быстро уходит от акцента на структуре папок и возвращается к реальной архитектуре кода. Попытки провести параллели с тем, где размещаются файлы, полностью омрачены его диаграммами, объясняющими, как логически разметить ваше приложение и изолировать его от любых фреймворков, которые вы используете.

В этом мы с ним согласны.

Проблема с фреймворками не связана с тем, находятся они в корне вашей веб-папки или нет, а в том, находятся ли они в корне логики вашего приложения.

Фреймворки, как я описал выше, по своей сути являются просто уровнем абстракции. Ядро вашего приложения не должно заботиться о том, запускается ли оно изнутри Laravel или WordPress. Вы должны иметь возможность запускать его из командной строки, если был написан правильный интерфейс.

Базовое приложение не должно расширять или реализовывать функции фреймворка.

Заманчиво позволить вашему базовому приложению использовать модели Eloquent Laravel. Похоже, что это противоречит «способу Laravel» не использовать эти модели. Но не стоит.

Помимо этого, ваша основная архитектура не должна реализовывать какие-либо вспомогательные методы Laravel, такие как помощник Str.

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

Обратите внимание: это не имеет абсолютно никакого отношения к структуре папок, а имеет отношение только к логике приложения.

Итак, давайте поговорим о структуре папок

Я считаю, что Мартин пытался сказать своим аргументом о структуре папок, что структура папок должна логически соответствовать логике приложения. Это, на первый взгляд, имеет абсолютный смысл.

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

Теперь, когда я разобрался с сорняками, я собираюсь использовать PHP в качестве основного языка примеров, но все это работает для любого языка, который использует пространства имен. Просто на теоретическом уровне, а не на конкретной реализации.

Но где?

В качестве примера я использовал Laravel, поэтому продолжу здесь.

Я считаю, что вам следует избегать написания кода бизнес-логики внутри папки app.

Я уверен, что это шок, если вы использовали Laravel какое-то время. Дело в том, что, как мы уже обсуждали, Мартин прав в одном важном моменте: удалении бизнес-логики из вашего фреймворка.

Он может ошибаться насчет структуры каталогов, но не настолько, как вы думаете.

Я знаю, я просто натянул небольшую наживку и включил тебя, не так ли?

Не совсем, но вроде как.

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

Вместо этого вам следует написать свою бизнес-логику в виде пакета, установленного в каталоге поставщика VIA composer. Ваша бизнес-логика живет в одном репозитории, ваша реализация бизнес-логики на Laravel живет в другом.

Это, вероятно, то, что имел в виду дядя Боб все время

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

Просто чтобы подвести нас к концу.

Все это просто правильное разделение забот

Разделение интересов - тема, которой хорошо известен Мартин. Он, конечно, тот, кто первым формализовал принципы SOLID (хотя и не название SOLID) в своей статье Принципы проектирования и шаблоны проектирования [pdf].

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

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

Механизмы доставки дяди Боба

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

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

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

Архитектура - это намерение, а не структура папок

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

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

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

Если, однако, мы достаточно разделили наши заботы, чтобы мы могли перенести нашу бизнес-логику в новую структуру, написать код реализации и начать работу без каких-либо изменений в нашей основной бизнес-логике?

Что ж, тогда я говорю, что это достаточно хорошая архитектура.

Все остальное - это детали.

Если эта статья была вам интересна, вам понравится поток технических знаний, который есть в моей ленте в Твиттере. Иди туда и дай мне подписаться. Вы не будете разочарованы.

2012

2013