.NET version by Michał Mac

520 views
Skip to first unread message

Sławek Sobótka

unread,
Aug 21, 2012, 2:54:53 PM8/21/12
to ddd-cqr...@googlegroups.com

Michał Mac

unread,
Aug 22, 2012, 6:12:30 AM8/22/12
to ddd-cqr...@googlegroups.com
The main goal of the project was to demonstrate:
- DDD building blocks in nontrivial examples
- Advanced DDD technics: BCs, Sagas
- Pragmatic CqRS
- Clean domain code, no magic libraries and frameworks

The goals for next iterations are:
- BDD tests
- Automatic testing
- Phone (android, wp7) support
- Integration between BCs written in .Net and Java

Any comments and suggestions are welcome.

Regards,
Michał Mac


W dniu wtorek, 21 sierpnia 2012 20:54:53 UTC+2 użytkownik Sławek Sobótka napisał:
enjoy!

Jose Fernandez

unread,
Jun 3, 2013, 12:03:23 PM6/3/13
to ddd-cqr...@googlegroups.com
Hello Mr. Sobotka.

Congrats in your approach to DDD-CQRS. By far one of the best out there.

Question. Why didn't you use NServiceBus as your "Gate"? I think you could come up with that instead of a homemade bus. People will feel more "safe" about using it.

That's just my opinion.

The other question. Looking at your projects' structure... What's the motivation behind having an .Interface project? Are these the classes that will be exposed (think of an API) to the "world" for each Bounded Context?

Thanks.

On Tuesday, August 21, 2012 2:54:53 PM UTC-4, Sławek Sobótka wrote:
enjoy!

Michał Mac

unread,
Jun 3, 2013, 3:36:25 PM6/3/13
to ddd-cqr...@googlegroups.com

Question. Why didn't you use NServiceBus as your "Gate"? I think you could come up with that instead of a homemade bus. People will feel more "safe" about using it.

That's just my opinion.

It could be implemented as you said (it was planned for step 2). However, many real word systems can (and should) use the in-memory implementation without the need to use any real message bus. "Keep it simple".
 

The other question. Looking at your projects' structure... What's the motivation behind having an .Interface project? Are these the classes that will be exposed (think of an API) to the "world" for each Bounded Context?

Yes, that's correct. They are the public API of the BC. 
I've extracted them from the implementation assembly so that it's harder to reference (by mistate or on purpose) the internals of the domain from the outside.
 
Best Regards,
Mac Michał

Jose Fernandez

unread,
Jun 3, 2013, 4:57:13 PM6/3/13
to ddd-cqr...@googlegroups.com
I totally see the point on the KISS approach, but NServiceBus really offers a lot of good functionality. If i were you, i would've created several samples. This one you're offering, one with a NServiceBus approach, another one with a WCF approach, etc. After all it shouldn't be too hard. It's just add features.

One thing i like is that you have taken the time to write some comments to describe what's going on. In the lack of proper documentation, this fits perfectly fine. One thing you can do, which i think is very smart from microsoft CQRS Journey, is to create a PDF where you explain step by step what's going on. I can help you if you need help. The community will love it. I like Microsoft Journey but just the fact that they are SO (obviously) tied to Azure, makes me put it aside.

There is another "framework". Something called Skritchy or something like that. I don't think is ready for corporate applications but he created a video where he shows very simply how to start off using his libraries. Pretty cool and ingenious. Sometimes a video is WAY better than any book. Like you said... Keep It Simple.

One more question... are all those attributes just to make it easier to register those classes using windsor? Because other than that i don't get it.

Thanks for your responses...

Michał Mac

unread,
Jun 4, 2013, 3:47:24 PM6/4/13
to ddd-cqr...@googlegroups.com

W dniu poniedziałek, 3 czerwca 2013 22:57:13 UTC+2 użytkownik Jose Fernandez napisał:
I totally see the point on the KISS approach, but NServiceBus really offers a lot of good functionality. If i were you, i would've created several samples. This one you're offering, one with a NServiceBus approach, another one with a WCF approach, etc. After all it shouldn't be too hard. It's just add features.

I totally agree with you. Unfortunately, I'm very limited in time now because of the new project I'm working on.
I'll try to include your suggestions in it.
 

One thing i like is that you have taken the time to write some comments to describe what's going on. In the lack of proper documentation, this fits perfectly fine. One thing you can do, which i think is very smart from microsoft CQRS Journey, is to create a PDF where you explain step by step what's going on. I can help you if you need help. The community will love it. I like Microsoft Journey but just the fact that they are SO (obviously) tied to Azure, makes me put it aside.

