Fork me on GitHub
#clojure-uk
<
2018-01-16
>
thomas08:01:28

moin moin morning

jasonbell09:01:49

morning friends

thomas09:01:27

anyone planning on going to ClojureD?

guy09:01:20

morning!

conan11:01:28

hi all. i thought i'd let you know i'm feeling very positive about clojure this week

guy11:01:46

woop woop!

guy11:01:57

Are you doing anything fun @conan?

conan11:01:26

plugging a brand new re-frame app together using the specs i've already made for all my datomic schema

conan11:01:57

one keyword to rule them all

guy11:01:31

very cool šŸ˜„

maleghast12:01:44

Hello All - Good Morning!

maleghast12:01:37

@conan - That does sound very satisfying and exciting šŸ™‚

maleghast14:01:05

Oh bravoā€¦ šŸ™‚

maleghast14:01:32

Have I misunderstood this, or do all datoms get a ā€œtimestampā€ as they are added to a Datomic database (i.e. there is no need to explicitly include a ā€œdate-addedā€ attribute to a schema)?

dominicm17:01:45

Recording time isn't always the same time something happened šŸ˜‰

dominicm17:01:26

Also, you can't do a pull on txes relating to a user, so it becomes painful.

conan14:01:20

yes they do, that's how datomic can query at a specific time in history

conan14:01:35

datoms are 5 things: [entity-id attribute-name attribute-value transaction-id timestamp]

conan14:01:05

in practice, you usually only work with the first three

maleghast15:01:19

@conan - Thanks, I thought soā€¦ šŸ™‚ And so, if Iā€™ve understood correctly, schema associate certain datoms together in a ā€œshapeā€ that can be returned together for convenience but more specifically to allow for data deeper than one single fact to be modelled in the database?

conan15:01:07

yes. a datomic schema is just a bunch of datoms, except these datoms are used in an extra way: to validate incoming datoms to the transactor. they're single-datom validators though, you can't have relational constraints in the way that you can in a RDBMS for example

maleghast15:01:25

And so to follow on from that, how do you and indeed other people deal with db.type/ref entries that might be coming from data that is not yet present..? i.e. I am defining a schema at the moment and I want to include a ref to an organisation, but Iā€™ve not defined my organisation schema yet. Is that an issue..? More to the point there is no data yet at all, and when I come to load some in, will I need to load in organisation data before any other data that may require a reference to an organisation?

conan15:01:34

so you can say that an attribute has to be a ref, or it has to be a string, but you can't say that it has to exist and the thing it points to has to exist as well

maleghast15:01:05

@conan - Thatā€™s an interesting distinction, but I am happy with not being able to enforce such things

conan15:01:41

off the top of my head i'm not sure what happens if you add a schema for a ref attribute that points to another attribute for which there is not yet a schema. my guess is that you wouldn't be able to add it, but datomic is pretty flexible so it might let you get away with it. after all, it's still capable of enforcing the fact that every value for your new ref attribute is a ref that points to something - it may just not let you add any of these attributes if the thing it points to can't exist.

conan15:01:01

i suspect the schema datoms will be rejected though.

conan15:01:00

using spec is a great way to pick up on this stuff though, as when doing generative testing you'll definitely end up with values being created, and if datomic isn't happy with them it'll complain at you quick smart

conan15:01:57

