clojure clojure.spec

¿Dónde poner las especificaciones para Clojure.Spec?



(3)

En mi opinión, las especificaciones deben estar en el mismo ns que el código.

Mi consideración principal es mi filosofía personal, y técnicamente funciona bien. Mi filosofía es que la especificación de una función es una parte integral de ella. No es algo extra. Definitivamente no son "dos preocupaciones" como se ponen en el PO. En realidad, es lo que es la función, porque en términos de corrección: ¿a quién le importa la implementación? a quién le importa lo que escribiste en tu defn ? a quien le importa el identificador? a quién le importa nada más que la especificación?
Creo que es extraño porque no solo clojure.spec vino más tarde, también la mayoría de los idiomas no le permitirán tener las especificaciones como una cosa integral incluso si usted quisiera, y cualquier cosa cercana (pruebas en el código) es usualmente desaprobada, entonces por supuesto, parece extraño. Pero piense un poco, y puede llegar a una conclusión como yo (o puede que no, esta parte es obstinada).

Las únicas buenas razones por las que puedo pensar por qué no quieres las especificaciones en el mismo ns son estas dos razones:

  1. Abarrota tu código.
  2. Desea apoyar las versiones de Clojure antes de Clojure 1.9.0.

En cuanto a la primera razón, bueno, de nuevo, creo que es una parte integral de sus funciones. Si descubres que realmente es demasiado, mi consejo sería el mismo que si tu ns estuviera demasiado abarrotada independientemente de la especificación: mira si puedes dividirla.

En cuanto a la segunda razón, si realmente le importa, puede verificar el código si clojure.spec ns está disponible, si no, sombree los nombres con funciones / macros que son NOP. Otra opción es usar clojure-future-spec pero no lo he probado yo mismo, así que no sé qué tan bien funciona.

Otra forma de que esto funcione bien técnicamente es que a veces hay una dependencia cíclica que no puedes manejar con diferentes espacios de nombres, por ejemplo, cuando tus especificaciones dependen de tu código (para las especificaciones de función) y tu código depende de tus especificaciones para analizar (consulta esta question ).

Por lo tanto, estoy buceando más y más en Clojure.Spec .

Una cosa con la que tropecé es dónde poner mis especificaciones . Veo tres opciones:

Archivo de especificaciones globales

En la mayoría de los ejemplos, encontré en línea, hay un gran archivo spec.clj , que se requiere en el espacio de nombres principal. Tiene todos los (s/def) y (s/fdef) para todos los "tipos de datos" y funciones.

Pro:

  • Un archivo para gobernarlos a todos

Contra:

  • Este archivo puede ser grande
  • ¿Principio de responsabilidad único violado?

Especificaciones en espacios de nombres de producción

Puede poner su (s/def) y (s/fdef) junto a su código de producción. Entonces, la implementación y la especificación coexisten en el mismo espacio de nombres.

Pro:

  • uso compartido de la implementación y especificación
  • un espacio de nombres, ¿una preocupación?

Contra:

  • el código de producción podría desordenarse
  • un espacio de nombre, ¿dos preocupaciones?

Estructura de espacio de nombres de especificación dedicada

Entonces pensé, tal vez las especificaciones son un tercer tipo de código (al lado de la producción y la prueba). Entonces tal vez se merecen su propia estructura de espacios de nombres, como esta:

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

Pro:

  • espacios de nombres dedicados (pero relacionados) para las especificaciones

Contra:

  • tienes que buscar y solicitar los espacios de nombres correctos

¿Quién tiene experiencia con uno de los enfoques?
¿Hay otra opción?
¿Qué piensas sobre las diferentes opciones?


Normalmente pongo las especificaciones en su propio espacio de nombres, junto con el espacio de nombres que están describiendo. No importa en particular su nombre, siempre que utilicen alguna convención de nomenclatura consistente. Por ejemplo, si mi código está en my.app.foo , pondré las especificaciones en my.app.foo.specs .

Es preferible que los nombres de las claves de las especificaciones estén en el espacio de nombres del código, sin embargo, no en el espacio de nombres de la especificación. Esto todavía es fácil de hacer utilizando un alias de espacio de nombres en la palabra clave:

(ns my.app.foo.specs (:require [my.app.foo :as f])) (s/def ::f/name string?)

Me mantendría alejado de tratar de poner todo en un espacio de nombres de especificación gigante (qué pesadilla). Aunque ciertamente podría ponerlos junto con el código específico en el mismo archivo, eso perjudica la legibilidad de la IMO.

Podrías poner todos tus espacios de nombres de especificaciones en una ruta de origen separada, pero no hay un beneficio real para hacerlo a menos que estés en una situación en la que quieras distribuir el código pero no las especificaciones o viceversa ... difícil imaginar qué Estaría bien.


Otra consideración según su caso de uso: colocar las especificaciones junto a su código principal limita el uso de su código a los clientes de Clojure 1.9, que pueden ser o no lo que usted desea. Al igual que @levand, recomendaría un espacio de nombres paralelo para cada uno de los espacios de nombres de tu código.