Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

I found spec very useful and use it more and more. I'm looking forward to newer revisions, with support for optionality, it's been a big problem area in my case.

Here's a quick list of gotchas (well, they got me, so perhaps other people will find this list useful):

* `s/valid?` does not actually tell you that the data is valid

The naming of `s/valid?` suggests that you can call it on your data and find out if the data is valid according to the spec. This isn't true. What it actually tells you is if the data, when conformed, will be valid according to the spec. If you pass the data as-is to your functions (without passing it through `s/conform`), you might find that they will be surprised at what they get.

* Conformers are likely not what you think. They are not intended for coercion and have many pitfalls (for example, multi-specs dispatch on unconformed value).

* s/merge doesn't necessarily do what you wanted if you're using conformers, only the last spec passed to merge will be used for s/conform (but you're not using conformers, right?)

* specs are checked eagerly. If you think that (s/valid? ::my-spec x) will only check ::my-spec, that is not the case. It will check any key of x found in the spec registry.

I settled on a subset of spec, because of the pitfalls.



I think all of those problems are only true when you try to do coercion with custom conformers. Which is not the intended use of conformers.

Conformers are meant to parse the data when there are multiple possibility of what something can validate against, the conformer will disambiguate and return a result that tells you which path was chosen.

Coercion is not supported as part of Spec, you're expected to do that seperatly either before or after validating/conforming.


Yes, that was largely my point. Many people (me included) assume that s/conform is a kind of coercion, which it is not.

Not all of the above problems are due to coercion, but the majority are.

To be clear: I'm not complaining here, I find spec to be very useful and I like it, just pointing out traps for the unwary.


Ya fair enough, I've definitely seen a lot of people think conforming is meant for coercion. But it's not, it's only meant for disambiguating the chosen path (when multiple are possible) for validation.


There are a few libraries that make it possible without abusing conformers, one of which is https://github.com/exoscale/coax


Looks nice, I knew of spec-coerce, but not coax.


Can you elaborate with an example for s/valid? on needing to preconfrom your data. I have not had this issue.

Also note for others with regard to eagerness, this is only for maps. "When conformance is checked on a map, it does two things - checking that the required attributes are included, and checking that every registered key has a conforming value. We’ll see later where optional attributes can be useful. Also note that ALL attributes are checked via keys, not just those listed in the :req and :opt keys. Thus a bare (s/keys) is valid and will check all attributes of a map without checking which keys are required or optional."

Can you explain the point of :opt with s/keys if it will always check any registered spec in if present?


> Can you elaborate with an example for s/valid? on needing to preconfrom your data. I have not had this issue.

If you have any conformers, s/valid? will use them before validating.

So, if you have a 'set' conformer, for example, s/valid? will tell you that the data is valid even if the value is not a set, but a vector, for example.

Your code must explicitly call 'conform', checking with s/valid? is not enough.


Found the answer to s/keys and :opt "The :opt keys serve as documentation and may be used by the generator."


The important aspect to keep in mind is that it makes the key optional, not the value of the key.

Thus if you have a map without the key, the value won't be validated. But if the key is present, then it will validate its value.

If you want to make the value of the key optional, in the spec for the value of the key, you need to add `nil?` as a valid value.


> Thus if you have a map without the key, the value won't be validated. But if the key is present, then it will validate its value.

Exactly. Which is something I did not expect. I expected '(s/valid? ::my-spec x)' to tell me if x is valid according to ::my-spec, checking only those keys that ::my-spec lists in :req and :opt (if present).

For maps, you might as well think of s/valid? as ignoring the first parameter. It validates anything it can.


Oh, you mean because it will validate even qualified keys that arn't defined on req and opt if they have a corresponding spec?

I admit, that's surprising. Not sure why they made it so.


> with support for optionality

You should be careful asking for this.

Both Protobufs and Cap'n Proto eventually decided that "optional" creates more grief that it saves.

It is also a bit of a religious flamewar.

Caution is advised.


That is exactly my point. Optionality is complex and causes a lot of bugs in applications (certainly in mine, I would say it's the #1 root cause of bugs).

Which is why I'd like spec to help me with managing it. It's not obvious, because whether certain data is required or optional depends on context. But from what I've heard, bright minds at Cognitect are thinking about it, and given their track record so far, I'm pretty confident I will like the solution.


They went with null?




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: