Fork me on GitHub
#clojure
<
2020-03-29
>
emccue13:03:52

Yeesh 186 replies

emccue13:03:16

I feel like these acronyms you are using are mostly meaningless

emccue13:03:33

@potetm That "Command Query Response Segregation" would be immediately associated with "Event Sourcing" is super concerning to me

emccue13:03:35

I don't think it fits the characterization of "semantic police"-ing to say that the first thing has nothing to do with the second

emccue13:03:07

unless either the words used to describe either CQRS or ES are entirely misleading

emccue13:03:26

or there is some deep and deeply stupid history behind them

emccue13:03:34

I can see how "event sourcing" as an architectural pattern could include in its definition "keep track of old events with the ability to replay/rewind"

emccue13:03:43

I've made apps before that would replay events off a queue and do idempotent writes

emccue13:03:36

which feels like it matches some part of what y'all are talking about

emccue13:03:11

but I'm understanding less the more im reading your descriptions

potetm13:03:18

It’s probably me, but it feels like every time I talk online w/ someone about CQRS I start to feel like I’m taking crazy pills.

potetm13:03:25

> That “Command Query Response Segregation” would be immediately associated with “Event Sourcing” is super concerning to me

potetm13:03:51

I’ve literally never seen someone talk about CQRS absent event sourcing.

potetm13:03:12

And, conversely, I’ve often seen them conflated.

potetm13:03:06

I said what I said in order to communicate something to somebody. Not to make it universally parsable in the most technical sense.

potetm13:03:58

But, back to what I was saying about talking about CQRS online: I feel like every conversation immediately devolves in to someone explaining what I don’t understand about CQRS. It’s like monads.

potetm13:03:28

Now, perhaps I’m really missing something. But I don’t think so. I think I’m generally talking about concepts and CQRS folks are myopic in their focus on implementation. So I’ll say, e.g. “Aggregates are a form of caching,” and then we’ll go round and round about how aggregates are an important conceptual pattern etc etc etc.

emccue13:03:05

In my brain I visualize it like a white rectangle

emccue13:03:25

that white rectangle contains every concept there is to learn in this field

emccue13:03:10

and on the corners, there is moss and mold from academics, mathematicians, or (i guess) architecture astronauts

emccue13:03:24

covering and obscuring otherwise useful knowledge

emccue13:03:32

its like legalese

potetm13:03:13

That would be true if it weren’t for the fact that these concepts are not somehow fundamentally different from more general programming concepts.

potetm13:03:34

how many negatives can I fit in a single sentence

potetm13:03:26

iow - CQRS/ES is just a bunch of other concepts pieced together

potetm13:03:33

we can talk about those

valerauko13:03:09

isn't that because cqrs is a pre-requisite of event sourcing?

valerauko13:03:54

to me cqrs just means "have read-only endpoints"

potetm14:03:46

I think there has to be some form of splitting reads and writes. I dunno if it requires the whole cqrs architecture.

potetm14:03:08

But I think your comment highlights my frustration: It’s like monads. Everyone articulates their understanding differently. (In this case, I suspect it’s because everyone has a slightly different understanding.)

potetm14:03:24

btw - apologies to @emccue. You just happened to be the one that made a comment after I figured out the source of my frustration 😄 Please don’t think this is directed at you, in particular.

potetm14:03:06

If you feel like you can clarify, please do.

mloughlin17:03:42

Sounds like one of those programmer honey traps. It's too nebulous to be worth discussing, but we just can't leave it alone.

💯 4
potetm17:03:49

:feelsbadman:

mloughlin17:03:14

If 10 people can give a different definition for the same thing it may be...... complected 😎 CSI Miami theme plays

😜 4
didibus17:03:08

Maybe I can try to explain, at least for me.

didibus17:03:24

I think you're trying to discuss ideas and concepts

didibus17:03:44

Like, what if we split our reads from our writes?

didibus17:03:08

What if we never mutated anything, even in our database?

didibus17:03:58

But you then call the first CQRS and the second ES

didibus17:03:31

Maybe you meant something slightly different to this. But let's say someone were too

didibus17:03:02

Like, CQRS is the idea of splitting our reads from our writes

didibus17:03:41

So, it's not that there isn't Interplay, obviously there is, that's why it's confusing

didibus17:03:35

But to me, it is a confusion of taking an abstract concept and mixing it with one of its concrete realization

didibus17:03:55

And I see that happen a lot

didibus17:03:29

I guess there's nothing wrong with it per say. It's just that it is confusing to me as well. Especially when we debate pros/cons and the merits of a solution. It's like the ideas of OOP versus say a Class and Inheritance system of OOP used in Java. That's another one I see that happens a lot. OOP is just the idea of encapsulation. Hey isn't this just some form of encapsulation, guess you're doing OOP.

didibus17:03:20

Or people discuss that OOP is just about message passing, oh so I guess OOP and Actors are actually the same thing

potetm18:03:10

