In conclusion: it looks like you put a lot of effort in a good looking and well polished cqrs framework. I think this would probably be great to introduce people to cqrs, but IMO I think would only advise it for learning projects (for now)
Have you watched my talk on occasionally connected clients a while ago at skillsmatter? There isnt really anything to abstract away
Tom, can you elaborate your assertion "it looks a lot like a 4GL, and I assume we all know what that means..."?
Yes now I recognize the meaning. I have had my fair share of trying to
find the "sweet spot" with 4GL, but the compromises and "cutting
corners" always bite back.
These abstractions do not cause compromises. If something is missing
in the logical level, it should be added, as well as the
implementation can be added/modified by chaning the T4 generators that
The modifications to the schema or generators is faster to do than
revisit/update the example/reference HOW-TO documentation to guide the
I'll be updating the CQRS specific modifications as well, but the
"Modifying Add-In Abstraction Part 2 - Adding CheckBox Features" shows
the generic "alter architecture and update generators" modification.
Applies as-is to any abstraction modification.
Greg, tried to search for your talk, but could you provide a link.
Logically there isn't anything complex, but I guess what I mean with
"abstracting" does not match with OOP "abstracting". "Abstracting" (as
to raise the abstraction level that is) of "occasionally connected
clients" will show to end-developer as simply an additional boolean
"createOfflineSupportForProxy", where T4 generators then create the
local storage for storing commands, as well as handling the
"business-logic-simulation" on client side.
The client is not trusted though, so when connection is
re-established, simply the stored commands are sent back with some
options for collision detection/handling.
Les erreurs de grammaire et de syntaxe ont été incluses pour m'assurer
de votre attention
This technology has similiarities with DSLs, DDD + generators,
MDA/CASE tools as well. I have underlined some of the key differences
here. Two largest ones are the practical effectiveness, that allows
multiple "mini-DSL"s that do not require compromises and the fact,
that everything is just source code within the project source code
system. No binary constraints to worry in distribution.
I think you are still a bit stranded of what "abstraction" means in
object oriented programming. This is not a framework, this is totally
platform-agnostic technology to genuinely raise the level of
abstraction. Nothing bound to .NET, Java or any specific programming
language. All you end up is a (well) structured source code, with the
generators right there available in the source form as well.
One moves to higher level of abstraction simply for the reason, that
the amount of information required to specify something greatly
reduces, when you speak in precise terms. The key question indeed is,
what you gain and what you lose by doing it.
Let me compare the abstracted vs. traditional by using the
offline-mobile-client example here:
- You have to provide the example code and guidance documentation for
any chosen implementation.
- Any library such as ncqrs is a 3rd party dependency that is more
difficult to alter than your own code (this applies also to
open-source libraries; although you can include it as in source code,
you end up building even stronger dependency that way)
- When you make the end-developer to write the code as required by the
guidance (if he gets it wrong, his program does not work properly),
you actually also create a logical dependency.
- What if he cannot use some part of your example, although logically
he still needs to get the offline functionality there?
- Perhaps he's writing on another platform where there are some binary
restrictions to use some library?
Also you have little control over keeping the end-developer in the
his/her chosen path. If they miss ceremonial code somewhere, their
program does not work properly.
The way to minimize the technical dependencies (such as libraries)
would be to provide source code in a way that it can be plugged in
as-is to existing project.
- There is single bit of information (literally)
- The people currently giving the guidance (anyone, including people
such as Greg Young or Udi Dahan) provide the examples in a form of
actual code generators, that implement good reference code in stead of
just giving static example of "this is how you should do it"
- The template simply outputs as a source code and is right there.
- You can alter the template without worrying how much you break
something else, because the immediate 1:1 from template to code is
- The change is local by all means, but in case it applies to the
logical abstraction elsewhere, you can branch/merge it to the other
places in your project structure as well.
Abstractions enforce the end-developer to stick to the path. The
architect provides the implementation spots through generating code
hooks in the abstraction; the end-developer is simply complying with
the chosen architecture by implementing them. Everybody benefits from
the fact, that the implementation is strongly enforced by the design.
What about "Tomorrow":
- In abstracted world, the offline "true" is not technology or
platform bound. Simply adding the generators for Windows Phone (C#),
Android (Java/Dalvik), iPhone (Objective-C) and MeeGo (C++), the
end-developer experience remains the same and as-optimal-as-possible.
- Abstraction can be updated by distributing the artifacts; XML schema
and all the generators separate). All source control merging
technologies are in place to support the merge between self-modified
parts and updated parts from the provider.
- In traditional world the guidance needs to be written separately to
every supported platform. Updating the guidance so that the
end-developers get the result requires action from the end-developer
to specifically change his code. In all the places where he applied
the guidance, regardless of how well he understood the code that he
I tried looking at what you had up. The ramp up time to understanding your generation techniques and how to get what i wanted out of them seemed to be low roi for my personal time.
You discuss 'ceremonial' code, can you give concrete examples? Also how does the time saved factor into how much time it takes to learn a tool (as well as risks that said tool may be wrong or later not be able to do something that i want todo). In the same line of thinking what is the overhead for bringing on a new dev?
This is not to say that such a tool is impossible to build. I have seen mda style tools used successfully on projects. I have also seen them fail miserably.
I will also agree with you that such tools do not necesarily increase complexity, they do however have additional knowledge requirements/education requirements. This of course would not be such an issue if your tool were widespread in use and i could put it on a job offer and get back many applicants, but now we have a chicken and egg problem.
The most expensive part of building an application with a'cqrs style architecture' is the figuring out and capturing intent and the modelling of aggregates/getting.language right. The other 20-30% is coding. Of that coding process on the high end you have lets say 20% ceremony (its actually much lower imho). Getting rid of this enormous amount of ceremony will speed up my team by 4-6% and any gains can be easily lost by a single use case running into say boundary problems.
As such i would consider such a tool a.mivro optimization. I would not consider bringing it in until the team was very well versed in building aggregates and determining intent.
Unfortunately no tool that i have seen has been built can help with getting boundaries or use cases right. This is where i worry about getting productivity goals from.
Please accept apologies in advance for typos as this was written on my phone.