<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.abdullin.com/~d/styles/itemcontent.css"?><!--Generated by Squarespace Site Server v5.11.81 (http://www.squarespace.com/) on Mon, 06 Feb 2012 11:30:11 GMT--><rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0"><channel><title>Rinat Abdullin on Efficient Software Development</title><link>http://abdullin.com/journal/</link><description>Articles on efficient software development with .NET, including IoC, ORM, Cloud Computing.</description><lastBuildDate>Mon, 06 Feb 2012 11:16:21 +0000</lastBuildDate><copyright /><language>en-US</language><generator>Squarespace Site Server v5.11.81 (http://www.squarespace.com/)</generator><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.abdullin.com/RinatAbdullin" /><feedburner:info uri="rinatabdullin" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><feedburner:emailServiceId>RinatAbdullin</feedburner:emailServiceId><feedburner:feedburnerHostname>http://feedburner.google.com</feedburner:feedburnerHostname><item><title>Make Code Explicit and Stupid</title><dc:creator>Rinat Abdullin</dc:creator><pubDate>Mon, 06 Feb 2012 11:16:18 +0000</pubDate><link>http://feeds.abdullin.com/~r/RinatAbdullin/~3/_BM_xkGPnYk/make-code-explicit-and-stupid.html</link><guid isPermaLink="false">287483:2929700:14896355</guid><description>&lt;p&gt;There is one thing that surprises me in CQRS-related development.&lt;/p&gt;

&lt;p&gt;We, as developers, go at great lengths, explaining how event-centric architectures are so better than CRUD-based ones: you don't need to reverse engineer behaviors from state, since you &lt;strong&gt;express them explicitly&lt;/strong&gt; (as events) and can project to any structural form.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;At Lokad we leverage this heavily for web UIs, that tend to be &lt;a href="http://abdullin.com/journal/2012/2/5/people-dont-think-in-tables.html"&gt;slightly more intuitive&lt;/a&gt; because of that.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;However, when things get to the code, we suddenly change our minds to the opposite and vastly favor implicit conventions and smart heuristics to discover and wire components in an application. &lt;/p&gt;

&lt;p&gt;Maybe this is because, &lt;strong&gt;we are so good with solving complex problems, that we see them in every single problem&lt;/strong&gt;? &lt;/p&gt;

&lt;p&gt;&lt;span class="full-image-block ssNonEditable"&gt;&lt;span&gt;&lt;img src="http://abdullin.com/storage/uploads/2012/02/2012-02-06_smart2.png" alt=""/&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;(this is only a part of the picture, component instantiation is in another class).&lt;/p&gt;

&lt;p&gt;We say, that such approach is smart, generic and reduces friction (when such approach is pushed to extreme, it is called &lt;em&gt;Inversion of Control Container&lt;/em&gt;). That it generally is a better alternative than this:&lt;/p&gt;

&lt;p&gt;&lt;span class="full-image-block ssNonEditable"&gt;&lt;span&gt;&lt;img src="http://abdullin.com/storage/uploads/2012/02/2012-02-06_proj-boring.png" alt=""/&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Seriously, is it?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;An important remark&lt;/strong&gt;: Both pieces of code were written by me. At the moment of writing of each one, I was extremely proud of the approach being used :)&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.abdullin.com/~ff/RinatAbdullin?a=_BM_xkGPnYk:tuiIEEfsCiE:-BTjWOF_DHI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RinatAbdullin?i=_BM_xkGPnYk:tuiIEEfsCiE:-BTjWOF_DHI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.abdullin.com/~ff/RinatAbdullin?a=_BM_xkGPnYk:tuiIEEfsCiE:nQ_hWtDbxek"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RinatAbdullin?d=nQ_hWtDbxek" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.abdullin.com/~ff/RinatAbdullin?a=_BM_xkGPnYk:tuiIEEfsCiE:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RinatAbdullin?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.abdullin.com/~ff/RinatAbdullin?a=_BM_xkGPnYk:tuiIEEfsCiE:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RinatAbdullin?i=_BM_xkGPnYk:tuiIEEfsCiE:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/RinatAbdullin/~4/_BM_xkGPnYk" height="1" width="1"/&gt;</description><wfw:commentRss>http://abdullin.com/journal/rss-comments-entry-14896355.xml</wfw:commentRss><feedburner:origLink>http://abdullin.com/journal/2012/2/6/make-code-explicit-and-stupid.html</feedburner:origLink></item><item><title>People Don't Think in Tables</title><category>Lokad</category><dc:creator>Rinat Abdullin</dc:creator><pubDate>Sun, 05 Feb 2012 12:14:26 +0000</pubDate><link>http://feeds.abdullin.com/~r/RinatAbdullin/~3/a6LcleWTJeo/people-dont-think-in-tables.html</link><guid isPermaLink="false">287483:2929700:14880900</guid><description>&lt;p&gt;Within the last few years I've seen major change in UI approaches in the systems I build. The change is caused by a shift from relational databases as persistence to something that does not require an SQL server (or DB server at all). &lt;/p&gt;

&lt;p&gt;Take a look at this old UI of mine. It's pretty powerful (huge amount of buttons proves that), is intuitive for geeks and scary for normal people. &lt;/p&gt;

&lt;p&gt;&lt;span class="full-image-block ssNonEditable"&gt;&lt;span&gt;&lt;img src="http://abdullin.com/storage/uploads/2012/02/2012-02-05-grid-ui.png" alt=""/&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;What's more curios, this UI is shaped by the relational persistence model that was created in mainframe days, when storage was expensive, memory even more so, and data had to be heavily normalized. However, technology has advanced slightly since then, and we no longer need to fit our UIs to something that is so spreadsheet-like. We can prevent user from overexposure to underlying data complexity, especially when data itself is simple, but just happens to be stored in a computer-optimized way.&lt;/p&gt;

&lt;p&gt;Think of it again. &lt;strong&gt;We turn UI experience of users in sudoku game just because we know how to store data in a way that was good 20 years ago&lt;/strong&gt;. No wonder Apple is making so much money - at least they don't try to turn every UI into spaceship control panel:&lt;/p&gt;

&lt;p&gt;&lt;span class="full-image-block ssNonEditable"&gt;&lt;span&gt;&lt;img src="http://abdullin.com/storage/uploads/2012/02/2012-02-05_183201.png?__SQUARESPACE_CACHEVERSION=1328445201388" alt=""/&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;People don't think with tables&lt;/strong&gt;. They would prefer something that is more simple, even if it does not benefit from a fancy styled UI framework. Something that does not involve solving &lt;a href="http://en.wikipedia.org/wiki/Sudoku"&gt;sudoku puzzle&lt;/a&gt; every time you need to find a simple answer to your question or do your job.&lt;/p&gt;

&lt;p&gt;&lt;span class="full-image-block ssNonEditable"&gt;&lt;span&gt;&lt;img src="http://abdullin.com/storage/uploads/2012/02/2012-02-05-facebook-ui.png" alt=""/&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;or where we have the most simple way to search complex structured info, as patented and proven to be useful by google:&lt;/p&gt;

&lt;p&gt;&lt;span class="full-image-block ssNonEditable"&gt;&lt;span&gt;&lt;img src="http://abdullin.com/storage/uploads/2012/02/2012-02-05-search-ui.png" alt=""/&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;It is surprising, how &lt;strong&gt;underlying technologies affect what we build with them&lt;/strong&gt;, is not it?&lt;/p&gt;