Yeah that all makes sense. Thing is, that’s exactly what I was trying to do! I was trying to lift the convo from implementation into “these are the useful abstractions.” So, for example, in our convo, I tried to say, “CQRS is useful, actually. As proof, you can see many of the relevant abstractions in Datomic.”

potetm18:03:15

But I can see how it seems like I was trying to do the reverse.

potetm18:03:25

“Oh, CQRS is awesome. Datomic implements CQRS.”

potetm18:03:52

I mean, I literally said “But datomic is basically CQRS embodied (depending on your definition).” So. There’s that.

potetm18:03:31

So maybe the takeaway is to be explicit in trying to lift the conversation to abstraction.

👍 4
didibus18:03:23

Think you about summed it up exactly as it played out haha

didibus18:03:10

To be fair, all this software craftsmanahip mumbo jumbo with Martin Fowler and co. It threads a very dangerous line. I don't know how to define that line, but it's similar to the whole Agile/Scrum and methodologies line

didibus18:03:29

Like, it's easy to devolve in a place which only exists in the clouds, and no one is ever able to really connect back to reality. Where it starts having its own vocabulary of things defined using other made up vocabulary, etc.

didibus18:03:31

I feel I always have to spend so much time deciphering what things mean concretely, and sometimes when you see that part it's like, why does this even have a name

didibus18:03:34

I'm not doing a good job of explaining. But it's like, when people lose sight of the original goals or even problem.

didibus18:03:03

And you start doing a bunch of things for the sake of it.

potetm18:03:06

I think felt the same talking about “Aggregates” with some CQRS people once.

potetm18:03:45

One person was asking, I dunno, something like, “When do you make an aggregate vs allow a read from the write domain object?”

potetm18:03:07

I mean the entire question reveals a certain level of navel-gazing. But it’s easy to ask the question: What do you get from an “aggregate?” Well you get faster reads if they’re materialized (i.e. caching). Other than that, it doesn’t really matter!

didibus18:03:47

Yup, exactly. It's like, what are we even talking about?!?

didibus18:03:05

And when they show you example code, oh boy

didibus18:03:48

It's all MyCoolBlaService with methods etc. The most pendantic OOP stuff

potetm18:03:03

IMO - this is the status quo conversation in software today. Most folks never stop to ask, “What exactly does this get us vs some other option?”

potetm18:03:19

where exactly means, “Matters to non-software people.”

potetm18:03:54

Not to say software people don’t matter. But we spend so much time on ourselves that everyone else gets totally neglected.

didibus18:03:04

That's true

didibus18:03:28

And honestly, I think we can often be off the mark too. Like we get lost in too much abstraction

💯 4
didibus18:03:33

We lose sight

didibus18:03:31

I read both DDD books, and spent a crazy long time trying to understand, what are you saying, how would I build a system following your descriptions and ideas.

didibus18:03:24

And it's not until I found some other book that I finally understood some parts of it, not all :p

potetm18:03:44

Curious what book made it click for you.

didibus18:03:55

Like how aggregate roots are just supposed to model transactional invariants.

potetm18:03:54

I’ve felt the same every time I have a convo w/ a DDD zealot. I feel like they’re speaking some weird derivative of a language that I know natively. Like Scottish for an English speaker.

potetm18:03:31

Except if you ever try to pin them down, they’re incapable of using normal words, so you never learn anything at all.

didibus18:03:33

Implementing Domain Driven Design by Vernon Vaughn

didibus18:03:11

Haha ya exactly!

potetm18:03:35

Maybe I’ll buy that book, just so I have a translation guide.

didibus18:03:42

Honestly, even after reading this book, it's like... I get it, but I don't lol

facepalm 4
didibus18:03:05

That said, it was the best I've found, goes more concrete

didibus18:03:33

The thing is, the model degenerates in practice and that's the part that is never covered

potetm18:03:57

Curious to hear more.

potetm18:03:15

I get how it’s overly-complex out of the box. But not sure what you mean by “degenerate.”

didibus18:03:30

Like figuring out the bounded context is left as an exercise to the reader. And, it's all just intuition

didibus18:03:07

If you end up with the bad partitioning though, you're stuck

didibus18:03:40

Same with your domain entities, if you mess up your aggregates, the whole thing falls apart

potetm18:03:42

Yeah, honestly the whole read model sounds like utter, excuse my french, horseshit.

didibus18:03:33

So let me get a bit more concrete so I don't do what I'm just describing

4
👍 4
didibus18:03:10

Take "writes". What even is a write?

didibus18:03:24

We're talking writes to the DB off course

didibus18:03:42

Say we have a SQL db

didibus18:03:00

Writes to a DB are thus done with insert or update SQL queries

didibus18:03:22

Ok, so now we are inside our application

didibus18:03:47

We want to process data before we write it to the DB

didibus18:03:30

Now we're in DDD land. Because it's how we model the data inside our app for modifications inside our app

didibus18:03:54

