web-dev-qa-db-fra.com

Où mettre les spécifications pour Clojure.Spec?

Donc, je plonge de plus en plus profondément dans Clojure.Spec.

Une chose sur laquelle je suis tombé est, où mettre mes spécifications. Je vois trois options:

Fichier de spécification globale

Dans la plupart des exemples, j'ai trouvé en ligne, il y a un gros spec.clj fichier, qui est requis dans l'espace de noms principal. Il a tous les (s/def) et (s/fdef) pour tous les "types de données" et fonctions.

Pro:

  • Un fichier pour les gouverner tous

Contra:

  • Ce fichier peut être volumineux
  • Principe de responsabilité unique violé?

Spécifications dans les espaces de noms de production

Vous pouvez mettre votre (s/def) et (s/fdef) juste à côté de votre code de production. Ainsi, l'implémentation et la spécification coexistent dans le même espace de noms.

Pro:

  • colocalisation de la mise en œuvre et des spécifications
  • un espace de noms - une préoccupation?

Contra:

  • le code de production pourrait devenir désordonné
  • un espace de noms - deux préoccupations?

Structure d'espace de noms de spécification dédiée

Ensuite, j'ai pensé que les spécifications sont peut-être un troisième type de code (à côté de la production et du test). Alors peut-être qu'ils méritent leur propre structure d'espaces de noms, comme ceci:

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

Pro:

  • espaces de noms dédiés (mais associés) pour les spécifications

Contra:

  • vous devez source et exiger les espaces de noms corrects

Qui a de l'expérience avec l'une des approches?
Y a-t-il une autre option?
Que pensez-vous des différentes options?

49
DiegoFrings

Je place généralement des spécifications dans leur propre espace de noms, à côté de l'espace de noms qu'ils décrivent. Peu importe leur nom, tant qu'ils utilisent une convention de dénomination cohérente. Par exemple, si mon code est dans my.app.foo, Je vais mettre des spécifications dans my.app.foo.specs.

Il est préférable que les noms de clés de spécification se trouvent dans l'espace de noms du code, mais pas dans l'espace de noms de la spécification. C'est toujours facile à faire en utilisant un alias d'espace de noms sur le mot clé:

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

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

Je resterais à l'écart d'essayer de tout mettre dans un espace de noms de spécification géant (quel cauchemar.) Bien que je puisse certainement les mettre à côté du code spécifié dans le même fichier, cela nuit à la lisibilité de l'OMI.

Vous pourriez mettre tous vos espaces de noms de spécification dans un chemin source séparé, mais cela ne présente aucun avantage réel à moins que vous ne soyez dans une situation où vous souhaitez distribuer le code mais pas les spécifications ou vice versa. .. difficile d'imaginer ce que ce serait.

21
levand

À mon avis, les spécifications devraient être dans le même ns que le code.

Ma principale considération est ma philosophie personnelle, et techniquement, cela fonctionne bien. Ma philosophie est que la spécification d'une fonction en fait partie intégrante . Ce n'est pas une chose supplémentaire. Ce n'est certainement pas "deux préoccupations" comme indiqué dans l'OP. En fait, c'est ce qu'est la fonction, car en termes de correction: qui se soucie de la mise en œuvre? peu importe ce que vous avez écrit dans votre defn? qui se soucie de l'identifiant? qui se soucie de quoi que ce soit mais de la spécification?
. habituellement mal vu, donc bien sûr, cela semble bizarre. Mais réfléchissez-y, et vous pourriez arriver à une conclusion comme je l'ai fait (ou vous ne pouvez pas, cette partie est opiniâtre).

Les seules bonnes raisons pour lesquelles je peux penser pourquoi vous ne voudriez pas de spécifications dans le même ns sont ces deux raisons:

  1. Il encombre votre code.
  2. Vous souhaitez prendre en charge les versions de Clojure avant Clojure 1.9.0.

Quant à la première raison, eh bien, encore une fois, je pense que cela fait partie intégrante de vos fonctions. Si vous trouvez que c'est vraiment trop, mon conseil serait le même que si vos ns étaient trop encombrés indépendamment des spécifications: voyez si vous pouvez le diviser.

En ce qui concerne la deuxième raison, si vous vous souciez vraiment, vous pouvez vérifier le code si le ns clojure.spec est disponible, sinon masquer les noms avec des fonctions/macros qui sont NOP. Une autre option consiste à utiliser clojure-future-spec mais je ne l'ai pas essayé moi-même donc je ne sais pas comment cela fonctionne.

Une autre façon dont cela fonctionne bien techniquement est qu'il y a parfois une dépendance cyclique que vous ne pouvez pas gérer avec différents espaces de noms, par exemple lorsque vos spécifications dépendent de votre code (pour les spécifications de fonction) et que votre code dépend de vos spécifications pour l'analyse (voir ceci question ).

14
MasterMastic

Une autre considération en fonction de votre cas d'utilisation - mettre les spécifications à côté de votre code principal limite l'utilisation de votre code aux clients Clojure 1.9, ce qui peut ou non être ce que vous voulez. Comme @levand, je recommanderais un espace de noms parallèle pour chacun de vos espaces de noms de code.

7
Colin