&lt;p&gt;As you can guess, first 2 screenshots depict UI that runs on some sort of SQL, while the other UIs were influenced by a simple NoSQL storage model (to be precise: CQRS/DDD+ES model that uses for UI persistence blobs for cloud persistence and plain files for on-premises deployments). &lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;BTW, I know that quite a lot of people are using Lucene to provide full text search capabilities for their read models. However in the simplest case (esp. with cloud deployments), it's easier to write a few lines of code as opposed to dealing with one more dependency.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Another side effect is that with the change of underlying tech from SQL (and more importantly - thinking model), there is &lt;strong&gt;less need to resort to data-aware UI frameworks&lt;/strong&gt; (mostly used on conjunction with desktop apps) in order to provide rich user experience. This allows to have web-based applications that don't force framework installations  (good luck with getting .NET or Java on all machines in some large organization with a lot of momentum) or complex upgrade routines (i.e. ClickOnce auto-update or automatic MSI updates).&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;I'm not talking about development simplicity and cloud-scalability - these come for free, and we don't really value things unless we struggle for them.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Obviously, as you can see from screenshots above, my UI skills are still below that of a kid with a box of &lt;a href="http://en.wikipedia.org/wiki/Crayon"&gt;crayons&lt;/a&gt; but lately &lt;a href="http://twitter.github.com/bootstrap/"&gt;Bootstrup&lt;/a&gt; and jquery have provided a really nice experience, especially, when you can reuse some great ideas and frameworks.&lt;/p&gt;

&lt;p&gt;&lt;span class="full-image-block ssNonEditable"&gt;&lt;span&gt;&lt;img src="http://abdullin.com/storage/uploads/2012/02/2012-02-05_cqrs-case-studies.png" alt=""/&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Wait, till we start getting into mobile experience with HTML5. It actually comes almost for free as well, since latest web layout frameworks provide a lot of mobile experience out-of-box.&lt;/p&gt;

&lt;p&gt;NB: In no way I'm implying that this second approach is anywhere near close to being reasonably simple. And it's obviously bad looking (especially UIs that I hack together), but I think this is going in the right direction. At least, less time is wasted on writing UI docs and providing support.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.abdullin.com/~ff/RinatAbdullin?a=a6LcleWTJeo:Rrv-vNxuD18:-BTjWOF_DHI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RinatAbdullin?i=a6LcleWTJeo:Rrv-vNxuD18:-BTjWOF_DHI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.abdullin.com/~ff/RinatAbdullin?a=a6LcleWTJeo:Rrv-vNxuD18:nQ_hWtDbxek"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RinatAbdullin?d=nQ_hWtDbxek" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.abdullin.com/~ff/RinatAbdullin?a=a6LcleWTJeo:Rrv-vNxuD18:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RinatAbdullin?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.abdullin.com/~ff/RinatAbdullin?a=a6LcleWTJeo:Rrv-vNxuD18:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RinatAbdullin?i=a6LcleWTJeo:Rrv-vNxuD18:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/RinatAbdullin/~4/a6LcleWTJeo" height="1" width="1"/&gt;</description><wfw:commentRss>http://abdullin.com/journal/rss-comments-entry-14880900.xml</wfw:commentRss><feedburner:origLink>http://abdullin.com/journal/2012/2/5/people-dont-think-in-tables.html</feedburner:origLink></item><item><title>Architectural Principle - Focus on Simplicity</title><dc:creator>Rinat Abdullin</dc:creator><pubDate>Thu, 02 Feb 2012 08:10:50 +0000</pubDate><link>http://feeds.abdullin.com/~r/RinatAbdullin/~3/zqZtWckxLeE/architectural-principle-focus-on-simplicity.html</link><guid isPermaLink="false">287483:2929700:14837836</guid><description>&lt;p&gt;A few hours ago I've posted a tweet that gathered unexpected response:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Popular things that I consciously avoid: IoC Containers, Mocking, ORM, SQL, NuGet, WCF, WWF, WPF, NServiceBus, DTC and TFS.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I did expect any kind of response. And I'd understand that perfectly, since I myself used to &lt;a href="http://abdullin.com/journal/2008/7/6/implementing-orm-independent-linq-queries.html"&gt;adore ORM&lt;/a&gt;, &lt;a href="http://abdullin.com/journal/2009/6/25/testing-mvc-elements-and-interactions-with-mock-container.html"&gt;play with mocking&lt;/a&gt;, &lt;a href="http://abdullin.com/journal/2010/4/24/visualize-ioc-container-and-domain-dependencies-part-2.html"&gt;abuse IoC badly&lt;/a&gt; and do all sorts of &lt;a href="http://abdullin.com/xlim/"&gt;other bad things&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;However the only question people got was: "&lt;em&gt;What's the problem with NuGet&lt;/em&gt;"? Well, answering it requires going a few steps back. &lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Keep in mind, that I'll be pushing my point of view slightly to the extreme, just to make the point more clear.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Every new junior developer (growing team, or a product) starts with the simple approach: we start writing software and adding features till we deliver (sometimes in waterfall approach quite a lot of time could be invested before this happens). Then we grow from there. As software and developers mature, they face new challenges and problems. Luckily we get new tools, skills and ideas to help us growing. New team members and frameworks join in to help everybody move forward and deliver more. Things that hurt or are uncool are thrown away (even though sometimes it might take some effort). &lt;/p&gt;

&lt;p&gt;Sounds like fun.&lt;/p&gt;

&lt;p&gt;However, somewhere in my career path, I've been lucky to get on a rocky path. We never had real ability to just add more tools, people or features. I never worked on a project that had more than 3 people involved in it full-time at once. All these projects were stressed in time (no man-years till the next release) and functionality (rapidly growing companies need to evolve and scale fast).&lt;/p&gt;

&lt;p&gt;Sounds like a minefield and completely unrewarding environment, does not it? &lt;strong&gt;Every wrong decision shows itself really fast&lt;/strong&gt;. Every step that is just good (and &lt;em&gt;not outstanding&lt;/em&gt;) also shows (since you waste precious time that could've been invested more efficiently). So my development career was governed by pain: wrong decisions and poor choices lead to long hours, late nights and unsustainable work efforts. Not, that I don't make frequent mistakes any more, but these ones were really bad. &lt;/p&gt;

&lt;p&gt;And that's actually good: &lt;strong&gt;harder life hits you, faster you learn&lt;/strong&gt;. Bad ideas and tools don't get a lot of chances to stick around in such poor environment. Semi-useful things don't get to stick either. The core principle that still remains and always works is &lt;strong&gt;disciplined simplicity and focus&lt;/strong&gt;. Among other things this means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If I get a chance to remove something or break things down with a small effort, I will take that effort. &lt;/li&gt;
&lt;li&gt;If I get a chance to add something with a small effort, I will fight it. &lt;/li&gt;
&lt;li&gt;I prefer to refactor something first and then maybe add complexity as opposed to adding complexity and then maybe refactoring.&lt;/li&gt;
&lt;li&gt;If I have a chance to defer solving the problem (or even avoid it altogether), I will try that.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;p&gt;Obviously this is the idealistic scenario, that does not factor business values and the rest of the real-world. However, these are just strengthened even more, when you start consciously measuring costs and try to avoid problems.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This often comes to things that other would see as extremes: dropping project references, avoiding to use new technology or framework, removing files, taking preventable risks and even turning down features. Some call this &lt;strong&gt;pain-driven development&lt;/strong&gt; - you keep only things that are too painful to live without, because you can't afford keeping the rest; you focus only on problems that are the most painful for the business (and are measured in real money), because you don't have enough people and hours to deal with the rest.&lt;/p&gt;

&lt;p&gt;This is like constant &lt;strong&gt;tending your garden&lt;/strong&gt; or &lt;strong&gt;curating an exhibition&lt;/strong&gt;: you continuously look look for bad combinations or things that are just good (and not great). You think twice before adding something new (Dependencies also count). Because each thing means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;One more thing for a new developer to learn.&lt;/li&gt;
&lt;li&gt;One more thing that have a chance of going wrong in production.&lt;/li&gt;
&lt;li&gt;One more thing to keep in mind while developing.&lt;/li&gt;
&lt;li&gt;One more logical dependency that has a chance of causing regression.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All this zealotic obsession with simplicity would not be needed if I had environment that is more rich: with more resources, time and people to help us. Would it?&lt;/p&gt;

&lt;p&gt;If we push the idea to the extreme, consider two imaginary products. One could be designed by a rich team with a strong vision, smart architects and man-years dedicated for their goal. The other product could be developed mostly by a semi-organized group individualistic hackers, that scavenge a few hours, accept risks, while working on diverse bits, that are kept stupid and isolated.&lt;/p&gt;

&lt;p&gt;How do you think, will these projects perform in real life? How close is your project to either of these extremes?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An example of rich project environment would be something like: &lt;strong&gt;TFS&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;An example of poor project would be a collection of hacks commonly known as &lt;strong&gt;Git&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'm not trying to compare these projects or judge them. This is up to you :)&lt;/p&gt;

&lt;p&gt;BTW: the answer to the question of "What's wrong with NuGet, NSB etc" is simple: &lt;strong&gt;these projects might be good, but I can live without them in my projects&lt;/strong&gt; (or learned how to live without them). They didn't prove essential (just like almost all utilities and open source libraries I've created and thrown out myself). &lt;/p&gt;

