На конференции clojure/conj на прошлой неделе, наверное, в половине презентаций так или иначе упоминалась спецификация, и она еще даже не вышла из альфа-версии. spec — это основная функция clojure; она здесь, чтобы остаться, и она мощная.
В качестве примера его мощности возьмем статическую проверку типов, которую многие приветствуют как своего рода страховочную сетку и определяющую характеристику многих языков программирования. Он невероятно ограничен тем, что хорош только во время компиляции и проверяет только типы. spec, с другой стороны, проверяет и согласовывает любой предикат (не только тип) для аргументов, возврата, а также может проверять отношения между ними. Все это является внешним по отношению к коду функции, отделяя логику функции от смешения с проверкой и документацией по коду.
Относительно РАБОЧЕГО ПРОЦЕССА:
Одним из архетипических примеров преимуществ проверки отношений по сравнению только с проверкой типов является функция, вычисляющая подстроку строки. Проверка типов гарантирует, что в (subs s start end)
s
является строкой, а start
и end
— целыми числами. Однако внутри функции необходимо выполнить дополнительную проверку, чтобы убедиться, что start
и end
являются положительными целыми числами, что end
больше, чем start
, и что результирующая подстрока не больше исходной строки. Все эти вещи можно указать, например (простите меня, если что-то из этого немного избыточно или, может быть, даже неточно):
(s/fdef clojure.core/subs
:args (s/and (s/cat :s string? :start nat-int? :end (s/? nat-int?))
(fn [{:keys [s start end]}]
(if end
(<= 0 start end (count s))
(<= 0 start (count s)))))
:ret string?
:fn (fn [{{:keys [s start end]} :args, substring :ret}]
(and (if end
(= (- end start) (count substring))
(= (- (count s) start) (count substring)))
(<= (count substring) (count s)))))
Вызовите функцию с демонстрационными данными, соответствующими приведенной выше спецификации args
:
(s/exercise-fn `subs)
Или запустите 1000 тестов (это может несколько раз дать сбой, но продолжайте работать, и оно будет работать — это связано с тем, что встроенный генератор не может удовлетворить вторую часть предиката :args
; можно написать собственный генератор, если нужный):
(stest/check `subs)
Или хотите проверить, делает ли ваше приложение недействительные вызовы subs
во время работы в режиме реального времени? Просто запустите это, и вы получите исключение из спецификации, если функция вызывается, а спецификации не соблюдены:
(stest/instrument `subs)
Мы еще не интегрировали это в наш рабочий процесс и не можем использовать в производстве, так как это все еще альфа-версия, но первая цель — написать спецификации. Сейчас я помещаю их в одно и то же пространство имен, но в отдельные файлы.
Я предполагаю, что наш рабочий процесс будет состоять в том, чтобы запустить тесты для спецификаций, используя это (найдено в руководстве по спецификациям clojure):
(-> (stest/enumerate-namespace 'user) stest/check)
Затем было бы целесообразно включить инструментирование для всех функций и запустить приложение под нагрузкой, как мы обычно его тестируем, и убедиться, что данные «реального мира» работают.
Вы также можете использовать s/conform
для деструктуризации сложных данных в самих функциях или использовать s/valid
в качестве пред- и пост-условий для запуска функций. Я не слишком заинтересован в этом, так как это накладные расходы в производственной системе, но это возможно.
Нет предела возможностям, и мы только что коснулись поверхности! Крутые вещи появятся в ближайшие месяцы и годы со спецификацией!
person
Josh
schedule
12.12.2016
conform
? (Как вы могли иметь его вообще без формата спецификации для проверки?) - person Charles Duffy   schedule 12.12.2016