I am learning CQRS and event sourcing architecture (with nestjs), and I am a bit confused by aggregates.
I am following the kind of architecture explained here : https://danielwhittaker.me/2020/02/20/cqrs-step-step-guide-flow-typical-application/
If I understand well, the aggregate root is my "Write Model". It update itself using events which will be committed to the event bus, and I get its current state using event history (or cache).
As I never really read the data in the aggregate root (only the data needed to accept or not the next commands), and I don't persist it (the events are), should I really need to keep all my data in aggregates?
I am not sure if I am clear, so let's see a simplified example :
I've got a CreateProduct command for my shopping website, and a ProductCreated event. I use the content of the event to create views for some query like GetProductByCategory, SearchProduct, ...
Here the command :
class CreateProduct {
public name: string;
public description?: string;
// ...
}
I skip the commandHandler. If I understand well, my aggregate root should be like :
class ProductAggregateRoot extends AggregateRoot {
public id: string;
private name: string;
private description?: string;
create(data: { name: string, description?: string }) {
if (! data.name) {
throw Error('Name is required');
}
this.apply(new ProductCreated(uuid(), data));
}
onProductCreated(event: ProductCreated) {
this.id = event.id;
this.name = event.name;
this.description = event.description;
}
}
Can I just do :
class ProductAggregateRoot extends AggregateRoot {
public id: string
create(data: { name: string, description?: string }) {
if (! data.name) {
throw Error('Name is required');
}
this.apply(new ProductCreated(uuid(), data));
}
onProductCreated(event: ProductCreated) {
this.id = event.id;
}
}
as I never use name and description on the command side? It is just usefull for me to create the views on the query side.
It confuses me because it seems to be far from the domain (a Product is more than just an id). But I don't get the point to keep these data here. If I change my mind, I can add it later and rebuild my aggregate roots from the history.
I do not know about nestjs in particular, but in a general implementation of an Event Sourcing application is absolutely OK to only us the fields you need in order to satisfy your business rules. So in this case, since there are no rules involving name or description they don't need to be materialized into the aggregate root class when you handle additional commands (maybe DeleteProduct or similar).
When you apply your next command your application should materialize the aggregate root again from the history of events, so yes you can add fields later if needed.
You can see an example from the Serialized Java client here (https://serialized.io/java/working-with-aggregates/) where OrderPlaced event contains an amount that is not read into the transient state of the Order aggregate when handling commands.
Related
the most common way to implement aggregates is to create a god class with enum status and "if-ladder", like below:
public class Order {
private OrderId id;
private PropertyA a;
private PropertyB b;
private OrderStatus status;
public void doSthWithA() {
if(status != OrderStatus.A) {
//throw illegal argument
}
//do sth with PropertyA
status = OrderStatus.B;
}
public void doSthWithB() {
if(status != OrderStatus.B) {
//throw illegal argument
}
//do sth with PropertyB
}
}
Order class isn not coherent, because doSthWithA uses PropertyA and doSthWithB uses PropertyB.
Isn't better way doing it in this way:
public class OrderA {
private OrderId id;
private PropertyA a;
public OrderB doSthWithA() {
//do sth with PropertyA
return new OrderB(id);
}
}
public class OrderB {
private OrderId id;
private PropertyB b;
public void doSthWithB() {
//do sth with PropertyB
}
}
?
Anyway I have a question. We could persist both aggregates in one table ORDER or two tables: ORDER_A and ORDER_B.
But what are strategies to test which order state is newest?
Let's assume that someone saves OrderA to DB, next executes doSthWithA and saves OrderB to DB.
Futher when we do some query how could we resolve the newest state? Should we add some version or timestamp to aggregates?
And what about REST services?
With one god class Order the REST services could look like:
/orders/{id}/do-sth-with-a and
/orders/{id}/do-sith-with-b
With second solution could we have:
/a-orders/{id}/do-sth-with-a and
/b-orders/{id}/do-sith-with-b
?
Isn't better way doing it in this way
Not necessarily better, because there are trade offs. However, it is common that the benefits of a design with smaller aggregates outweigh the costs.
Vaughn Vernon, in Implementing Domain Driven Design, proposes the rule "Design Small Aggregates".
Roughly, each aggregate "should" enclose coupled information; typically graphs of values that must be internally "consistent". If you find that your values form two discrete sets that have only a single identifier in common, that's a good sign that there is an opportunity to reduce the aggregate further.
We could persist both aggregates in one table ORDER or two tables: ORDER_A and ORDER_B. But what are strategies to test which order state is newest?
Real answer: if you actually care about "newest", then you should be modeling time in your domain logic.
It's not uncommon to throw general purpose timing information into a design, but you want to be careful about entangling general purpose timing used for operation and analysis from your domain timing.
And what about REST services?
Your resource model is not your domain model. Having a single "god" resource in your resource model has a completely different set of trade offs from "god" aggregates in your domain model.
It's completely normal to have one web resource that renders information from multiple aggregates.
This was asked during an interview.
There are different manufacturers of buses. Each bus has got different models and each model has only 2 variants. So different manufacturers have different models with only 2 variants. The interviewer asked me to design a standalone program with just classes. She mentioned that I should not think about databases and I didn't have to code them. For example, it could be a console based program with inputs and outputs.
The manufacturers, models and variants information should be held in memory (hard-coded values were fine for this standalone program). She wanted to observe the classes and my problem solving approach.
She told me to focus on implementing three APIs or methods for this system.
The first one was to get information about a particular bus. Input would be manufacturer name, model name and variant name. Given these three values, the information about a particular bus such as its price, model, year, etc should be shown to the client.
The second API would be to compare two buses and the output would be to list the features side by side, probably in a tabular format. Input would be the same as the one for the first API i.e. manufacturer name, model name and variant name for both the buses.
The third one would be to search the buses by price (>= price) and get the list of buses which satisfy the condition.
She also added that the APIs should be scalable and I should design the solution with this condition on my mind.
This is how I designed the classes:
class Manufacturer {
private String name;
private Set<Model> models;
// some more properties related to manufacturer
}
class Model {
private String name;
private Integer year;
private Set<Variant> variants;
// some more properties related to model
}
class Variant {
private String name;
private BigDecimal price;
// some more properties related to variant
}
class Bus {
private String manufacturerName;
private String modelName;
private String variantName;
private Integer year;
private BigDecimal price;
// some more additional properties as required by client
}
class BusService {
// The first method
public Bus getBusInformation(String manufacturerName, String modelName, String variantName) throws Exception {
Manufacturer manufacturer = findManufacturer(manufacturerName);
//if(manufacturer == null) throw a valid exception
Model model = findModel(manufacturer);
// if(model == null) throw a valid exception
Variant variant = findVariant(model);
// if(variant == null) throw a valid exception
return createBusInformation(manufacturer, model, variant);
}
}
She stressed that there were only 2 variants and there wouldn't be any more variants and it should be scalable. After going through the classes, she said she understood my approach and I didn't have to implement the other APIs/methods. I realized that she wasn't impressed with the way I designed them.
It would be helpful to understand the mistake I made so that I could learn from it.
I interpreted your 3 requirements a bit differently (and I may be wrong). But it sounds like the overall desire is to be able to perform different searches against all Models, correct?
Also, sounds to me that as all Variants are Models. I suspect different variants would have different options, but nothing to confirm that. If so, a variant is just a subclass of a particular model. However, if variants end up having the same set of properties, then variant isn't anything more than an additional descriptor to the model.
Anyway, going on my suspicions, I'd have made Model the center focus, and gone with:
(base class)
abstract class Model {
private Manufacturer manufacturer;
private String name;
private String variant;
private Integer year;
private BigDecimal price;
// some more properties related to model
}
(manufacturer variants)
abstract class AlphaModel {
AlphaModel() {
this.manufacturer = new Manufacturer() { name = "Alpha" }
}
// some more properties related to this manufacturer
}
abstract class BetaModel {
BetaModel() {
this.manufacturer = new Manufacturer() { name = "Beta" }
}
// some more properties related to this manufacturer
}
(model variants)
abstract class AlphaBus : AlphaModel {
AlphaBus() {
this.name = "Super Bus";
}
// some more properties related to this model
}
abstract class BetaTruck : BetaModel {
BetaTruck() {
this.name = "Big Truck";
}
// some more properties related to this model
}
(actual instances)
class AlphaBusX : AlphaBus {
AlphaBusX() {
this.variant = "X Edition";
}
// some more properties exclusive to this variant
}
class AlphaBusY : AlphaBus {
AlphaBusY() {
this.variant = "Y Edition";
}
// some more properties exclusive to this variant
}
class BetaTruckF1 : BetaTruck {
BetaTruckF1() {
this.variant = "Model F1";
}
// some more properties exclusive to this variant
}
class BetaTruckF2 : BetaTruck {
BetaTruckF2() {
this.variant = "Model F2";
}
// some more properties exclusive to this variant
}
Then finally:
var data = new Set<Model> {
new AlphaBusX(),
new AlphaBusY(),
new BetaTruckF1(),
new BetaTruckF2()
}
API #1:
var result = data.First(x => x.manufacturer.name = <manufactuer>
&& x.name = <model>
&& x.variant = <variant>);
API #2:
var result1 = API#1(<manufacturer1>, <model1>, <variant1>);
var result2 = API#1(<manufacturer2>, <model2>, <variant2>);
API #3:
var result = data.Where(x => x.price >= <price>);
I would say your representation of the Bus class is severely limited, Variant, Model, Manufacturer should be hard links to the classes and not strings. Then a get for the name of each.
E.G from the perspective of Bus bus1 this.variant.GetName() or from the outside world. bus1.GetVariant().name
By limiting your bus to strings of it's held pieces, you're forced to do a lookup even when inside the bus class, which performs much slower at scale than a simple memory reference.
In terms of your API (while I don't have an example), your one way to get bus info is limited. If the makeup of the bus changes (variant changes, new component classes are introduced), it requires a decent rewrite of that function, and if other functions are written similarly then all of those two.
It would require some thought but a generic approach to this that can dynamically grab the info based on the input makes it easier to add/remove component pieces later on. This will be the are your interviewer was focusing on most in terms of advanced technical&language skills. Implementing generics, delegates, etc. here in the right way can make future upkeep of your API a lot easier. (Sorry I don't have an example)
I wouldn't say your approach here is necessarily bad though, the string member variables are probably the only major issue.
I'm building a RESTful interface on a Grails 2.1.1 application. How should I implement search operations? I don't want to repeat huge amounts of code, which my current thinking would require.
The server structure is quite normal Grails-MVC: domain classes represent data, controllers offer the interface and services have the business logic. I use command objects for data binding in controllers but not on service methods. The client is a web UI. My goal is to have search URLs like this:
/cars/?q=generic+query+from+all+fields
/cars/?color=red&year=2011
(I'm aware of the debate on the RESTfulness of this kind of URLs with query strings: RESTful URL design for search. While I think this is the best model for my purpose, I'm open to alternatives if they make the API and the implementation better.)
As you can see from the code examples below my problem is with the second kind of URL, the field-specific search. In order to implement this kind of search operation for several domain classes with lots of fields my method signatures would explode.
There probably is a "Groovy way" to do this but I'm still a bit of a n00b in finer Groovy tricks :)
Domain:
class Car {
String color
int year
}
Controller:
class CarsController {
def carService
def list(ListCommand cmd) {
def result
if (cmd.q) {
result = carService.search(cmd.q, cmd.max, cmd.offset, cmd.order, cmd.sort)
}
else {
result = carService.search(cmd.color, cmd.year, cmd.max, cmd.offset, cmd.order, cmd.sort)
}
render result as JSON
}
class ListCommand {
Integer max
Integer offset
String order
String sort
String q
String color // I don't want this field in command
int year // I don't want this field in command
static constraints = {
// all nullable
}
}
// show(), save(), update(), delete() and their commands clipped
}
Service:
class CarService {
List<Car> search(q, max=10, offset=0, order="asc", sort="id") {
// ...
}
List<Car> search(color, year, max=10, offset=0, order="asc", sort="id") {
// ...
}
}
UrlMappings:
class UrlMappings {
static mappings = {
name restEntityList: "/$controller"(parseRequest: true) {
action = [GET: "list", POST: "save"]
}
name restEntity: "/$controller/$id"(parseRequest: true) {
action = [GET: "show", PUT: "update", POST: "update", DELETE: "delete"]
}
}
}
You can get all this parameters from params, like:
result = carService.search(params.color, params.year as Integer, cmd.max, cmd.offset, cmd.order, cmd.sort)
All values of params map are strings, so you should convert it to appropriate data structures in controller (and it's better to check that params.year is actual number)
Update
If you don't want to writer field names, you can pass it as a Map:
resutl = carService.search(params)
where
List<Car> search(Map params)
I have a domain object which has a collection of primitive values, which represent the primary keys of another domain object ("Person").
I have a Wicket component that takes IModel<List<Person>>, and allows you to view, remove, and add Persons to the list.
I would like to write a wrapper which implements IModel<List<Person>>, but which is backed by a PropertyModel<List<Long>> from the original domain object.
View-only is easy (Scala syntax for brevity):
class PersonModel(wrappedModel: IModel[List[Long]]) extends LoadableDetachableModel[List[Person]] {
#SpringBean dao: PersonDao =_
def load: List[Person] = {
// Returns a collection of Persons for each id
wrappedModel.getObject().map { id: Long =>
dao.getPerson(id)
}
}
}
But how might I write this to allow for adding and removing from the original List of Longs?
Or is a Model not the best place to do this translation?
Thanks!
You can do something like this:
class PersonModel extends Model<List<Person>> {
private transient List<Person> cache;
private IModel<List<String>> idModel;
public PersonModel( IModel<List<String>> idModel ) {
this.idModel = idModel;
}
public List<Person> getObject() {
if ( cache == null ) {
cache = convertIdsToPersons( idModel.getObject() );
return cache;
}
public void setObject( List<Person> ob ) {
cache = null;
idModel.setObject( convertPersonsToIds( ob ) );
}
}
This isn't very good code but it shows the general idea. One thing you need to consider is how this whole thing will be serialised between requests, you might be better off extending LoadableDetachableModel instead.
Another thing is the cache: it's there to avoid having to convert the list every time getObject() is called within a request. You may or may not need it in practice (depends on a lot of factors, including the speed of the conversion), but if you use it, it means that if something else is modifying the underlying collection, the changes may not be picked up by this model.
I'm not quite sure I understand your question and I don't understand the syntax of Scala.
But, to remove an entity from a list, you can provide a link that simply removes it using your dao. You must be using a repeater to populate your Person list so each repeater entry will have its own Model which can be passed to the deletion link.
Take a look at this Wicket example that uses a link with a repeater to select a contact. You just need to adapt it to delete your Person instead of selecting it.
As for modifying the original list of Longs, you can use the ListView.removeLink() method to get a link component that removes an entry from the backing list.
I have an application which does data processing. There is
class Pipeline {
IEnumerable<IFilter> Filters {get; set;}
I register filters implementations as
builder.RegisterType<DiversityFilter>().As<IFilter>();
builder.RegisterType<OverflowFilter>().As<IFilter>();
...
So far so good. Now, for experimentation and fine-tuning I want to be able to override any filter implementation in config file with a program(script) which would read data from stdin, process it and send data to stdout. I've implemented a module with "fileName", "args" and "insteadOf" custom properties, described module in xml and got it called.
In the module I register my "ExecutableFilter" but how do I make it run "instead of" desired service? If I try do it like this:
builder.RegisterType<ExecutableFilter>().As<DiversityFilter>()
then I get an exception " The type 'ExecutableFilter' is not assignable to service 'DiversityFilter'.". Ok, this is logical. But what are my options then?
Once you've overridden the registration for IFilter "After" with your wire-tap, you won't be able to resolve it from the container, as the new registration will be activated instead, hence the circular lookup.
Instead, create and register a module that hooks into the filter's creation, and replaces the instance with the 'wire tapped' one:
class WiretapModule : Module
{
override void AttachToComponentRegistration(
IComponentRegistration registration,
IComponentRegistry registry)
{
if (registration.Services.OfType<KeyedService>().Any(
s => s.ServiceKey == After && s.ServiceType == typeof(IFilter)))
{
registration.Activating += (s, e) => {
e.Instance = new WireTap((IFilter)e.Instance, new ExecuteProvider(fileName, args))
};
}
}
}
(Cross-posted to the Autofac group: https://groups.google.com/forum/#!topic/autofac/yLbTeuCObrU)
What you describe is part container work, part business logic. The challenge is to keep separation of concerns here. IMO, the container should do what it is supposed to do, that is building and serving up instances or collections thereof. It should not do the "instead of" in this case. I would rather "enrich" the services with enough information so that the pipeline make the decision.
The "enrichment" can be accomplished by making the ExecutableFilter implement a more distinct interface.
interface IInsteadOfFilter : IFilter { }
...
builder.RegisterType<ExecutableFilter>().As<IFilter>();
...
class Pipeline
{
IEnumerable<IFilter> Filters {get;set;}
public void DoTheFiltering()
{
var filters = Filters.OfType<IInsteadOfFilter>();
if (!insteadof.Any())
filters = Filters;
foreach(var filter in filters)
{
...
}
}
You could also solve this using the metadata infrastructure, which gives us an even more expressive way of differentiating services.