&lt;p&gt;Constraints of such projects are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A few developers (distributed around the world) and rapid releases.&lt;/li&gt;
&lt;li&gt;Necessity to compete with multi-billion transnational companies. &lt;/li&gt;
&lt;li&gt;Necessity to have complex business intelligence (think business analytics) OR extreme scaling (think big data processing with 200x scaling in matter of hours) OR flexible and rich UIs OR cross-cloud low-friction development OR low operating costs OR tolerance to process failures and human errors.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;More often than not, such &lt;strong&gt;projects require ALL of that at once&lt;/strong&gt; (that's how we roll at &lt;a href="http://www.lokad.com/aboutus.ashx"&gt;Lokad&lt;/a&gt;). And guess who gets to babysit these projects and spend weekends fixing things that go wrong?&lt;/p&gt;

&lt;p&gt;Such tight constraints led to the architectural principles and focus on simplicity that I've outlined in this article. &lt;/p&gt;

&lt;p&gt;Tools and frameworks that we still stick to - are getting all the passion, gratitude and even free time. They are worth it, since they helped to work through the problems that we were unable to solve otherwise. However, among all these precious things, &lt;strong&gt;the most valuable&lt;/strong&gt; tool and architectural principle is &lt;strong&gt;keep things simple&lt;/strong&gt;, focus on that.&lt;/p&gt;

&lt;p&gt;PS: You can continue reading on this topic in a fine article by Rob Ashton: &lt;a href="http://codeofrob.com/entries/your-container-is-not-wanted-here.html"&gt;Your container is not wanted here&lt;/a&gt;.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.abdullin.com/~ff/RinatAbdullin?a=zqZtWckxLeE:GEejjbM3BSk:-BTjWOF_DHI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RinatAbdullin?i=zqZtWckxLeE:GEejjbM3BSk:-BTjWOF_DHI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.abdullin.com/~ff/RinatAbdullin?a=zqZtWckxLeE:GEejjbM3BSk:nQ_hWtDbxek"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RinatAbdullin?d=nQ_hWtDbxek" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.abdullin.com/~ff/RinatAbdullin?a=zqZtWckxLeE:GEejjbM3BSk:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RinatAbdullin?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.abdullin.com/~ff/RinatAbdullin?a=zqZtWckxLeE:GEejjbM3BSk:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RinatAbdullin?i=zqZtWckxLeE:GEejjbM3BSk:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/RinatAbdullin/~4/zqZtWckxLeE" height="1" width="1"/&gt;</description><wfw:commentRss>http://abdullin.com/journal/rss-comments-entry-14837836.xml</wfw:commentRss><feedburner:origLink>http://abdullin.com/journal/2012/2/2/architectural-principle-focus-on-simplicity.html</feedburner:origLink></item><item><title>Handling Big Data in Cloud</title><category>Azure</category><category>Cloud Computing</category><dc:creator>Rinat Abdullin</dc:creator><pubDate>Sun, 29 Jan 2012 08:19:29 +0000</pubDate><link>http://feeds.abdullin.com/~r/RinatAbdullin/~3/u-C31kBaxcM/handling-big-data-in-cloud.html</link><guid isPermaLink="false">287483:2929700:14723612</guid><description>&lt;p&gt;Big Data is one of the new hype terms that is gradually gaining popularity. No big surprise - amount of data around us is gradually growing and by properly mining it we can get competitive advantage and eventually make more money. Money attracts money. &lt;/p&gt;

&lt;p&gt;Usually by term &lt;strong&gt;big data&lt;/strong&gt; we mean a &lt;em&gt;collection of datasets that are so large, that they become too hard to be processed on a single machine&lt;/em&gt;. This data can even be so big, that it takes hours or days to process it in a data warehouse.&lt;/p&gt;

&lt;p&gt;Fortunately, cloud computing comes to the rescue. It provides following resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;nearly unlimited scalable storage capacity for data (i.e. Azure Blob storage or Amazon S3)&lt;/li&gt;
&lt;li&gt;elastic compute capacity to process this data (i.e. Azure Worker Roles or Amazon EC)&lt;/li&gt;
&lt;li&gt;network capacities and services to transfer data and coordinate processing (queues and actual networks).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These resources are elastic (you can get as much as you need) and paid-on-demand. Latter is really important, since you pay only for what you use. &lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;I'm assuming here, that in your business model, &lt;strong&gt;more data processed&lt;/strong&gt; means &lt;strong&gt;more money&lt;/strong&gt; made.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;There are three distinct approaches in handling big data, based on the specific challenges. &lt;/p&gt;

&lt;h2&gt;Batch Processing&lt;/h2&gt;

&lt;p&gt;First one is about &lt;strong&gt;batch processing&lt;/strong&gt;, where you &lt;em&gt;do not need extremely fast computation results&lt;/em&gt; but have terabytes and petabytes of data. This is essentially about implementing &lt;a href="http://en.wikipedia.org/wiki/MapReduce"&gt;MapReduce&lt;/a&gt; functionality in your system, often resorting to hacky but extremely practical tricks. Below I'll talk about some of the lessons learned in this direction in Lokad (we &lt;a href="http://www.lokad.com/forecasting-technology.ashx"&gt;provide forecasts&lt;/a&gt;  as a service without any hard limit on amount of data to process).&lt;/p&gt;

&lt;p&gt;Obviously, storage of this data becomes a primary concern with this approach. Fortunately starting companies can leverage already existing cloud computing resources, starting from &lt;a href="http://arstechnica.com/business/news/2012/01/the-big-disk-drive-in-the-sky-how-the-giants-of-the-web-store-big-data.ars/1"&gt;Google's GFS and up to Azure Store&lt;/a&gt;. Or if you are big enough (and this is worth it), you can roll a data center of your own. Idem for computing and network capacities.&lt;/p&gt;

&lt;h2&gt;Stream Processing&lt;/h2&gt;

&lt;p&gt;Second approach deals with cases, where you need &lt;strong&gt;high-throughput&lt;/strong&gt; and &lt;strong&gt;consistently low latency&lt;/strong&gt; on gigabytes of data. High-frequency trading is one of the most known domains here (various real-world telemetry systems being the second one). Abusing event streams and ring buffers (like in &lt;a href="http://martinfowler.com/articles/lmax.html"&gt;LMAX&lt;/a&gt;) along with partitioning - helps to deal with the challenge.&lt;/p&gt;

&lt;p&gt;Due to latency requirements, cloud computing might be not the best choice for latency-sensitive solutions. It is more efficient to roll out fine-tuned infrastructure of your own including specialized hardware and soft (things like &lt;a href="http://en.wikipedia.org/wiki/InfiniBand"&gt;InfiniBand&lt;/a&gt; and &lt;a href="http://en.wikipedia.org/wiki/Application-specific_integrated_circuit"&gt;ASIC&lt;/a&gt; or even Mixed-signal chips).&lt;/p&gt;

&lt;p&gt;However if you are OK with a bit of latency and are more interested in high-throughput continuous computation, then the flexible network and CPU resources provided by cloud are a good match.&lt;/p&gt;

&lt;h2&gt;Realtime Batch Processing&lt;/h2&gt;

&lt;p&gt;Third approach to Big Data involves dealing with more complex requirement - providing &lt;strong&gt;real-time capabilities over vast amounts of data&lt;/strong&gt; (so we have to be both fast and capable of handling petabytes of data). Twitter is a vivid example here - it needs to provide (almost) real-time analysis over billions of tweets around the world (although fortunately it does not to go at microsecond level).&lt;/p&gt;

&lt;p&gt;This challenge can be solved by actually mixing first two approaches: we would use slower batch-processing for dealing with actual bulk of data (tricks like preprocessing, append-only storage and MapReduce work here), while latest data will be handled through the real-time streams (stream processing and continuous computation). Results are merged as they come out of these two data pipes. Over the course of time (i.e. daily) latest data is pushed from "hot" zone into the bulk data.&lt;/p&gt;

&lt;p&gt;More often than not, real-time data processing is done by simplified approximating algorithms that deal with subset of data. Batch processing is more through and precise (at the cost of being slower). By pushing real-time data back to the bulk data, results of the computations are actually corrected, as they are recomputed by batch algorithms. &lt;a href="http://engineering.twitter.com/2011/08/storm-is-coming-more-details-and-plans.html"&gt;Twitter's Storm&lt;/a&gt; project features nice overview of this approach.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.abdullin.com/~ff/RinatAbdullin?a=u-C31kBaxcM:nl6ajz5l-rM:-BTjWOF_DHI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RinatAbdullin?i=u-C31kBaxcM:nl6ajz5l-rM:-BTjWOF_DHI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.abdullin.com/~ff/RinatAbdullin?a=u-C31kBaxcM:nl6ajz5l-rM:nQ_hWtDbxek"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RinatAbdullin?d=nQ_hWtDbxek" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.abdullin.com/~ff/RinatAbdullin?a=u-C31kBaxcM:nl6ajz5l-rM:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RinatAbdullin?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.abdullin.com/~ff/RinatAbdullin?a=u-C31kBaxcM:nl6ajz5l-rM:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RinatAbdullin?i=u-C31kBaxcM:nl6ajz5l-rM:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/RinatAbdullin/~4/u-C31kBaxcM" height="1" width="1"/&gt;</description><wfw:commentRss>http://abdullin.com/journal/rss-comments-entry-14723612.xml</wfw:commentRss><feedburner:origLink>http://abdullin.com/journal/2012/1/29/handling-big-data-in-cloud.html</feedburner:origLink></item><item><title>New Videos on CQRS/DDD and Practical CQRS</title><category>Azure</category><category>CQRS</category><category>Cloud Computing</category><category>DDD</category><category>Event Sourcing</category><category>Lokad</category><dc:creator>Rinat Abdullin</dc:creator><pubDate>Fri, 20 Jan 2012 13:04:53 +0000</pubDate><link>http://feeds.abdullin.com/~r/RinatAbdullin/~3/erBE6YufLK8/new-videos-on-cqrsddd-and-practical-cqrs.html</link><guid isPermaLink="false">287483:2929700:14660284</guid><description>&lt;p&gt;Thanks to awesome guys from &lt;a href="http://www.dotnet-austria.at/"&gt;Austrian Alt.NET&lt;/a&gt; (and particularly  &lt;a href="https://twitter.com/#!/JoergEg"&gt;Jörg Egretzberger&lt;/a&gt;) there has been an opportunity for me to speak with Greg Young at Professional.NET in Vienna on September 2011. And here are the videos that were made there.&lt;/p&gt;

&lt;p&gt;It's recommended to watch them in the provided order: first Greg's "CQRS and DDD" and then my "Practical CQRS"&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Please, keep in mind, that this event took place more than 4 months from now; it also was the first talk I've done together with Greg (meaning that I became slightly less stupid and naive since then, especially during the &lt;a href="http://abdullin.com/roadtrip-2011"&gt;CQRS RoadTrip 2011&lt;/a&gt;; at least that's what I hope). &lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;CQRS and Domain Driven Design&lt;/h2&gt;

