clojure / clojure-site

clojure.org site
https://clojure.org
Eclipse Public License 1.0
250 stars 271 forks source link

Spec guide improvement - update to include example use cases and anti-patterns of simple namespaces. #517

Open dvingo opened 3 years ago

dvingo commented 3 years ago

In practice (on blogs and in app templates) application domains are often modeled using simple namespace names instead of globally unique names - task instead of com.myorg.myapp.task. This is great for getting started for new programmers but if your intention is to construct a scalable application that needs to deal with changing data designs over time, having those globally unique namespaces is crucial, as the rationale indicates.

It would be great if the spec guide had a section detailing this issue and examples of why it is a bad idea to use simple names.

One use case is when a data model has differing semantics on the client versus when being persisted to a database.

Here is an example use case I think would be beneficial in the guide (or a similar one, if not this exact code):

I have a task that has a description which in a UI form is allowed to be an empty string, but when persisted to a database must have a minimum length.

With simple namespace names this is not possible to model in spec:

(s/def :task/description string?)
;; the name is taken already so I can only provide one meaning.

It would be useful to indicate that this is by design of spec and means you are not using the tool as intended.

To alleviate this problem, one solution is to use a fully qualified namespace name:

(s/def :com.myorg.myapp.ui.task/description string?)
(s/def :com.myorg.myapp.db.task/description (s/and string? #(> (count %) 99))))

The spec guide also includes these simple namespace names in some places (:animal, :event) which I think helps encourage the notion that this is a good idea, even though it is directly against the rationale: https://clojure.org/about/spec#_global_namespaced_names_are_more_important

If these simple names are kept in the guide it would be very helpful to those learning spec to call out that this is an anti-pattern for actual usage (I would argue these examples should be removed and use fully qualified global names to avoid any ambiguity that this is a good idea).

Because there is no comment in the guide on the use of these names, and how they should be discouraged, it is very confusing to users when later they find out that this is not how spec is intended to be used.

dvingo commented 3 years ago

Another real-world example of why not to use simple names: integrating with external data - what if another system already uses the "task" ns, which has totally different semantics from mine? Examples around this use case would also be beneficial in explaining the advantages of global names.

dvingo commented 1 year ago

relevant: https://rynkowski.pl/en/posts/clojure.spec-gotchas/