So this is OOP world. You have for each table a Class (more or less)

didibus18:03:02

Where columns are fields

didibus18:03:45

Ok, say we want to capitalize the first name of User?

didibus18:03:51

Normally you might do getUser(Id), which gives you the current user data, and then go User.setName(user.getName().capitalize())

didibus18:03:45

And then you'll do something like user.save()

didibus18:03:57

Which will generate the query and update the DB

didibus18:03:25

Ok, so what happened here? Did we do a write or a read or both?

potetm18:03:09

uh, both? But I would say, primarily, write (since that was the stated purpose).

didibus18:03:10

We did both, because an update requires first reading in the latest data, changing it, and putting it back

didibus18:03:41

But so this is the first challenge you face. And took me a while to figure it out

didibus18:03:59

So after two books, I realize DDD says

didibus18:03:25

Your domain entities like User, they are only designed in terms of writes

didibus18:03:49

And it's super confusing, but they assume a write requires a read

didibus18:03:24

So when you fetch data from the DB and create domain entities out of it, it should be only for the purpose of making modifications to them

didibus18:03:53

When you don't intend to change them, don't use them.

didibus19:03:04

Instead, when you don't intend to change them, use a different set of entities, which are no longer called your domain entities. Those don't need to be modeled as carefully, just have entities in whatever shape and form your presentation layer cares for

didibus19:03:28

And like, this right there, that's 80% of DDD.

didibus19:03:57

I just summarized 3/4 of all the books I read

potetm19:03:28

I actually had the sneaking suspicion that most folks were lost in some OOP mumbo jumbo.

💯 4
didibus19:03:35

Anyways, I'm not sure where I'm going with all this anymore :rolling_on_the_floor_laughing:

didibus19:03:06

I guess, too much fluff, not enough substance is my summary :p

didibus19:03:24

I still like the ideas around DDD

didibus19:03:30

Specifically, I like the idea of spending a lot of time to model your data, with regards to how you're going to modify it over time. I like how it encourages breaking out your application in components which map back to the problem space. And I like how it recommends you build a vocabulary that is as close to what the business people use within your code as well, so that communication is improved

didibus19:03:49

I think a lot of the details in the book beyond that are very OOP specific, and you start to fall in that whole complexity nightmare of design pattern and all that

Spaceman17:03:56

Hi guys, I have a question regarding bidi, but there isn't a bidi channel, so I'll ask here: I am sending an index-handler on "/this-route":

(defn index-handler [req]
  (assoc (resource-response "index.html" {:root "public"})
         :headers {"Content-Type" "text/html; charset=UTF-8"}))

(def routes ["" {"/this-route" {:get index-handler}}]) ;; works
Which works fine.  But when I append anything to this-route, I'm unable to send index-handler even though I can still send a basic res/response:
(def routes ["" {"/this-route" {"" {:get index-handler} ;; doesn't work
                                "/something" {:get index-handler} ;; doesn't work
                                "/something-else" (res/response "some response") ;; works  

}}])
I get the errors in the client side console showing an error in the index.html line, where I start my app:
<script type="text/javascript">myapp.system.go();</script>
and the error is "myapp is undefined." Why might this be, and what am I doing wrong?

lispyclouds18:03:59

You can try the #yada channel

dominicm18:03:11

This doesn't seem to be a bidi question either :)

dominicm18:03:32

#clojurescript is your best bet

dominicm18:03:35

Is your script tag before or after you load your clojurescript?

Spaceman18:03:45

<html lang="en"> <head> <title>My App</title> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link href="css/style.css" rel="stylesheet" type="text/css"> <link rel="shortcut icon" type="image/png" href="favicon1.png"/> </head> <body> <div id="app"></div> <script src="js/compiled/myapp.js" type="text/javascript"></script> <script type="text/javascript">myapp.system.go();</script> </body> </html>

dominicm19:03:04

Hmm, I think I misunderstood. I thought this was about bidi in clojurescript

dominicm19:03:16

Those routes work for me, are you sure they don't work:

user=> (require '[bidi.bidi :as bidi])
nil
user=> (def routes ["" {"/this-route" {"" :index ;; doesn't work
  #_=>                                 "/something" :index-handler ;; doesn't work
  #_=>                                 "/something-else" :some-response }}])
#'user/routes
user=> (bidi/match-route routes "/this-route")
{:handler :index}
user=> (bidi/match-route routes "/this-route/something")
{:handler :index-handler}
user=> (bidi/match-route routes "/this-route/something-else")
{:handler :some-response}
user=> 

braai engineer20:03:25

@pshar10, the src attribute in <script src=js/.." points to a relative path. Try /js/` with a leading slash so that pages relative to the root refer to the same absolute script resource.

Spaceman21:03:53

The leading slash didn't work. In fact js/myapp.js doesn't exist. The myapp.js that I shared was in myapp-root/dev-target/js and not in myapp-root/resources/js. How do I make a js/myapp.js exist?