&lt;p&gt;by Greg Young. Direct link: &lt;a href="http://youtu.be/KXqrBySgX-s"&gt;http://youtu.be/KXqrBySgX-s&lt;/a&gt;&lt;/p&gt;

&lt;iframe width="560" height="315" src="http://www.youtube.com/embed/KXqrBySgX-s" frameborder="0" allowfullscreen&gt;&lt;/iframe&gt;

&lt;h2&gt;Practical CQRS in Cloud&lt;/h2&gt;

&lt;p&gt;by Rinat Abdullin. Direct Link: &lt;a href="http://youtu.be/CnvO_nlvrps"&gt;http://youtu.be/CnvO_nlvrps&lt;/a&gt; | &lt;a href="http://abdullin.com/storage/publish/2011-09-15_Vienna.pdf"&gt;PDF&lt;/a&gt;&lt;/p&gt;

&lt;iframe width="560" height="315" src="http://www.youtube.com/embed/CnvO_nlvrps" frameborder="0" allowfullscreen&gt;&lt;/iframe&gt;

&lt;p&gt;I hope you enjoy them. Once again, kudos to terrific guys from &lt;a href="http://www.dotnet-austria.at/"&gt;Austrian Alt.NET&lt;/a&gt; community for making these recordings possible.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.abdullin.com/~ff/RinatAbdullin?a=erBE6YufLK8:kflJRjJAyVI:-BTjWOF_DHI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RinatAbdullin?i=erBE6YufLK8:kflJRjJAyVI:-BTjWOF_DHI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.abdullin.com/~ff/RinatAbdullin?a=erBE6YufLK8:kflJRjJAyVI:nQ_hWtDbxek"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RinatAbdullin?d=nQ_hWtDbxek" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.abdullin.com/~ff/RinatAbdullin?a=erBE6YufLK8:kflJRjJAyVI:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RinatAbdullin?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.abdullin.com/~ff/RinatAbdullin?a=erBE6YufLK8:kflJRjJAyVI:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RinatAbdullin?i=erBE6YufLK8:kflJRjJAyVI:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/RinatAbdullin/~4/erBE6YufLK8" height="1" width="1"/&gt;</description><wfw:commentRss>http://abdullin.com/journal/rss-comments-entry-14660284.xml</wfw:commentRss><feedburner:origLink>http://abdullin.com/journal/2012/1/20/new-videos-on-cqrsddd-and-practical-cqrs.html</feedburner:origLink></item><item><title>Run Lokad.CQRS code natively on Windows Azure</title><category>Azure</category><category>C#</category><category>CQRS</category><category>Cloud Computing</category><category>Event Sourcing</category><category>Lokad</category><category>xLim</category><dc:creator>Rinat Abdullin</dc:creator><pubDate>Sat, 14 Jan 2012 14:09:08 +0000</pubDate><link>http://feeds.abdullin.com/~r/RinatAbdullin/~3/H4MM_GC8_TA/run-lokadcqrs-code-natively-on-windows-azure.html</link><guid isPermaLink="false">287483:2929700:14579136</guid><description>&lt;p&gt;As it seems, the most common use of &lt;a href="https://github.com/lokad/lokad-cqrs/"&gt;Lokad.CQRS Sample&lt;/a&gt; these days is for building CQRS-based applications for Intranet (and migrating legacy projects). I didn't see that coming, but glad that the latest "lean" version makes some sense to people (&lt;a href="http://abdullin.com/journal/2012/1/5/announcing-lokadcqrs-vlean-sampleproject-and-tools.html"&gt;more about it&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;However, one of the initial purposes of this Sample is to &lt;strong&gt;enable and demonstrate cross-cloud portability&lt;/strong&gt; of projects developed using abstractions from &lt;code&gt;Lokad.Cqrs.Portable&lt;/code&gt;. That's how we use it at &lt;a href="http://www.lokad.com/forecasting-technology.ashx"&gt;Lokad&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;So to highlight this (and to help folks from &lt;em&gt;Microsoft CQRS Advisory Board&lt;/em&gt; that showed interest in trying Lokad.CQRS with Azure), I've added two new projects: &lt;code&gt;Sample.Azure.Wires&lt;/code&gt; and &lt;code&gt;Sample.Azure.Deploy&lt;/code&gt;. There is nothing really special, first project just wires SampleProject to run on Windows Azure in a Worker Role, without touching existing domain code. Second project is the actual deployment. &lt;/p&gt;

