DataScript as a Lingua Franca for domain modeling

New article, feedback welcome:

https://vvvvalvalval.github.io/posts/2018-07-23-datascript-as-a-lingua-franca-for-domain-modeling.html

I’m not sure of my interpretations of ‘Adaptable vs Principled’, borrowed from Elements of Clojure… what do you think? Maybe @ztellman wants to chime in?

6 Likes

Very interesting article, thank you! I think the core idea is somewhat similar to that of the hyperfiddle - have you seen it?

Also, I haven’t read Elements of Clojure (yet?), but your discussion of adaptable vs principled seems perfectly reasonable to me.

(Not sure if “France” in the title is a typo or a pun on “twitteur” :slight_smile:)

1 Like

I think your interpretation of principled vs adaptable is solid.

On the topic of fragility, how would I enforce that my email field is not just an arbitrary string? Typically this would be enforced in the constructor for the domain object, but since we’re just using maps I’m not sure if that invariant lives in a function, or in the schema itself. If it’s not part of the schema, it seems you’d have to wrap the write path, meaning the “database is the API” only for reads.

My first approach would be to declare a Plumatic Schema in the Domain Model Representation, e.g:

     {:twitteur.attribute/name :user/email
      :twitteur.schema/doc "The email address of this user (not visible to other users)."
      :twitteur.attribute/ref-typed? false
      :twitteur.attribute.scalar/type :string
      :twitteur.attribute.validation/schema my-schemas/Email ;; <-- HERE
      :twitteur.attribute.security/private? true}

If you need your ‘domain assertions’ DataScript transactions to be serializable ‘as EDN’ (I haven’t) you may want to add some name indirection to refer to the Plumatic Schema.

This :twitteur.attribute.validation/schema would then be read from the DataScript metadb to generate the machine components that need to write, e.g some GraphQL handlers or HTTP endpoints.

Because :twitteur.attribute.validation/schema would typically be optional, I would add a ‘refinement’ step to enrich the metadb with a default value:

(require '[schema.core :as sch])

(defn add-default-schemas
  "Enriches the Domain Model Representation `metadb` by adding a default `:twitteur.attribute.validation/schema` 
  to Attributes that don't have one explicitly specified, based on their `:twitteur.attribute.scalar/type`."
  [metadb]
  (dt/db-with metadb
    (for [[attr sch]
          (dt/q '[:find ?attr ?sch
                  :in $ [[?scalar-type ?sch]] :where
                  [?attr :twitteur.attribute.scalar/type ?scalar-type]
                  [(missing? $ ?attr :twitteur.attribute.validation/schema)]]
            metadb
            [[:string sch/Str]
             [:long sch/Int]
             [:bool sch/Bool]
             [:uuid sch/Uuid]
             ;; etc.
             ])]
      {:db/id attr
       :twitteur.attribute.validation/schema sch})))

Yeah I’ve seen it! There are definitely conceptual similarities, although in Hyperfiddle’s case what you manipulate is the UI is not metadata about Hyperfiddle’s domain, it’s metadata about the user’s domain. You could imagine Hyperfiddle having metadata about its own domain encoded in DataScript - that would be quite abstract, DataScript-stored metadata about Datomic-stored metadata about Datomic-stored data!

Do read it. NOW. Stop reading my blog.

Yeah, just a typo, sorry about that :slight_smile:

1 Like

This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.