4 ms·
> Often yes, people do starting adding queues, materialised views to CQRS which can make it complicated. You don't say?? You don't say?? Sorry to be flip, I
by EdSharkey 9y ago
> Often yes, people do starting adding queues, materialised views to CQRS which can make it complicated.
You don't say?? You don't say??
Sorry to be flip, I hope you can tell that I've been burned. Badly. Thanks for your detailed response. You obviously care and are not a stupid person nor do you come off sounding vain.
But, you're not selling me on CQRS at all. What you've described is just classifications and organization for types in a sane sounding UI design that happen to have similar roles as types in a CQRS system.
If you were selling me on CQRS, you'd start by talking about data flow. Something like, "it's a realtime, live multiuser system where all commands are queued, transformed to system events, and those events are committed to log (via another queue, we have to synchronize after all) that stretches back into time. We can replay those events, rewind time, events are merged ..." And it goes on and on into the stratosphere of architecture astronaut-hood...
My problem with your response is I honestly can't trust what you say here until I do a code review. Is your actual code pathological, or are you whitewashing the constant twizzling and niggling you have to do to keep your ship afloat? How bad, honestly, do you have to work to add a new feature? What's your velocity like? I want to see how much work and layers there are in your code to do data type transformation.
Data transformation is where El Diablo lives, because data transformation requires lots of people to agree and business terms to meet code - it's the unholy marriage of garbage disposal, forest fire, and whirlwind. CQRS seems to invite needless data transforms that other architectures do not require, and that's the pukey taste in my mouth when I have discussions about CQRS.
- UK-AL 9y ago"it's a realtime, live multiuser system where all commands are queued, transformed to system events, and those events are committed to log (via another queue, we have to synchronize after all) that stretches back into time. We can replay those events, rewind time, events are merged ..." And it goes on and on into the stratosphere of architecture astronaut-hood..." But that isn't CQRS. That's event sourcing, a complicated implementation of event sourcing. CQRS can work on a standard SQL system, you can design the database using a standard normalised database. All that has to be different is that commands and queries are separate. A simple implementation; A command can literally be var command= new AcceptOfferCommand(db); command.Execute(); A query can be var query = new AvailableOffersQuery(db); var viewModel = query.Execute() Inside the command you may retrieve a domain object from repository, and execute a method on it. Inside the query method you may just perform a raw sql statement which grabs data from multiple tables, populates a viewModel and returns it. Rather trying to retrieve multiple domain objects from multiple repositories and then shuffling that data into a result.. That's one way of doing simple cqrs. It can be simpler than this. But this code just made it obvious. CQRS allows you do very complicated things, but it doesn't mean you have to.
- EdSharkey 9y agoAh, well CQRS is only justifiable when you're selling the work if you couple it with the ES, and the more complex it is, the better the sales job and the budget. It's like peanut butter and jelly. My main point in replying to you was that you weren't selling me on whatever brand of CQRS you think you've got. Why? It seems like you're atomizing your business logic into a fine mist, why is that good? And you still haven't talked about all the myriad transforms you do: where's the payoff? Does YAGNI apply in your case?
- UK-AL 9y agoWell each command is a use case. Each use case can be tested independently without having setup controllers and their dependencies, or big service layers and their dependencies. Plus I can run the usecases from a console frontend for quick testing without much setup. I don't really do any transforms other than mapping domain objects into the dB or database results into a query result. Why do I need it? Because I practise DDD, and domain objects are not designed for queries. To populate a single view you have pull multiple domain objects from repos. This can be slow and adds complexity. Query objects allow me to query the database using standard SQL or stored procedure and put the output into query result using only a single query. These queries can as complicated and optimised as they need to be. Meaning I can avoid all DDD abstractions that I don't need for querying, but I do need for enforcing complicated business rules on the command side.
- EdSharkey 9y agoIf you're able to reuse (through encapsulation or extension) your domain object types in your commands and queries without transformations, then your pattern sounds sane to me.
- bonesss 9y agoThe entire point of the Separation in CQRS is to avoid unnecessary coupling between reporting concerns, GUI concerns, and user concerns. The act of starting an order does not look like an order. Asking for an order cancellation does not look like an order. Using GraphQL to pull an order summary with report-specialized drill down capabilities does not look like an order. These specialized domain objects should be modeled individually. By trying to encapsulate all these facets in a single object what you get is tight coupling, compromises, domain impedance, logical errors, and slow development. In context: One of the root principles of DDD is that each domain represents its entities as is befitting that domain. Domain entities should be meaningful in their domain and _not_ corrupted by every niggling redigestion of the same facts through tens, or hundreds, of simultaneous conflicting views... Reporting concerns should be first-class citizens when solving reporting, for example.... View concerns and high-load systems often require denormalization, materialization, transformation, and replication that has very little to do with the user of origin while also _destroying_ the premises of traditional ORM driven RMDB interactions. At scale, under load, while supporting multiple N-tiered applications and their accordant services, unified domain models break down. Aggregate boundaries map these epistemological distinctions. CQRS on top of that is just good engineering. In the same way modern car-tunnel builders build two separate tunnels for traffic in each direction, CQRS isolates low-frequency user interaction from high-frequency reporting (or vice versa!), allowing independent scaling and direct delivery of features without impossible coordination activities between teams or finding silver-bullet technologies that may or may not exist. That said: these are Enterprise solutions to Enterprise issues... Scale is the reason they exist. If you aren't looking at a horrible mess around a unified domain model then these solutions might not apply. If you aren't dealing with multiple simultaneous data delivery platforms (mixing SQL server and Oracle and Mongo DB and S3 and DocumentDB and DynamoDB all at once), these solutions may not apply. If you're not balancing multiple teams working on multiple products that have a constant need for harmonic data exchange, these solutions may not apply. If you're not juggling BigData, if you're not dealing with complex business logic, if scaling up an extra ten thousand users isn't something you deal with, if you're not supporting multiple client types, and so on: these solutions may not apply.