&lt;p&gt;As expected, trace output is similar to the one we get from running sample in on-premises mode (via  &lt;code&gt;Sample.Engine&lt;/code&gt; console).&lt;/p&gt;

&lt;p&gt;&lt;span class="full-image-block ssNonEditable"&gt;&lt;span&gt;&lt;img src="http://abdullin.com/storage/uploads/2012/01/2012-01-14_cqrs-in-azure.png" alt=""/&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Obviously, this worker is wired to use native components of Windows Azure, instead of file system. These components (developed in Lokad and production-tested over the last few years in various scenarios) include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;BlockBlobTapeStorage (used for append-only event streams on Azure)&lt;/li&gt;
&lt;li&gt;AzureAtomicStorage (used for storing documents, saga state and persistent read models)&lt;/li&gt;
&lt;li&gt;BlobStreamingStorage (used for streaming large BLOBs for Big DataProcessing)&lt;/li&gt;
&lt;li&gt;Azure Queues (for your message sending needs)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you have latest Azure SDK installed, just open &lt;code&gt;Lokad.CQRS.Sample.withAzure.sln&lt;/code&gt; to see these additional Azure projects and get a taste of &lt;a href="http://bliki.abdullin.com/event-sourcing/why"&gt;event sourcing&lt;/a&gt; on the cloud (actually tastes exactly like any other ES, but feels cooler).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Maintenance Tip:&lt;/strong&gt; By the way, you can download domain log file (&lt;code&gt;sample-tapes/domain.tmd&lt;/code&gt;) from the Azure Storage to your disk and open it with Audit tool. This &lt;strong&gt;helps to visualize and investigate processes that happen in your CQRS system on the cloud&lt;/strong&gt; (actually saved my day more than once, when production systems hit unexpected problems). Likewise you can also download and investigate event streams of any single aggregate. &lt;/p&gt;

&lt;p&gt;Actually, this Audit tool was also designed to open event streams directly from Azure (and allow sending selected messages back or rebuilding all projections), however this functionality is not ported to open source yet. If somebody finds it useful, I'll try to find time and export it (there is nothing really fancy there, though - just using append-only nature of event streams for efficient data replication from remote cloud to local machine).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Maintenance Tip:&lt;/strong&gt; Those, that plan to use this in a production, might want to plug the quarantine into the message handlers. For instance, &lt;a href="https://gist.github.com/1027419"&gt;here is a sample&lt;/a&gt; that records every handler failure and send a detailed report (with stack traces and message information) to email as soon as message is quarantined. The latter helps to deal with cloud problems really fast.&lt;/p&gt;

&lt;p&gt;The next thing I want to include in this Sample Project is a lean Web UI, using ASP.NET MVC 3 Razor Views with &lt;a href="http://jquery.com/"&gt;jQuery&lt;/a&gt; and &lt;a href="http://twitter.github.com/bootstrap/"&gt;Bootstrap.css&lt;/a&gt;. Just to demonstrate how easy it is to add browser-friendly and fast Web UI to existing CQRS systems (and have it hosted on-premises or in the cloud, of course). What do you think?&lt;/p&gt;

&lt;p&gt;Meanwhile, have fun, join the &lt;a href="https://groups.google.com/forum/#!forum/lokad"&gt;community&lt;/a&gt; of people &lt;a href="https://groups.google.com/forum/#!topic/lokad/kD53JYzkV0o"&gt;abusing the project&lt;/a&gt; and be sure to fill in &lt;a href="http://t.co/3zBMC52n"&gt;CQRS Survey put out by P&amp;amp;P Team&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.abdullin.com/~ff/RinatAbdullin?a=H4MM_GC8_TA:Z8Iq4nY3Jik:-BTjWOF_DHI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RinatAbdullin?i=H4MM_GC8_TA:Z8Iq4nY3Jik:-BTjWOF_DHI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.abdullin.com/~ff/RinatAbdullin?a=H4MM_GC8_TA:Z8Iq4nY3Jik:nQ_hWtDbxek"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RinatAbdullin?d=nQ_hWtDbxek" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.abdullin.com/~ff/RinatAbdullin?a=H4MM_GC8_TA:Z8Iq4nY3Jik:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RinatAbdullin?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.abdullin.com/~ff/RinatAbdullin?a=H4MM_GC8_TA:Z8Iq4nY3Jik:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RinatAbdullin?i=H4MM_GC8_TA:Z8Iq4nY3Jik:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/RinatAbdullin/~4/H4MM_GC8_TA" height="1" width="1"/&gt;</description><wfw:commentRss>http://abdullin.com/journal/rss-comments-entry-14579136.xml</wfw:commentRss><feedburner:origLink>http://abdullin.com/journal/2012/1/14/run-lokadcqrs-code-natively-on-windows-azure.html</feedburner:origLink></item><item><title>Announcing Lokad.CQRS vLean - SampleProject and Tools</title><category>Azure</category><category>C#</category><category>CQRS</category><category>Cloud Computing</category><category>DDD</category><category>Event Sourcing</category><category>Lokad</category><category>xLim</category><dc:creator>Rinat Abdullin</dc:creator><pubDate>Thu, 05 Jan 2012 17:49:25 +0000</pubDate><link>http://feeds.abdullin.com/~r/RinatAbdullin/~3/D85sGsdQ_ks/announcing-lokadcqrs-vlean-sampleproject-and-tools.html</link><guid isPermaLink="false">287483:2929700:14450141</guid><description>&lt;p&gt;I've just finished assembling pre-release of Lokad.CQRS vLean (&lt;a href="https://github.com/Lokad/lokad-cqrs/tree/lean"&gt;lean branch in github repository&lt;/a&gt;). From of this version &lt;strong&gt;Lokad.CQRS is no longer a framework&lt;/strong&gt;, it is a &lt;strong&gt;full sample&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;As such, Lokad.CQRS could be used for &lt;strong&gt;learning about event centric development&lt;/strong&gt; (&lt;a href="http://abdullin.com/cqrs/"&gt;CQRS/DDD&lt;/a&gt; with event sourcing and ability to deploy in cloud and on-premises). Gradually growing series of articles in &lt;a href="http://bliki.abdullin.com/"&gt;my bliki&lt;/a&gt; could provide some theoretical background.&lt;/p&gt;

&lt;p&gt;You can also use Lokad.CQRS to jumpstart new projects by copying the entire &lt;code&gt;SampleProject&lt;/code&gt; to your system and then modifying it to your needs. That's essentially how we start new projects at &lt;a href="http://www.lokad.com/"&gt;Lokad&lt;/a&gt; these days.&lt;/p&gt;

&lt;p&gt;Because of this transition from "Framework" to "Sample with Sources" (aka "Reference Implementation"), I was finally able to include a lot of new material into this branch.&lt;/p&gt;

&lt;h2&gt;Sample Project&lt;/h2&gt;

