Feedback on Precept library


#1

Hello everyone,

Has anyone used the Precept library ? It looks extremely interesting to model state, business rules and reactive updates in the browser, taking several ideas from Datomic.

I’d love to hear from people who used it, and if possible from the maintainers themselves !


#2

Thanks for sharing! Looks like a very interesting concept, pushing Datomic’s logic even further. It’s kind of mind bending to me right now though… I’d be glad to hear more about it too!


#3

Looks like @alex-dixon hangs around here. Can you tell about your experience with Precept in the real world ? Strengths, weaknesses?


#4

Hey! Sorry for not seeing this sooner.

Precept is still in alpha and not in production use that I’m aware of. It may well be production ready (it’s a wrapper around Clara rules and Reagent mostly). We take removing the “alpha” tag really seriously though and won’t remove it until we’re convinced beyond doubt it’s ready and users won’t suffer as a result of using it.

We could definitely use more feedback from people using it to build anything. Most of the QA is being done by me, which means it’s slower than it could be and limited to my experience and perspective. It’d be valuable to have more perspectives on it, and issues!

My real word experience using it consists of building the todomvc, the fullstack example, a drag and drop example just to see if that was performant (it was). Most recently I’ve used it to develop precept-devtools, which should be released soon.

I really do love it. I’m consistently amazed at how much it simplifies front-end development, state management, and programming in general. Things just seem to work. Rules are a much more natural way of reasoning and expressing logic for me. Going back to work on Mondays where we’re using Javascript’s latest and greatest – GraphQL, Apollo, Redux, redux-saga – is hell because I know there’s a much better way of doing things.

The devtools have a lot going on and I’ve found some problems like data munging to be more difficult to solve using rules and relational data structures. In those cases I’ve found it seamless to use Clojure/Clojurescript alongside rules instead of trying to use them for everything (which I kind of took as a challenge to myself before). I still try using rules for everything first but back off if it starts to seem silly. Using each for what they seem best at.

It’s always an option to use other stuff – a Reagent atom to hold temporary state, conditional statements inside components, a sort or filter function inside a component, or whatever you like. As I got more comfortable with using the rule engine though, I found myself not doing that as much and using Precept for pretty much everything. Precept and Clara handle updates performantly (including keypresses, mouse movements), and if I can put all state in the rules session (i.e. global state atom) then any rule can process and respond to anything that happens in the app.


#5

Nice answer !

Too bad you didn’t use it in the real world. My main concern about precept is the effort to convert data from outside the browser into the Datomic/RDF like format (eav maps). I imagine trying to integrate it with my current application (Clj/cljs with graphql backend) I admit that I foresee a lot of code for this conversion.

Do you (or someone else) have any hindsight in this regard ?


#6

Important point. Not entirely sure of the most programmatic way to handle that. Seems like something anyone using Datascript would encounter so may be some advice to be had there.

Precept has helper functions that try to make it easy to convert to and from different tuple structures. I knew that would be an issue for adoption. The view always receives maps which is nice for React. They are “entity” maps they’re way easier to work with than relational vector tuples.

I think the biggest challenge is deciding the entities for your domain. Further I don’t think there’s a function we can write to do that for every domain. In the best case you might be renaming :id to :db/id. clojure.walk is nice for things like that :slight_smile:

Starting with a schema might help modeling. We have support for uniqueness and cardinality but no component attributes yet.

For better or worse we allow any? in the value slot, so you might be able to leverage that to marshal data that you additively tag with an eid / attribute to the view layer. A typical Precept app does this regularly (typically with accumulators) in order to fulfill subscriptions that the view needs.

There’s a post on reddit about the role of a more or less singular data format throughout the clojure stack when you’re using datomic and something like datascript or precept. https://www.reddit.com/r/Clojure/comments/7jjjnq/clojures_big_picture_edn_unifies_database_schema/

This was a goal for Precept and part of why I felt parity with Datomic was important. You could use the same data structures from top to bottom, and have Precept on the server and/or the client, derive whatever data you need, and when it’s time to perform a write your data is already in the format the database expects.

I’m not against supporting more general “fact” formats, like Clara does with defrecords. Do you think that would help your situation?


#7

Thanks the detailed answer. Based on what you said, I’d say that Precept can be a good choice at the start of a project, when you have everything to build yourself. But transitioning a “real world” app with, you know, already one or several non-Datomic databases and JSON APIs to Precept could be a huge pain because of the all the necessary data transformation to put this data in Precept format.

Maybe supporting more format would help? I don’t know, I haven’t Clara Rules at all so no real experience with this problem. Still, I think the strength of Precept is it’s data format à la Datomic (EAV).

I don’t have a situation at all since I’m really asking just out of curiosity. Whether you should support more “facts” format or not, your call :wink:

Thanks again, really interesting library and discussion.


#8

We’re actually planning to discuss a “fat object” format at the start of the new year. It’s been on the table since the outset and I haven’t been a strong advocate for it since Clara seems to cover it fairly well using defrecords. We’ve discussed extending the tuple format to accommodate more than 3-4 slots, but I’m not sure that gains much ground in terms of usefulness or simplicity over what we already have.

I’m not sure what a fact object format would look like, or how to allow an entityless data model that doesn’t heavily leverage refs in the form of something like eids like we have now.

All that said though it’s a really exciting prospect to me. I’d encourage you to share any ideas or pseducode of what you’d like to see

Clara is extremely well thought out and designed. They use records as their default fact type but allow a :fact-type-fn argument to defsession (defaults to clojure’s type fn). They also allow custom hierarchies using Clojure’s derive fn. Precept hard codes the fact-type-fn to :a and provides an ancestors function where all facts descend from the keyword :all. That allows us to match on an eid or a value independent of a fact’s attribute (e.g. match on any fact with value 42 regardless of attribute [[_ :all 42]]). So we have a lot of options when it comes to designing an alternate format.