それで、私はもっと深くClojure.Specに飛び込んでいます。
私がつまずいたのは、仕様を置く場所です。次の3つのオプションがあります。
ほとんどの例で、私はオンラインで見つけた、1つの大きなspec.clj
ファイル。メインのネームスペースで必要になります。すべての(s/def)
および(s/fdef)
すべての「データ型」および関数用。
プロ:
コントラ:
(s/def)
および(s/fdef)
生産コードのすぐ隣。そのため、実装と仕様は同じ名前空間に共存します。
プロ:
コントラ:
それから私は、おそらく仕様が第三の種類のコードであると考えました(実動とテストの次に)。そのため、次のような独自の名前空間の構造に値する可能性があります。
├─ src
│ └─ package
│ ├─ a.clj
│ └─ b.clj
├─ test
│ └─ package
│ ├─ a_test.clj
│ └─ b_test.clj
└─ spec
└─ package
├─ a_spec.clj
└─ b_spec.clj
プロ:
コントラ:
アプローチの1つを経験したのは誰ですか?
別のオプションはありますか?
さまざまなオプションについてどう思いますか?
私は通常、仕様が記述している名前空間とともに、独自の名前空間に配置します。一貫した命名規則を使用している限り、それらの名前は特に関係ありません。たとえば、コードがmy.app.foo
にある場合、my.app.foo.specs
に仕様を配置します。
仕様のキー名は、仕様の名前空間ではなく、コードの名前空間にあることが望ましいです。これは、キーワードに名前空間エイリアスを使用することで簡単に実行できます。
(ns my.app.foo.specs
(:require [my.app.foo :as f]))
(s/def ::f/name string?)
1つの巨大な仕様名前空間にすべてを配置しようとすることは避けたい(悪夢です)。確かに同じファイル内の仕様コードと並べて配置することはできますが、読みやすさは損なわれます。
couldすべての仕様ネームスペースを個別のソースパスに配置しますが、コードを配布するが仕様を配布しない、またはその逆の場合を除き、そうすることには実際のメリットはありません。 ..それがどうなるか想像するのは難しい。
私の意見では、仕様はコードと同じnsでなければなりません。
私の主な考慮事項は私の個人的な哲学であり、技術的にはうまくいきます。私の哲学は、関数の仕様はintegralの一部であるということです。余分なものではありません。 OPにある「2つの懸念」ではなく、明確にです。正確さの観点から:実装を誰が気にするのか?誰があなたのdefn
に書いたかを気にしますか?誰が識別子を気にしますか?誰がanythingを気にしますか?
clojure.specが後になって来ただけでなく、ほとんどの言語では仕様が必要な場合でも仕様を必要なものにできないため、奇妙なことだと思います。通常は眉をひそめているので、もちろん奇妙に思えます。しかし、考えてみてください、そうすればあなたは私がしたように結論に達するかもしれません(あるいは、そうでないかもしれません、この部分は意見があります)。
同じnsで仕様が必要ない理由について考えることができる唯一の正当な理由は、次の2つの理由です。
最初の理由については、繰り返しますが、それはあなたの機能の不可欠な部分だと思います。本当に多すぎると思うなら、私のアドバイスはスペックに関係なくあなたのnsが乱雑になるのと同じです:あなたがそれを分割できるかどうか確かめてください。
2番目の理由については、本当に気にするなら、clojure.spec nsが使用可能かどうかをコードでチェックインできます。そうでない場合は、NOPの関数/マクロで名前をシャドウイングします。別のオプションとして clojure-future-spec を使用することもできますが、自分で試したことがないので、どのように機能するかわかりません。
これが技術的にうまく機能する別の方法は、時々、異なる名前空間では処理できない循環依存関係があることです。仕様がコードに依存し(関数仕様の場合)、コードが構文解析の仕様に依存する場合(これを参照してください question )。
ユースケースに応じて、もう1つの考慮事項-メインコードと一緒に仕様を記述することで、コードの使用がClojure 1.9クライアントに制限されます。 @levandのように、コード名前空間ごとに並列名前空間をお勧めします。