i wrote a whole bunch of specs first, and when i came to model them with datomic schema it literally all worked first time. (admittedly it didn't work second time, i got lucky with a couple of edge cases, but it was very easy to fix - and these edge cases were bugs for sure)

conan15:01:47

but then you can't put nil as a value in datomic - so if an attribute exists for an entity, you know for sure it is the type defined by its schema. if it's a :db/ref and it exists, then it is definitely pointing somewhere - i'm not sure whether that means the somewhere has to exist, i don't think it does

conan15:01:13

i love this stuff

maleghast15:01:15

Ahā€¦ I was starting with schema - perhaps I will get a better result starting with spec(s)..?

conan15:01:28

i always think you get a better result starting with spec

maleghast15:01:07

Datomic schema are not COMPLETELY new to me, clojure.spec is - I may have been being a little bit ā€œeasy routeā€ about thisā€¦

conan15:01:10

it's like doing TDD, except you only have to think about the data to begin with, and can add behaviour later. all from your hammock, of course

conan15:01:26

nothing wrong with doing what helps you learn best

maleghast15:01:54

I was intending to write clojure.spec specs for this dataā€¦

conan15:01:57

if you want to learn how to write custom specs, i wrote a blog post about it http://conan.is/blogging/a-spec-for-urls-in-clojure.html

maleghast15:01:58

maybe I will start there.

maleghast15:01:34

Is there a low-friction way to convert specs to schema or does one still have to hand-ball the schema afterwards?

conan15:01:35

i'd just get the hang of sticking some specs together for whatever data you already have. the fact that they're all namespaced keywords is very convenient when it comes to making datomic schema from them

conan15:01:41

i did it all by hand

conan15:01:59

it's simple, if not easy šŸ˜„

maleghast15:01:18

If it were easy EVERYONE would be doing itā€¦

maleghast15:01:18

Yeah, thatā€™s a handy resource for sure - thanks @shan

yogidevbear15:01:22

Yeah @shan, I saw someone tweeting about that the other day too

maleghast15:01:40

Have people reached a consensus yet about how to organise / store and use specs..?

maleghast15:01:47

I mean do they ā€œliveā€ in .edn files in say ā€œ/resources/specsā€ and then as part of the app initialisation we read them in, or do they co-exist in namespaces that need them, or something else entirely..? I realise that the beauty of this is that as long as I can access them and donā€™t break anything else that I can do it any way I damn well please, but I am generally interested in at least knowing about the ā€œbest practiceā€ way of doing something, even if that may change or is the subject of some debateā€¦

conan15:01:02

i put mine in a namespace that's modelling the thing they're for. so for example, i have a personnamespace, and it contains all the specs that are :person/full-name and stuff

conan15:01:37

try to keep it together so you always have the specs you need near to hand. i think this makes sense when you have an fdef next to each of your functions too

thomas15:01:21

a spec for functions if I am not mistaken

maleghast15:01:28

Oh rightā€¦

thomas15:01:57

and the curated list of specs is a cool and very good idea!

maleghast16:01:12

@conan - Would you be prepared to share / show your person namespace - a lot of the documentation I am trying to use to get my head around all of this is very fragmented when all I really__ want / need is a complete exampleā€¦

maleghast16:01:36

(totally understand if not - I realise it might be proprietary etc - but I thought I may as well ask šŸ˜‰ )

rickmoynihan17:01:15

@maleghast: Well technically spec isnā€™t really edn, itā€™s clj so putting them in resources isnā€™t quite right, but you might put some/all of them in a different :source-path/`profile` depending on your needs.

maleghast17:01:04

Yeah, I am starting to think that I want them alongside / inline with the code that is going to use them

maleghast17:01:40

That the whole thing is actually a very different paradigm from other kinds of data template (e.g. JSONSchema)

maleghast17:01:57

(as far as I can tell)

rickmoynihan17:01:28

It is a different paradigm. Regarding where to put things your intuition os probably a good one. But it can get more subtle. e.g You might want different specs for the same thing depending on context, and they themselves might reuse bits and pieces. Also think about specificity. Some things can be harder to spec preciselyā€¦ but then if youā€™re doing generative tests a broad spec can generate invalid inputs (though you can also swap out the generators ā€” but then you also need to think about where to put/share them)

rickmoynihan17:01:33

Another aspect is that (require '[,,, :as ,,,]) complects aliasing with namespace loading, so you can only alias specs that live in a namespace.

guy17:01:07

^ this is really useful iā€™ve found

rickmoynihan17:01:28

but typically putting specs for foo.bar in foo.bar.spec or putting them in foo.bar is a good start šŸ™‚

rickmoynihan17:01:32

specā€™s can also take up a lot of locs, so splitting them from the code makes sense for mid-sized+ namespaces

rickmoynihan17:01:28

@guy It is but itā€™s worth being aware of the limitations it imposes. As it means you canā€™t alias keys that donā€™t exist in namespaces. For example the spec for :mvn/version in tools.deps doesnā€™t exist in an mvn namespace (but the keys short so it doesnā€™t matter). I guess what Iā€™m saying is that sometimes you want a short key for brevity, and the spec might want to be in a more fully qualified namespace.

maleghast18:01:10

This is all good / useful insights - thanks very much

rickmoynihan20:01:59

Another insight I had is that spec can be used for a lot of things (youā€™ll all know that): - validation - documentation / tool for thought - parsing data structures (conforming) - generative testing - test data generation - instrumentation - error reporting - ā€¦ However, when starting out go slow, and concentrate on just one or two aspects. With generative testing in particular be cautious of the time cost associated with it, and be careful to apply it to low hanging fruit / well suited areas first. Basically spec supports a lot of workflows; and it can be hard to adopt them all simultaneously. Personal recommendation is probably not to jump in whole-hog, but to add specs where they can help most (e.g. around your core data model), and itā€™s quite easy to use spec in your existing example-based tests. Later on you may be able to transition to more generative tests; though Iā€™m not so clear on how to integrate this style of testing with e.g. clojure.test and to get good clojure.test errors out. (Iā€™ve found test.check integrates here more easily.)

rickmoynihan20:01:49

Also there are no docstrings for spec yetā€¦ so the documentation benefit isnā€™t fully realised.

otfrom21:01:19

@jonpither thx for the http://autonomous.ai suggestion. I'm standing in front of mine now. šŸ™‚