&lt;p&gt;I've ripped part of domain code (simple account+users setup) from one of our projects, along with all the accompanying tooling, tests and engine. Current approach to event sourcing is also included (as explained in the &lt;a href="http://bliki.abdullin.com/"&gt;bliki&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;The project currently &lt;strong&gt;does not include&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Deployment runners for Azure.Cloud&lt;/strong&gt; (planned later, however Lokad.CQRS users should have pretty good sense of reconfiguring the domain to run in Azure).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Web UI&lt;/strong&gt; (but I might add it later, if time permits, since Razor + Bootstrap make really pleasant and fast development with this architecture).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'll try to add these later (community contributions are also awesome).&lt;/p&gt;

&lt;p&gt;Absence of Web UI makes it harder to visualize what's going inside. However you can still run tests and also start &lt;code&gt;Sample.Engine&lt;/code&gt; (configured with file-based persistence and queues), that will fire a few commands, which will produce events that will be wired to sagas and projections. Just like in the real world.&lt;/p&gt;

&lt;p&gt;Plus, this project includes some sample code and tools that are wired to it. These are used exactly how we currently use them (although not necessary how we will use them a few months later). Read below for more info.&lt;/p&gt;

&lt;h2&gt;Contracts DSL&lt;/h2&gt;

&lt;p&gt;Lokad Contracts DSL is an optional console utility that you can run in the background. It tracks changes to files with special compact syntax (as mentioned in &lt;a href="http://bliki.abdullin.com/event-centric/commands-events"&gt;commands and events&lt;/a&gt; on bliki) and updates CS file. Changes are immediate upon saving file (and ReSharper immediately picks them). This is an improved version of &lt;a href="https://github.com/Lokad/lokad-codedsl"&gt;Lokad Code DSL&lt;/a&gt;, it supports identities and can auto-generate interfaces for aggregates and aggregate state classes.&lt;/p&gt;

&lt;p&gt;You can try this out by starting &lt;code&gt;SampleProject\Tools\Dsl&lt;/code&gt; project and then doing some changes to &lt;code&gt;SampleProject\Domain\Sample.Contracts\Messages.tt&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Current DSL code generates contracts classes that are compatible with &lt;code&gt;DataContracts&lt;/code&gt;, &lt;code&gt;ServiceStack.JSON&lt;/code&gt; and &lt;code&gt;ProtoBuf&lt;/code&gt;. Here are how they look like:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[DataContract(Namespace = "Sample")]
public partial class AddSecurityPassword : ICommand&amp;lt;SecurityId&amp;gt;
{
    [DataMember(Order = 1)] public SecurityId Id { get; private set; }
    [DataMember(Order = 2)] public string DisplayName { get; private set; }
    [DataMember(Order = 3)] public string Login { get; private set; }
    [DataMember(Order = 4)] public string Password { get; private set; }