There's a tutorial in the java version. It's not the same, however the concepts are cross-platform.
 

There is another "framework". Something called Skritchy or something like that. I don't think is ready for corporate applications but he created a video where he shows very simply how to start off using his libraries. Pretty cool and ingenious. Sometimes a video is WAY better than any book. Like you said... Keep It Simple.

Yes, I prefer vides too. They are a way better.
 

One more question... are all those attributes just to make it easier to register those classes using windsor? Because other than that i don't get it.

As for now yes. However they give an explicit intent as what is the main goal of the class.
There'a an idea to create a tool based on the attributes for viewing the whole system architecture.

Sławek Sobótka

unread,
Jun 4, 2013, 4:01:10 PM6/4/13
to ddd-cqrs-sample
Jose, take a look at our wiki: http://code.google.com/p/ddd-cqrs-sample/wiki/TableOfContents
Text references Java classes, but as Michał said: general idea is the
same...
btw: this "map" should help to grasp architecture (links are clickable
and point to the sources): http://prezi.com/hi2dmhfej9zu/ddd-cqrs-sample/

Jose Fernandez

unread,
Jun 5, 2013, 11:43:30 AM6/5/13
to ddd-cqr...@googlegroups.com
Hello Slawek,

Yes, I had already read all the documentation, including the prezi presentation. Very cool.

Now, in my previous post i made a mistake. It's not Skritchy or whatever is called, but Tyrone Groves' Simple Cqrs mini framework. Sorry for the confusion. Here is the link https://github.com/tyronegroves/SimpleCQRS

They included two videos on how to create an application just using their DLLs. Very nice. The reason i want to make emphasis on this is because there are HUNDREDS of blogs out there talking about CQRS and all the whistles and bells... and unfortunately they're creating more confusion than certainty in this subject.

Thank you for the follow up.

Jose Fernandez

unread,
Jun 5, 2013, 4:45:03 PM6/5/13
to ddd-cqr...@googlegroups.com
Question...
Lead has the attribute DomainAggregateRoot but it lacks the inheritance from AggregateRoot

At the same time, coincidentally, all aggregateRoots repositories inherit from GenericRepositoryForBase.... but Lead's repository itself, inherits from GenericRepository directly.

I am trying to find an answer to my own question but can't come up with a good one.

What's the reason for this?

Thanks

Michał Mac

unread,
Jun 6, 2013, 3:06:59 PM6/6/13
to ddd-cqr...@googlegroups.com
Yes, it's on purpose.

You can use the AggregateRoot as a base class in other bounded context, but you do not have to.
I don't like to force people only to cases I can think of so you can choose because you know.
It's not a framework it's a recipe you can follow or use your own when needed.

For example, what if you want to use Guid as your key? With not another framework approach you can do this.

Best Regards,
Mac Michael

Jose Fernandez

unread,
Jun 9, 2013, 12:34:44 PM6/9/13
to ddd-cqr...@googlegroups.com
Awesome. That's what i figured because you implicitly set to int the TKey in those cases where you inherit.

Thanks

Jose Fernandez

unread,
Jun 16, 2013, 1:25:59 AM6/16/13
to ddd-cqr...@googlegroups.com
Question...

I have been trying to "catch" where you initialize the StandardGate :IGate to not avail.

Where exactly in your ContainerInit is this happening?

Thanks

Jose Fernandez

unread,
Jun 16, 2013, 1:42:06 AM6/16/13
to ddd-cqr...@googlegroups.com
Nevermind. Found it.

            container.Register(Classes.FromAssemblyInDirectory(new AssemblyFilter(HttpRuntime.BinDirectory))
                                   .Where(t => t.IsComponentLifestyle(ComponentLifestyle.Singleton))
                                   .StartIfNecessary()
                                   .WithServiceAllInterfaces()
                                   .WithServiceSelf()
                                   .LifestyleSingleton()
                );

You decorated the class StandardGate with a [Component] attribute that has a default Singleton Lifestyle.

Michał Mac

unread,
Jun 17, 2013, 1:30:40 PM6/17/13
to ddd-cqr...@googlegroups.com
Yes, that's correct.

I don't like magic, so there is as little as possible.
You can find much info in ContainerInit class.

Best Regards,
Michael Mac

Jose Fernandez

unread,
Jun 21, 2013, 11:18:47 PM6/21/13
to ddd-cqr...@googlegroups.com
hahaha. So far so good. Sinking in everything.

