Статьи

Конфигурация это код

Вы начинаете с простого файла .ini:

something.url = http://example.com/api/resource

Через некоторое время вы настраиваете его значения в зависимости от среды развертывания:

[development]
something.url = http://preproduction.example.com/api/resource
[production]
something.url = http://example.com/api/resource

а затем подставьте в него значения, чтобы удалить дублирование:

something.url.base = http://example.com
something.url.resource = {something.url.base}/api/resource

или заменить константы, в этом отношении:

something.url = "http://" . APPLICATION_ENV . "example.com"

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

something.url.resource = {something.url.base}/api/resource{some_condition() ? '/subresource' : ''}

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

<?
$something['url']['base'] = 'http://example.com';
$something['url']['resource'] "{$something['url']['base']}/api/resource" . (some_condition() ? '/subresource' : '');

Назад в день Java-фреймворков первого поколения

Это был приемлемый код конфигурации в среде Java (в файле web.xml):

<web-app xmlns="http://java.sun.com/xml/ns/javaee" version="2.5">
    <servlet>
        <servlet-name>comingsoon</servlet-name>
        <servlet-class>mysite.server.ComingSoonServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>comingsoon</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>
</web-app>

Давайте сосредоточимся не на многословности XML, а на концепции сопоставления маршрутов. В то время было широко распространено мнение, что отделением кода Java сервлета от его сопоставления с URL-адресами является GoodDesign (TM).

Слишком плохие сервлеты всегда создавались только один раз конфигурацией XML, и было легко создать связь между отображением и кодом из-за списка параметров, на которые есть ссылки как в коде сервлета, так и в файле конфигурации. Так что мечта о компиляции и настройке везде никогда не работала; однако программисты могут получать удовольствие от написания длинных XML-файлов и сложных IDE, чтобы проверить их на лету.

Гвоздем в гробу для этого подхода было дублирование: если у вас есть две одинаковые зоны XML, вы можете только смотреть на них и надеяться не забывать сообщать об изменениях из одной в другую. Альтернативой было сгенерировать XML во время сборки или изобрести более мощную семантику и абстракцию и заставить читателя конфигурации принять их. По обоим вариантам могу сказать только удачу .

Сегодня платформа Play или JAX-RS позволяют указывать маршруты в местах аннотаций непосредственно с сервлетами; аннотации являются первоклассными конструкциями в Java, и оттуда для программного задания маршрутов это короткий шаг.

Лисп и Пол Грэм: насколько силен язык

Теперь для чего-то совершенно другого. Вы, вероятно, знаете историю Пола Грэма и Viaweb, где стартап из 3 человек изобрел веб-приложения (рассказы об истории могут быть преувеличены.) Грэм и его соучредители использовали диалект Lisp в качестве языка программирования, что давало им конкурентное преимущество. из-за абсолютной гибкости и мощи самого Lisp.

Выразительная сила не пушистое понятие: опыт ведущего Грэма определить его в статье в качестве возможности языка Y сделать для того , что на языке X возможен только в письменной форме интерпретатора для языка Y . Например, autoCurry — это библиотека для JavaScript и PHP (и, возможно, других языков), которая эмулирует каррирование, частичное применение функции, поддерживаемой функциональными языками:

(defun sum [x y] (+ x y))
(map (sum 2) list) // applied the function "sum 2" to each element of the list
$sum = autoCurry(function($x, $y) { return $x + $y; });
array_map($sum(2), $list);

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

Десятое правило Гринспуна описывает похожий сценарий: каждая программа расширяется, пока не будет содержать медленную, подверженную ошибкам реализацию половины Common Lisp. Здесь вместо этого у нас есть формат конфигурации, который будет расти до тех пор, пока не будет содержать медленную, ошибочную реализацию половины синтаксиса PHP.

Свойства кода

Почему очень сложная конфигурация должна быть написана на PHP (или Ruby), а не на декларативном языке? Императивный язык программирования имеет несколько интересных свойств.

  • Надежность: при наличии ошибок в конфигурации они являются синтаксическими анализаторами. Например, обнаружение неопределенных переменных или опечатка приводит к тем же ошибкам, которые вы наблюдали в течение 10 лет и над которыми работали, чтобы стать более читабельными (исключая PAAMAYIM_NEKUDOTAYIM). Проверки типа подсказок типа работают очень хорошо для конфигурации DI.
  • Распространение: каждый разработчик PHP знает, как писать файлы конфигурации на PHP и интерпретировать, что они делают.
  • Поддержка: вам не нужно импортировать какую-либо библиотеку для ее анализа, только некоторые операторы require_once ().
  • Существующие инструменты. Легко увидеть, что требуется создать в конфигурации с помощью профилировщика, и его анализ может быть значительно ускорен с помощью Opcache или APC. Это существующие инструменты, которые вы, вероятно, уже используете для своего собственного кода.
  • Удаление дубликатов. Он позволяет вам использовать все доступные инструменты для борьбы с ним: общие переменные, неизменяемые объекты, анонимные функции, генерация массивов.

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

Выводы

По моему мнению, создание нового сложного языка для написания сложных конфигураций решает не ту проблему. У нас уже есть решение, простой старый код PHP, который бы легко разрешал 80% вариантов использования и делал все остальное возможным .

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