    AddSecurityPassword () {}
    public AddSecurityPassword (SecurityId id, string displayName, string login, string password)
    {
        Id = id;
        DisplayName = displayName;
        Login = login;
        Password = password;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;Audit Tool&lt;/h2&gt;

&lt;p&gt;After you have run &lt;code&gt;Sample.Engine&lt;/code&gt;, try starting &lt;code&gt;Audit&lt;/code&gt; and opening  with it this file &lt;code&gt;temp\sample-tapes\domain.tmd&lt;/code&gt; (located in folder where the engine run). You should see something like this:&lt;/p&gt;

&lt;p&gt;&lt;span class="full-image-block ssNonEditable"&gt;&lt;span&gt;&lt;img src="http://abdullin.com/storage/uploads/2012/01/2012-01-05_lokad-audit.png?__SQUARESPACE_CACHEVERSION=1325783136000" alt=""/&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;You'll probably figure out the purpose of color coding (or you could look out in the sources). &lt;/p&gt;

&lt;p&gt;BTW, here's how the other tab looks like - it is used for automatically detecting and wiring all &lt;a href="http://bliki.abdullin.com/event-sourcing/projections"&gt;projections&lt;/a&gt; and then running the selected event stream through them:&lt;/p&gt;

&lt;p&gt;&lt;span class="full-image-block ssNonEditable"&gt;&lt;span&gt;&lt;img src="http://abdullin.com/storage/uploads/2012/01/2012-01-05_rebuild-views.png?__SQUARESPACE_CACHEVERSION=1325783286674" alt=""/&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Please keep in mind, that this is a fast rip from internal code, so a few buttons and functionality might not make full sense in the file-based context (i.e. domain log synchronization).&lt;/p&gt;

&lt;h2&gt;Simple Testing&lt;/h2&gt;

&lt;p&gt;I've been mentioning heavy abuse of Greg's SimpleTesting for dealing with &lt;a href="http://bliki.abdullin.com/event-sourcing/specifications"&gt;specifications&lt;/a&gt; to test &lt;a href="http://bliki.abdullin.com/event-sourcing/aggregates"&gt;Aggregates&lt;/a&gt;. Source code for that is included (and for printing out them in readable format). Just fire your NUnit (either directly or via ReSharper):&lt;/p&gt;

&lt;p&gt;&lt;span class="full-image-block ssNonEditable"&gt;&lt;span&gt;&lt;img src="http://abdullin.com/storage/uploads/2012/01/2012-01-05_simple-testing.png?__SQUARESPACE_CACHEVERSION=1325783505835" alt=""/&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;This setup currently supports usual AR+ES testing, plus testing exceptions thrown by the domain code (domain errors), plus dealing with services and time.&lt;/p&gt;

&lt;h2&gt;Core Changes&lt;/h2&gt;

&lt;p&gt;There were a few core changes in the actual Lokad.CQRS framework. They were caused by the need to move forward and support wider range of scenarios (and better scalability). Actually, these features were mostly related to throwing things out - all builder syntax and containers. In the current version you wire everything without using overcomplicated builders. This leads to fewer dependencies and simpler code.&lt;/p&gt;

&lt;p&gt;If you don't know, how old builder code translates to the new one - just check &lt;code&gt;Wires&lt;/code&gt; and &lt;code&gt;Engine&lt;/code&gt; projects in &lt;code&gt;SampleProject&lt;/code&gt; (in addition to &lt;code&gt;Snippets&lt;/code&gt; and unit tests for core building blocks).&lt;/p&gt;

&lt;p&gt;In the spirit, we are gradually drifting away from style of architectures that is similar to NServiceBus, MassTransit and RhinoQueues (where you have handler classes plugged into the container for you). Instead, we are going directly for the type of architectures described by the outstanding &lt;a href="http://zguide.zeromq.org/page:all"&gt;ZMQ guide&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;What's Next&lt;/h2&gt;

&lt;p&gt;As always, your feedback is always welcome (it helped to shape the current release and let us move forward). Please share it (along with any questions you might have) in &lt;a href="https://groups.google.com/forum/#!forum/lokad"&gt;Lokad community&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A lot more is planned in this world along the following directions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Simplifying the core even further, along with solidifying the backing theory, based on real-world experience.&lt;/li&gt;
&lt;li&gt;Better support of multiple clouds (just Azure is not enough)&lt;/li&gt;
&lt;li&gt;Realt-time performance scenarios.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Stay tuned and participate in the community, if you are interested!&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.abdullin.com/~ff/RinatAbdullin?a=D85sGsdQ_ks:ZCEIOviQFNc:-BTjWOF_DHI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RinatAbdullin?i=D85sGsdQ_ks:ZCEIOviQFNc:-BTjWOF_DHI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.abdullin.com/~ff/RinatAbdullin?a=D85sGsdQ_ks:ZCEIOviQFNc:nQ_hWtDbxek"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RinatAbdullin?d=nQ_hWtDbxek" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.abdullin.com/~ff/RinatAbdullin?a=D85sGsdQ_ks:ZCEIOviQFNc:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RinatAbdullin?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.abdullin.com/~ff/RinatAbdullin?a=D85sGsdQ_ks:ZCEIOviQFNc:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RinatAbdullin?i=D85sGsdQ_ks:ZCEIOviQFNc:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/RinatAbdullin/~4/D85sGsdQ_ks" height="1" width="1"/&gt;</description><wfw:commentRss>http://abdullin.com/journal/rss-comments-entry-14450141.xml</wfw:commentRss><feedburner:origLink>http://abdullin.com/journal/2012/1/5/announcing-lokadcqrs-vlean-sampleproject-and-tools.html</feedburner:origLink></item><item><title>Using Git Revision in Windows Azure Cloud Deployments</title><category>Azure</category><category>Cloud Computing</category><category>Integration</category><category>git</category><dc:creator>Rinat Abdullin</dc:creator><pubDate>Fri, 30 Dec 2011 11:19:14 +0000</pubDate><link>http://feeds.abdullin.com/~r/RinatAbdullin/~3/p9gVJM6Ur00/using-git-revision-in-windows-azure-cloud-deployments.html</link><guid isPermaLink="false">287483:2929700:14379482</guid><description>&lt;p&gt;Here's a quick approach for including git versions of your codebase into Windows Azure Deployment labels (as visible in the Portal). This applies to Azure SDK 1.6 and probably higher. Versions are appended automatically whenever you trigger a publish from Visual Studio.&lt;/p&gt;

&lt;p&gt;git versions usually are reported by &lt;code&gt;git describe&lt;/code&gt; and could look like &lt;code&gt;r40&lt;/code&gt; (if there is &lt;code&gt;r40&lt;/code&gt; tag on the last commit) or &lt;code&gt;r39-31-g48ac07c&lt;/code&gt; (if last tag &lt;code&gt;r39&lt;/code&gt; was 31 commits ago).&lt;/p&gt;

&lt;p&gt;It works like this.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1&lt;/strong&gt;: Create new Azure Deployment profile for your deployment project. It will be saved somewhere to &lt;code&gt;Profiles\ProjectName.azurePubxml&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2&lt;/strong&gt;: Save project and then edit deployment project file to include this profile file only if it exists&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;ItemGroup&amp;gt;
  &amp;lt;PublishProfile Include="Profiles\ProjectName.azurePubxml"  
     Condition=" Exists('Profiles\ProjectName.azurePubxml') " /&amp;gt;
&amp;lt;/ItemGroup&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Step 3&lt;/strong&gt;: Drop a &lt;code&gt;.gitignore&lt;/code&gt; file into the &lt;code&gt;Profiles&lt;/code&gt; folder so that changes will not be tracked. Contents will be straightforward:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;ProjectName.azurePubxml
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Step 4&lt;/strong&gt;: Add &lt;code&gt;PreBuildEvent&lt;/code&gt; to the Azure deployment project by editing it further. This script should:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fill &lt;code&gt;&amp;lt;AzureDeploymentLabel&amp;gt;&lt;/code&gt; XML node in &lt;code&gt;azurePubxml&lt;/code&gt; with a content of your choice (optionally grabbing output of &lt;code&gt;git describe&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Fail gracefully if there is no git available.&lt;/li&gt;
&lt;li&gt;Fail gracefully if there is no &lt;code&gt;azurePubxml&lt;/code&gt; file.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In other words, we just take output of &lt;code&gt;git describe&lt;/code&gt; command and put it inside the match of:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;new Regex("&amp;lt;AzureDeploymentLabel&amp;gt;.*&amp;lt;/AzureDeploymentLabel&amp;gt;", RegexOptions.Multiline);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;MSBuild &lt;code&gt;PreBuildEvent&lt;/code&gt; script can be wired to our process via editing of &lt;code&gt;.ccproj&lt;/code&gt; file (or you can just fill that via Visual Studio UI - Deployment | Properties | Build Events): &lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;PropertyGroup&amp;gt;
  &amp;lt;PreBuildEvent&amp;gt;"PathToReplacementScript" "$(ProjectDir)\Profiles\ProjectName.azurePubxml"&amp;lt;/PreBuildEvent&amp;gt;
&amp;lt;/PropertyGroup&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;For the actual replacement script you can use scripting environment of your choice or even C#.&lt;/p&gt;

&lt;p&gt;By the way, there are two interesting twists upon this concept.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Twist 1&lt;/strong&gt;: You can leverage git's super powers to print all changes in the code between any two deployment labels. They will be nicely formatted by committer, too.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;git log r39..r40 --pretty=short | git shortlog
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That's how we publish releases at Lokad. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Twist 2&lt;/strong&gt;: You can set your system to publish &lt;code&gt;InstanceStartedEvent&lt;/code&gt; with the following schema:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;InstanceStarted!(string codeVersion, string role, string instance)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The latter can be used to link your code version trees directly with the event streams and life-cycle of a distributed system deployed to the cloud. This immensely simplifies post-mortem debugging  of such systems along with adding a few maintenance tricks to your sleeve.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.abdullin.com/~ff/RinatAbdullin?a=p9gVJM6Ur00:bNNO3QyeL3c:-BTjWOF_DHI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RinatAbdullin?i=p9gVJM6Ur00:bNNO3QyeL3c:-BTjWOF_DHI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.abdullin.com/~ff/RinatAbdullin?a=p9gVJM6Ur00:bNNO3QyeL3c:nQ_hWtDbxek"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RinatAbdullin?d=nQ_hWtDbxek" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.abdullin.com/~ff/RinatAbdullin?a=p9gVJM6Ur00:bNNO3QyeL3c:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RinatAbdullin?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.abdullin.com/~ff/RinatAbdullin?a=p9gVJM6Ur00:bNNO3QyeL3c:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RinatAbdullin?i=p9gVJM6Ur00:bNNO3QyeL3c:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/RinatAbdullin/~4/p9gVJM6Ur00" height="1" width="1"/&gt;</description><wfw:commentRss>http://abdullin.com/journal/rss-comments-entry-14379482.xml</wfw:commentRss><feedburner:origLink>http://abdullin.com/journal/2011/12/30/using-git-revision-in-windows-azure-cloud-deployments.html</feedburner:origLink></item><item><title>Example of Self-documenting Unit Test with Event Sourcing</title><category>DDD</category><category>Event Sourcing</category><category>tdd</category><dc:creator>Rinat Abdullin</dc:creator><pubDate>Tue, 27 Dec 2011 15:13:37 +0000</pubDate><link>http://feeds.abdullin.com/~r/RinatAbdullin/~3/TyBQqrav2YY/example-of-self-documenting-unit-test-with-event-sourcing.html</link><guid isPermaLink="false">287483:2929700:14340835</guid><description>&lt;p&gt;One of the biggest advantages of &lt;a href="http://bliki.abdullin.com/event-sourcing/"&gt;event sourcing&lt;/a&gt; approach is it's inherent &lt;strong&gt;capability to turn unit tests into a living documentation&lt;/strong&gt;. Below is an example of specification that I've worked my way through today (that's how NUnit prints it out).&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;registrations: duplicate email fails - Passed

Environment: 
  index includes email("contact@lokad.com")

When: Register 'd6e64e':
        Customer Name: Lokad
        Contact Email: contact@lokad.com
        Date:          2011-12-27

Expectations:
  [Passed] Registration 'd6e64e':
             Customer Name: Lokad
             Contact Email: contact@lokad.com
             Date:          2011-12-27
  [Passed] Registration 'd6e64e' failed:
             Email 'contact@lokad.com' is already taken.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And here's how actual NUnit code looks like:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;public Specification duplicate_email_fails()
{
    var info = new RegistrationInfoBuilder("contact@lokad.com", "Lokad").Build();
    var index = new MockUniquenessService();

    return new RegistrationSpec(index)
        {
            Before = {() =&amp;gt; index.includes_email("contact@lokad.com")},
            When = new CreateRegistration(reg, info),
            Expect =
                {
                    new RegistrationCreated(reg, info),
                    new RegistrationFailed(reg, new[]
                        {
                            "Email 'contact@lokad.com' is already taken."
                        })
                },
            Finally = index.Clear
        };
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;All was achieved without any special magic or even fancy tools. I've just pulled over sources of &lt;a href="https://github.com/gregoryyoung/Simple.Testing"&gt;SimpleTesting&lt;/a&gt; and &lt;a href="http://comparenetobjects.codeplex.com/"&gt;CompareObjects&lt;/a&gt; for additional readability.&lt;/p&gt;

&lt;p&gt;For those who are interested in &lt;code&gt;RegistrationSpec&lt;/code&gt; class, it is just a simple snippet wiring together dependencies of aggregate root to a strongly-typed specification deriving from &lt;code&gt;TypedSpecification&lt;/code&gt; in &lt;code&gt;SimpleTesting&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;public sealed class RegistrationSpec : AggregateSpecification&amp;lt;RegistrationId&amp;gt;
{
    public RegistrationSpec(IRegistrationUniquenessService service)
    {
        Factory = (events, observer) =&amp;gt;
            {
                var state = new RegistrationAggregateState(events);
                return new RegistrationAggregate(state, observer, service, 
                    new TestPassword(), 
                    new TestIdentity());
            };
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Explicit strong-typing of aggregates (as described in &lt;a href="http://bliki.abdullin.com/event-centric/aggregates-2"&gt;bliki&lt;/a&gt;) works all the way back in unit test specification by allowing to benefit from  compiler-time checking and IntelliSense support. In other words: you &lt;strong&gt;don't need to navigate through hundreds of messages&lt;/strong&gt; to figure out which ones are actually applicable in test.&lt;/p&gt;

&lt;p&gt;&lt;span class="full-image-block ssNonEditable"&gt;&lt;span&gt;&lt;img src="http://abdullin.com/storage/uploads/2011/12/2011-12-27_event_sourcing_test.png?__SQUARESPACE_CACHEVERSION=1324998719605" alt=""/&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.abdullin.com/~ff/RinatAbdullin?a=TyBQqrav2YY:jyNgabi67JQ:-BTjWOF_DHI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RinatAbdullin?i=TyBQqrav2YY:jyNgabi67JQ:-BTjWOF_DHI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.abdullin.com/~ff/RinatAbdullin?a=TyBQqrav2YY:jyNgabi67JQ:nQ_hWtDbxek"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RinatAbdullin?d=nQ_hWtDbxek" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.abdullin.com/~ff/RinatAbdullin?a=TyBQqrav2YY:jyNgabi67JQ:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RinatAbdullin?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.abdullin.com/~ff/RinatAbdullin?a=TyBQqrav2YY:jyNgabi67JQ:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RinatAbdullin?i=TyBQqrav2YY:jyNgabi67JQ:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/RinatAbdullin/~4/TyBQqrav2YY" height="1" width="1"/&gt;</description><wfw:commentRss>http://abdullin.com/journal/rss-comments-entry-14340835.xml</wfw:commentRss><feedburner:origLink>http://abdullin.com/journal/2011/12/27/example-of-self-documenting-unit-test-with-event-sourcing.html</feedburner:origLink></item><item><title>Migrating Legacy Systems to Event Sourcing</title><category>CQRS</category><category>Cloud Computing</category><category>DDD</category><category>Event Sourcing</category><category>xLim</category><dc:creator>Rinat Abdullin</dc:creator><pubDate>Sat, 24 Dec 2011 10:59:23 +0000</pubDate><link>http://feeds.abdullin.com/~r/RinatAbdullin/~3/-KogK3_tGLI/migrating-legacy-systems-to-event-sourcing.html</link><guid isPermaLink="false">287483:2929700:14312515</guid><description>&lt;p&gt;These days I'm working on migrating really legacy system towards the simplified CQRS/DDD design with &lt;a href="http://bliki.abdullin.com/event-sourcing/why"&gt;event sourcing&lt;/a&gt; for the cloud. &lt;/p&gt;

&lt;p&gt;As part of the migration process, I'm &lt;strong&gt;reverse engineering&lt;/strong&gt; legacy SQL database into a stream of events. These events are not precise representation of what has happened in the past (this exact information is irreversibly lost, as in almost any data-driven system), but rather a pretty good estimate that could be used to prepopulate the new version.&lt;/p&gt;

&lt;p&gt;Essentially, &lt;strong&gt;reverse engineering events&lt;/strong&gt; is about writing a &lt;em&gt;throw-away utility&lt;/em&gt; that will scan database tables (MS Access files or punch-cards) and spit out events that could be used to reproduce that state. &lt;/p&gt;

&lt;p&gt;For instance, consider this customer record in DB table:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Customer {
  Name : "GoDaddy",
  Id : SomeGuid,
  Created : 2008-13-12,
  Status : Deleted,
  Phone : "111-22-22",
  Reason : "Supporting SOPA was poor PR move"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This record could be reversed into the following events&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;CustomerCreated!(
  Id: SomeGuid, 
  Name: "GoDaddy", 
  Created: 2008-13-12
)
CustomerPhoneSpecifid!(
  Id: SomeGuid, 
  Phone: "111-22-22"
)
CustomerDeleted!(
  Id: SomeGuid, 
  Reason: "Supporting SOPA was poor PR move", 
  Deleted: 2011-12-24
)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Note, that we actually had to improvise while coming up with this event stream: date of deletion was not stored in the original database (we were losing this information). So we are just substituting some predefined date here (i.e. date of upgrade to CQRS/DDD+ES).&lt;/p&gt;

&lt;p&gt;When you have a system with a few years of history, quite a few events are generated. The system that I'm currently migrating has data that dates back to the early dates of &lt;a href="http://www.lokad.com/"&gt;Lokad&lt;/a&gt;, hence 300-400 thousand events is something expected.&lt;/p&gt;

&lt;p&gt;As part of development process, these events are run through the &lt;a href="http://bliki.abdullin.com/event-sourcing/aggregates"&gt;aggregate&lt;/a&gt; state objects and also through the &lt;a href="http://bliki.abdullin.com/event-sourcing/projections"&gt;projections&lt;/a&gt;. The goal here is to pass all possible sanity checks and get read models that match exactly to the UI currently visible in the old system. If &lt;strong&gt;new system looks and behaves exactly like the old one&lt;/strong&gt; (even if the guts are completely simplified), then we are moving in the right direction.&lt;/p&gt;

&lt;p&gt;Obviously, during this process, a lot of problems show up, especially with logically inconsistent or corrupt data (i.e. accounting inconsistencies caused by race conditions and dead locks in the legacy database). These things are generally to be resolved manually - there is no magical silver bullet.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.abdullin.com/~ff/RinatAbdullin?a=-KogK3_tGLI:6Etu0sCBfrc:-BTjWOF_DHI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RinatAbdullin?i=-KogK3_tGLI:6Etu0sCBfrc:-BTjWOF_DHI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.abdullin.com/~ff/RinatAbdullin?a=-KogK3_tGLI:6Etu0sCBfrc:nQ_hWtDbxek"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RinatAbdullin?d=nQ_hWtDbxek" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.abdullin.com/~ff/RinatAbdullin?a=-KogK3_tGLI:6Etu0sCBfrc:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RinatAbdullin?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.abdullin.com/~ff/RinatAbdullin?a=-KogK3_tGLI:6Etu0sCBfrc:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/RinatAbdullin?i=-KogK3_tGLI:6Etu0sCBfrc:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/RinatAbdullin/~4/-KogK3_tGLI" height="1" width="1"/&gt;</description><wfw:commentRss>http://abdullin.com/journal/rss-comments-entry-14312515.xml</wfw:commentRss><feedburner:origLink>http://abdullin.com/journal/2011/12/24/migrating-legacy-systems-to-event-sourcing.html</feedburner:origLink></item></channel></rss>

