UnitOfWork instead of calling save() explicitly?

Hi Allard,

I commited a bunch of files to the Axon Auction Example but I got
stucked...

In the JavaDoc of Repository's save method there is a hint:
"You are recommended to use a UnitOfWork instead of calling
<code>save()</code> explicitly."

But if I don't call "save(..)" explicitly nothing get's stored...

Maybe you can take a look?

Here is the current configuration:

http://code.google.com/p/axon-auction-example/source/browse/trunk/auction-command-server/src/main/resources/application-context.xml

Cheers,
Michael

I checked the context file, and everything looked absolutely fine. I did notice that you are using Axon 0.6. Do you prefer to work on a stable release? The 0.7 version has some nice features that might make things easier. Spring Namespace support, for example.

Anyway, I checked the command handler too. That’s where I discovered something. You should call repository.add(aggregate) to let the repository know that you have created a new aggregate.

So, after:
User user = new User(…);
you call:
repository.add(user);

The API of you command handler gives me the impression that you have the intent to return a result for most -if not all- the command. You should always try to model the process in such a way that you can use fire-and-forget commands. A good command never fails.

Cheers,

Allard

I did notice that you are using Axon 0.6. Do you prefer to work on a stable
release? The 0.7 version has some nice features that might make things
easier. Spring Namespace support, for example.

Hmm... Is there a Maven Snapshot available?

Anyway, I checked the command handler too. That's where I discovered
something. You should call repository.add(aggregate) to let the repository
know that you have created a new aggregate.

OK, I'll try that.

The API of you command handler gives me the impression that you have the
intent to return a result for most -if not all- the command. You should
always try to model the process in such a way that you can use
fire-and-forget commands. A good command never fails.

Sounds good but you will always have at least some error conditions. I
don't want to transport Exceptions from the Command Server to the
Client as I want to keep the Command API as language agnostic as
possible. As you may have noticed I used the Hessian as transport
protocol. This way other languages that may not even have the concept
of an Exception can use the command service. But of course you are
right, there won't be (many) other scenarios beyond the "Create
Object" case that should transport additional data.

Cheers,
Michael

Yes, there is a maven snapshot in the sonatype repository.

Check this page: http://code.google.com/p/axonframework/wiki/Downloads#Snapshot_release

The biggest downside of the snapshot is that the reference documentation is not completely up-to-date.

Cheers,

Allard

> I did notice that you are using Axon 0.6. Do you prefer to work on a stable
> release? The 0.7 version has some nice features that might make things
> easier. Spring Namespace support, for example.

I switched to the new 0.7-SNAPSHOT and found the source attached to it
is still 0.6

Could you check that?

Cheers,
Michael

Oh, and about the response on commands:

Udi wrote a nice blog that relates to failing commands:
http://www.udidahan.com/2010/08/31/race-conditions-dont-exist/

When you say “beyond the Create Object” commands, do you mean that you always expect a return value on those commands? You’re probably returning the generated identifier there. In my projects, I use client-generated identifiers. We only have a single command that has a return value in the entire application. And the only reason it’s there is that my creativity is too limited to find a way around it.

Cheers,

Allard

My bad. I did a few “mvn clean deploy” actions lately. I didn’t realise that I was updating the jar files, but not the source jars.

I’ve just deployed the latest snapshot, including sources.

I think it's all more related to giving a clear error code & message.

In the Axon Auction Example we have for example a user registering
with a user id (Something like "peter123"). If the user id is already
in use by another user the command will fail.

I gues you modeled that with an Exception in your applications? You
throw things like "AggregateNotFoundException"? This is simply
replaced with a result type that contains informations like "error
code" and "error message":
http://code.google.com/p/axon-auction-example/source/browse/trunk/auction-command-api/src/main/java/org/fuin/auction/command/api/CommandResult.java

The other point is creating a new aggregate - Returning the UUID (or
with Axon 0.7 the new "AggregateIdentifier" :wink: with a Create Command
seems very natural to me. In fact this is the only kind of return
value I see at the moment for command execution (beyond above error
information). Creating some kind of query just to return a new
identifier seems to be overkill and generating it client side prevents
a central generation of the value.

We have the policy in our application that the client is responsible for sending a command that makes sense. That means the client should do a query to check for uniqueness of a username. It is then able to display nice error messages to the user. In our case, a failing command throws an exception, but it is also perfectly possible to publish an UnableToCreateUserEvent (an application event, I guess, because no state was changed). In the end, it’s a matter of taste, really.

When i say “client generated id’s”, I don’t mean an ID that the client asks by doing a query. I mean that the clients comes up with an identifier on its own. That’s why I strongly believe in UUID’s. The client just say “create an aggregate for me with ID: UUID.randomUuid()”. The client sends the command and can (parallel) show the details of the newly created aggregate in the details screen, for example. No need to wait for a response from the server there. That increases perceived performance of your application dramatically.