Clojure data format security

Based on the Java background, I really like the security of static types and I wonder how clojure programmers deal with the problem of data format definitions (maybe not only types, but also general invariants, because types are just a special case of that.)

This is similar to the existing question “Type of security in Clojure”, but it focuses more on the aspect of type checking at compile time, while I'm more interested in how the problem is pragmatically considered.

As a practical example, I consider an editor application that processes a specific document format. Each document consists of elements that come in several different varieties (graphic elements, font elements, etc.). There would be editors for different types of elements, as well as, of course, functions for converting a document from / to a byte stream in its own on-disk.

The main problem that interests me is that editors and read / write functions must agree on a common data format. In Java, I would model the document data as a graphic object, for example. with one class representing the document and one class for each sort of item. Thus, I get a compile-time guarantee on what my data structure looks like and that the width field of the graphic element is an integer, not a floating one. It does not guarantee that the width is positive, but using the getter / setter interface would allow the corresponding class to add such invariant guarantees.

The ability to use this code simplifies the code associated with this data, and format violations can be caught at compile time or earlier at run time (where some code is trying to modify data that will violate invariants).

How can you achieve similar “data format reliability” in Clojure? As far as I know, there is no way to do compile-time checks and hide domain data behind a functional interface, it seems discouraged as non-idiomatic (or maybe I misunderstood?), So clojure developers do to feel the safe format of the data transferred to them function? How do you get the code as quickly as possible, and not after the user has edited another 20 minutes and tried to save to disk when the save function notes that there is a graphic element in the font list due to an editor error?

Please note that I am interested in clojure and training, but no real software has been written yet, so it is possible that I'm just confused and the answer is very simple - if so, sorry for wasting time :).

+6
source share
2 answers

I do not see anything wrong or uniomatic in using the validating API to create and manage your data, as in the following.

(defn text-box [text height width] {:pre [(string? text) (integer? height) (integer? width)]} {:type 'text-box :text text :height height :width width}) (defn colorize [thing color] {:pre [(valid-color? color)]} (assoc thing :color color)) ... (colorize (text-box "Hi!" 20 30) :green) ... 

In addition, links (vars, refs, atoms, agents) can have an associated validator function that can be used to ensure the correct state at any time.

+8
source

Good question. I also believe that moving from a statically typed language to a dynamic one requires a bit more caution regarding type safety. Fortunately, TDD methods help here in a huge amount.

Usually I write a "validate" function that checks all your assumptions about the data structure. I often do this in Java, too, for invariant assumptions, but in Clojure it is more important because you need to also check thoughts as types.

You can then use the validation function for several reasons:

  • As a quick check in REPL: (validate foo)
  • In unit tests: (is (validate (new-foo-from-template abc)))
  • Like checking runtime for key functions, for example. checking that (read-foo some-foo-input-stream) really

If you have a complex data structure that is a tree of several different types of components, you can write a validation function for each type of component and have a validation function to validate the entire document for each subcomponent. A good trick is to use protocols or multimethods to make the authentication function polymorphic for each type of component.

+5
source

Source: https://habr.com/ru/post/908218/


All Articles