Подтвердить что ты не робот

Где поставить спецификации для Clojure.Spec?

Итак, я погружаюсь глубже и глубже в Clojure.Spec.

Одна вещь, на которую я наткнулся, - , где можно поместить мои спецификации. Я вижу три варианта:

Глобальный файл спецификаций

В большинстве примеров, я нашел онлайн, есть один большой файл spec.clj, который требуется в основном пространстве имен. Он имеет все (s/def) и (s/fdef) для всех "типов данных" и функций.

Pro:

  • Один файл для управления всеми ними

Contra:

  • Этот файл может быть большим
  • Нарушен принцип одиночной ответственности.

Спецификации в производственных пространствах имен

Вы можете поместить свои (s/def) и (s/fdef) рядом с вашим производственным кодом. Таким образом, реализация и спецификация сосуществуют в одном пространстве имен.

Pro:

  • совместное расположение реализации и спецификации
  • одно пространство имен - одна проблема?

Contra:

  • производственный код может стать беспорядочным
  • одно пространство имен - две проблемы?

Структура пространства имен выделенной структуры

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

├─ src
│  └─ package
│     ├─ a.clj
│     └─ b.clj
├─ test
│  └─ package
│     ├─ a_test.clj
│     └─ b_test.clj
└─ spec
   └─ package
      ├─ a_spec.clj
      └─ b_spec.clj

Pro:

  • выделенные (но связанные) пространства имен для спецификаций

Contra:

  • вам необходимо указать и потребовать правильные пространства имен

Кто имеет опыт работы с одним из подходов?
Есть ли другой вариант?
Что вы думаете о разных вариантах?

4b9b3361

Ответ 1

Я обычно помещаю specs в собственное пространство имен вместе с пространством имен, которое они описывают. Не имеет особого значения то, что они назвали, если они используют какое-то согласованное соглашение об именах. Например, если мой код находится в my.app.foo, я поставлю спецификации в my.app.foo.specs.

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

(ns my.app.foo.specs
  (:require [my.app.foo :as f]))

(s/def ::f/name string?)

Я бы держался подальше от попыток поместить все в одно гигантское пространство имен спецификаций (какой кошмар.) Хотя я, конечно, мог бы поставить их прямо рядом со специфицированным кодом в том же файле, что ущемляет читаемость IMO.

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

Ответ 2

По-моему, спецификации должны быть в тех же ns, что и код.

Мое главное соображение - моя личная философия, и технически это хорошо работает. Моя философия заключается в том, что спецификация функции является ее неотъемлемой частью. Это не лишняя вещь. Это определенно не "две проблемы", как помещено в ОП. Собственно, это какая функция, потому что с точки зрения правильности: кто заботится о реализации? кто заботится о том, что вы написали в своем defn? кто заботится об идентификаторе? кто заботится о чем угодно, кроме спецификации?
Я думаю, что это странно, потому что позже не только clojure.spec, но и большинство языков не позволят вам иметь спецификации как неотъемлемую вещь, даже если вы хотите, чтобы это было, и что-нибудь близкое (тесты в коде возможно), как правило, неодобрительно, поэтому, конечно, это кажется странным. Но подумайте об этом, и вы можете прийти к такому выводу, как я (или вы не можете, эта часть утомлена).

Единственные веские причины, по которым я могу думать о том, почему вам не нужны спецификации в тех же ns, являются двумя причинами:

  • Он загромождает ваш код.
  • Вы хотите поддерживать Clojure версии pre Clojure 1.9.0.

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

Что касается второй причины, если вы по-настоящему заботитесь, вы можете проверить код, если доступен clojure.spec ns, если не затем тени именами с функциями/макросами, которые являются NOP. Другой вариант - использовать clojure-future-spec, но я сам не пробовал, поэтому не знаю, как хорошо он работает.

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

Ответ 3

Еще одно соображение в зависимости от вашего случая использования - включение спецификаций рядом с вашими основными ограничениями кода использует ваш код для Clojure 1.9 клиентов, что может быть или не быть тем, что вы хотите. Как и @levand, я бы рекомендовал параллельное пространство имен для каждого из пространств имен кода.