Speaking of magic... this piece of code

        public void Run<T>(T command)
        {
            // Transaction\Commit\Container CommadnHandler decorators are loaded by default <== THIS IS WHERE I SEE SOME MAGIC
            ICommandHandler<T> handler = Factory.Create<T>(); 
 
            //You can add Your own capabilities here: dependency injection, security, transaction management, logging, profiling, spying, storing commands, etc
 
            handler.Handle(command);
 
            //You can add Your own capabilities here
        }

I know it has to do with your CommandHandlerFactoryComponentSelector inheriting from DefaultTypedFactoryComponentSelector

How specifically this three decorators are loaded by default. This one i can't figure it out. Some help here please?

Thanks

Jose Fernandez

unread,
Jun 22, 2013, 2:06:00 PM6/22/13
to ddd-cqr...@googlegroups.com
Nevermind :)


Thank you thou. I am learning a bunch of new stuff.

Michał Mac

unread,
Jun 24, 2013, 11:41:21 AM6/24/13
to ddd-cqr...@googlegroups.com
Exactly.

There is typed factory facility used (so as to not couple gate with specific conatiner ) and decorator automatic chaining.

Of course if we don't want to use it we can create our own implementation of ICommandHandlerFactory (POCO) and build decorator by ourselves.

Best Regards,
Mac Michał

Jose Fernandez

unread,
Jun 25, 2013, 9:54:36 PM6/25/13
to ddd-cqr...@googlegroups.com
Perfect explanation, thanks.

New question.

In your class EntityManager you define another typed factory called IPerRequestSessionFactory. Basically you're returning an ISession. 
        public ISession CurrentSession
        {
            get { return _perRequestSessionFactory.Create(); }
        }

Wouldn't be the same to return SessionFactory.GetCurrentSession()? As far as I have understood, Once your typedFactory executes Create(), that's the equivalent to kernel.Resolve<ISession> and since the lifestyle is set to PerWebRequest, then I am assuming that changing _perRequestSessionFactory.Create() for SessionFactory.GetCurrentSession() would yield the same result?

What's the motivation behind this typedfactory? Seems like an overhead to me. 

Thanks

Michał Mac

unread,
Jun 26, 2013, 4:24:09 PM6/26/13
to ddd-cqr...@googlegroups.com
Yes, you're right, it's the same.

SessionFactory.GetCurrentSession() return a new session for each web request by default.

However, I don't want to introduce too much coupling so I oftne define such interface. If I want to use SessionFactory I make it explicit in the repo.
Secondly, for me it's easier to create integration test using this approach than NHibernate implementation. You only have to change the lifestyle mode.

Moreover, I use this construct during workshops to show how you can do this (session management, not only NHibernate) on your own using Castle Windsor.

Hope these help,
Mac Michael

Jose Fernandez

unread,
Jun 26, 2013, 7:37:27 PM6/26/13
to ddd-cqr...@googlegroups.com
Beautiful. Thank you so much Michael. I am really learning a lot with this sample. Expect more questions coming.... :)

Jose Fernandez

unread,
Jun 27, 2013, 12:40:42 PM6/27/13
to ddd-cqr...@googlegroups.com
Hello Michael,

Question.... related to Windsor with ISessionFactory and IHandlerSelector.

I have been trying to implement IHandlerSelector interface to determine which SessionFactory OR EntityManager i am going to use depending on a session variable("PA" or "GA"). Our system, for some reason, relies on two identical databases (schema, not the data) sitting on two different servers. Depending on which "Region" our employees wants to work on, they need to switch the region using a dropdown.

Now, i am a little confused about who should i really register twice. The EntityManager with a dynamic property, let's say, a constructor parameter that specifies the connection string to use in the web.config or create two SessionFactory properties in the EntityManager that each one privately creates an ISessionFactory for each case. 

Could you give me a hand on this? In the meantime i am gong to post this question on Castle Project group, and if i am lucky, i will get a response. I read they have a tendency to let posts bury themselves :)

Michał Mac

unread,
Jul 15, 2013, 6:17:07 PM7/15/13
to ddd-cqr...@googlegroups.com
Are that schemas identical in this two databases?

If yes than I would implement without using Castle so as to not introduce unnecessary dependencies.
Simple method ChangeRegion() which selects appropriate connection string and builds factory.


Best Regards,
Michael

Jose Fernandez

unread,
Jul 29, 2013, 1:28:41 AM7/29/13
to ddd-cqr...@googlegroups.com
I came up with a pretty decent solution for multiple databases. I will post it here if requested.

One question... back at your code. You have Clients in the SALES BC and Customer/Leads in the CRM BC. I think we all agree is pointing at the same person. Let's say that in the sales funnel, the person starts as a Lead, then becomes a Customer by Purchasing something making him a Client.

