Hi everyone 👋 to get my head around spec, I decided to just pick the FIX protocol and spec it. The result is my first Clojure lib https://github.com/rvalentini/fix.core. However the way I used spec felt a little bit "forced" here and there. At some point, I had the feeling that I was wrapping my validation logic into a thin spec wrapper definition for the sake of using spec, without much benefits. I couldn't find a clean/nice way how to build the validation logic as composition of individual specs. To illustrate what I mean: in https://github.com/rvalentini/fix.core/blob/master/src/fix/spec/primitives_spec.clj it felt for me like an "intended" usage of spec, where the individual spec definitions compose quite nicely. But here https://github.com/rvalentini/fix.core/blob/master/src/fix/spec/message_spec.clj it felt more like I misused spec, since the spec definition is just like a facade. Any advice on how I could improve this is much appreciated!
@riccardovalentini1854 Spec's strengths are granular errors, parsing, generators. Since you basically use/provide neither of those, and just give "yes/no" answer to "valid?" – I think, such validation would be "lighter" with instaparse, or just giant regex. What can be alternatively useful, though, is a speced (with generators) edn DSL + an encode/decode functions to/from that edn data structure to FIX string messages. (pretty much what I'm doing for graphviz dot files, right now)
@misha Thanks a lot for your feedback! As a next step I planned to improve the error reporting for the client, so that in case the validation fails, the client receives some message indicating which part of the FIX message is invalid. I could make use of spec's granular error reporting there I think. I will also have a look at custom generators and think about how I could apply them to the internal edn representation of the parsed FIX messages. A nice encoder to produce FIX messages also sounds like a good idea! 👍
user then can explore "WTH is FIX message, anyway?" with s/exercise, and assemble messages as familiar maps/vectors with core functions, validate, get granular errors, etc, and then convert them into message strings.