architecture

2017-03-06T05:03:08.000108Z

Anyone want to discuss this? https://youtu.be/B1-gS0oEtYc I’m really seeing a strong connection of ideas between that and http://www.stuttaford.me/2016/01/15/how-cognician-uses-onyx/ I’m too tired atm to put it all together, but the general trend i’m seeing is that its often sensible to build an append only data log (datomic, kafka) and have the rest of your system just consume and produce to it. This seems to be at the heat of CQRS and FRP, both of which i’m just starting to read about. The really interesting part is that the stream processor (kafka streams, onyx, flink) might just produce the views for other components of the system, there by removing the need for more ridge forms of storage. Which is talked about a bit here.... https://youtu.be/uuv-lnOrD0o And is a key principle of apache samza.

kauko 2017-03-06T08:13:39.000111Z

Yeah I really like that talk 🙂 That and the "Turning the database inside out" talks were the ones that really helped me understand the ideas of CQRS

kauko 2017-03-06T08:13:45.000112Z

Or maybe I should say Event Sourcing

kauko 2017-03-06T08:13:55.000113Z

Don't really see how FRP is related though

dominicm 2017-03-06T08:48:22.000114Z

FRP has 2 meanings. The common meaning, but also Functional Relational Programming, which has a discussion of immutable events as the basis.

dominicm 2017-03-06T08:49:04.000115Z

They're also similar enough that 2 can talk about each without realising they're not both discussing the same topic

kauko 2017-03-06T10:39:03.000116Z

Huh, first time I've heard of functional relational programming

kauko 2017-03-06T10:40:19.000117Z

http://shaffner.us/cs/papers/tarpit.pdf

👍 1
dominicm 2017-03-06T10:49:20.000119Z

It's a very good paper, relates well to Clojure

dominicm 2017-03-06T10:50:16.000120Z

I believe it has been cited as influential to the design of clojure

richiardiandrea 2017-03-06T16:04:09.000121Z

As a side note, event sourcing can be achieved without any CQRS, it is just identify and collect events. I see CQRS just as a fancy word that says: "please, writes and reads should not intermingle"

richiardiandrea 2017-03-06T16:07:12.000123Z

Very relevant to this are recent talks by Bobby Calderwood: https://www.youtube.com/shared?ci=rg0OP10t2NQ

2017-03-06T16:42:02.000126Z

Right, I meant to say event sourcing instead of cqrs

dominicm 2017-03-06T17:50:01.000127Z

I use CQRS with non-event sourcing. Needs using any time you do this: (defn get-user [id] (let [x (get-user-from-db id)] (assoc x :age (calc-on (:dob x)))) else you get endpoints with more data than others (many wtf moments there!)

seancorfield 2017-03-06T18:00:38.000128Z

@dominicm Could you elaborate on why that code fragment leads to a need for CQRS?

dominicm 2017-03-06T18:01:26.000129Z

@seancorfield People have a tendency to return the result of (jdbc/insert!) (there's a form that returns what you inserted I think?). Which would have less data.

seancorfield 2017-03-06T18:03:31.000130Z

Ah, I’m with you now. Yes, we have an API where many update operations return the updated data — but they all do it via calling the exact same function that the query itself calls. That’s done to avoid a round-trip on the API.

seancorfield 2017-03-06T18:04:29.000131Z

We could separate the Command (update) from the Query (get) but in nearly 100% of use cases all clients would need to issue C.Q. (two API calls).

dominicm 2017-03-06T18:07:42.000132Z

@seancorfield So you do (map #(assoc % :age …) (jdbc/insert! …))?

seancorfield 2017-03-06T18:09:12.000133Z

We have a render-user function that accepts either a user map (as returned by jdbc/insert!) or a user ID (in which case it starts by fetching the user map) and that is used consistently wherever we specify that we return a (public) user map.

seancorfield 2017-03-06T18:09:34.000134Z

Age isn’t the only thing we calculate and add to the map.

seancorfield 2017-03-06T18:10:02.000135Z

Then the public “get user” API calls render-user too.

seancorfield 2017-03-06T18:10:42.000136Z

For us, it’s just an optimization to avoid clients having to always follow a user update API call with a user get API call.

seancorfield 2017-03-06T18:12:05.000137Z

(mostly this is around jdbc/update! calls since only registration will jdbc/insert! on a user — but it applies to several other entities in the system too)

seancorfield 2017-03-06T18:13:43.000138Z

There are also some APIs where the update (or insert) operation cannot yield calculated data — so the client knows everything about the entity already — and those are pure command APIs (they return just success/failure).