My question is, Why to have three separates representation of the same "guy". Couldn't it be like a "Shared Kernel Aggregate"? I don't know if such a thing exist. It kinda bothers me a little bit to have three tables Client/Customer/Leads for the same "thing". Plus in the example is not clear (CRM is not implemented) how you communicate among BC. I read your documentation but I couldn't find any valuable clues about it. 

How would that process be? Let's say that you need to add this Lead/Customer/Client an address to ship the order. Which one would you pick? I guess ShippingAddress in the Shipping BC? With a Id pointing to? Customer? Client? Should you add the address directly to Customer? For direct mail for example, since it has nothing to do with Shipping?

Help please...

Thanks

Sławomir Sobótka

unread,
Jul 29, 2013, 6:26:16 AM7/29/13
to ddd-cqr...@googlegroups.com
Customer/Client concept separation is just a sample of crucial DDD
technique: Bounded Context.
In some domains Customer and Client could be the same as You suggest.
But in this sample we assume that they are different concepts form
different BCs - just to illustrate this problem and techniques.

According to communication question:
We can assume that CRM holds address data. Therefore other BCs
(modules) can ask CRM about that data (calling application service,
that returns DTO). Another approach could be: CRM publishes an Event
then client data changes (Event contains Aggregate Snapshot that
belongs to the Shared Kernel) and other BCs can "cache" needed data
inside their model.
> --
> You received this message because you are subscribed to the Google Groups
> "ddd-cqrs-sample" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to ddd-cqrs-samp...@googlegroups.com.
> For more options, visit https://groups.google.com/groups/opt_out.
>
>

Jose Fernandez

unread,
Jul 30, 2013, 2:10:10 PM7/30/13
to ddd-cqr...@googlegroups.com
I am still confused about.... let's say...
I know you are not here to teach me DDD or CQRS, I am just trying to make sense of your code.

Assuming that they are different concepts from different BCs...

You have two IDs (CustomerID and ClientID) and two tables. If there is no "relationship" between these tables, how would you "know" ClientID = CustomerID... let's say that CRM department adds 17 new Customers but they haven't purchased anything, so, at this point you are short by 17 "Clients", so you can't really match IDs. You can't assume that they will have the same ID in different tables since you're not creating the two aggregates at the same time (or you could and that could be a risky very unsafe solution) or I can only see one more solution...

Creating a foreign key in one of the tables. 

The way it is right now...

What if you need a report with all the purchases that went to a zip code? Duplicating the address at the moment of the purchase? Yes. But, from Who? Which Customer was this Client?

Once again, I know you are not here to teach me DDD or CQRS, I am just trying to make sense of your code :)

Thanks a lot for all the help.

Sławomir Sobótka

unread,
Jul 30, 2013, 5:44:57 PM7/30/13
to ddd-cqr...@googlegroups.com
General problem is: "Context Map" - one of the DDD Strategic Patters.

Solution is quite simple: introduce so called Correlation ID - it ma
be client number, or some natural id data.
In this naive sample it may look like artificial problem, but idea is
to touch "Context Mapping"

Jose Fernandez

unread,
Aug 7, 2013, 1:45:30 AM8/7/13
to ddd-cqr...@googlegroups.com
Got it.
I will read more into Context Mapping.

One question, if you were to use either fluent mapping or xml, where would you create this classes/xml? Inside each BC in the Infrastructure folder? I am assuming since you are pointing to the aggregate roots in the BC to locate types in its Assembly.

Thanks

Sławomir Sobótka

unread,
Aug 7, 2013, 3:22:22 AM8/7/13
to ddd-cqr...@googlegroups.com
That's the question to Michael:)

Michał Mac

unread,
Aug 13, 2013, 3:12:22 AM8/13/13
to ddd-cqr...@googlegroups.com
In this project I would place them in infrastructure folder.
However in bigger solutions I create separate Infrastructure project where I can place the files and all other data-access components: repo implementations, data agents, webservice proxy, etc.

Jose Fernandez

unread,
Oct 2, 2013, 3:51:25 PM10/2/13
to ddd-cqr...@googlegroups.com

Would you consider Contributors to your code?

It's one of the best samples out there. It would be a shame to leave it halfway abandoned... 

Michał Mac

unread,
Oct 4, 2013, 2:44:57 AM10/4/13
to ddd-cqr...@googlegroups.com
No problem.

What do you want to add?
Reply all
Reply to author
Forward
Message has been deleted
Message has been deleted
0 new messages