tag:blogger.com,1999:blog-55918658084621366432024-02-08T15:52:25.446+01:00MAD's adventures with softwareMy place to share practical knowledge and tips & tricks about Java, programming and everything. I don't really want to write another blog full of "Hello World" examples or copy-pasted documentation snippets. I'd like to describe here solutions to problems I encountered & solved in my work. Some occasional rant to entertain the public might appear here too ;)Unknownnoreply@blogger.comBlogger14125tag:blogger.com,1999:blog-5591865808462136643.post-66674906726977942052013-02-16T12:22:00.000+01:002013-02-16T12:22:24.759+01:00Enums, Hibernate 4 and Oracle database<p>Recently we were forced to upgrade our application, happily using Hibernate3.5, to latest version of our company's internal framework (must...resist...temptation...to...rant...about...it...). It turned out that this version has a dependency on Hibernate 4.1 so we had to upgrade our persistence layer as well. It's not really a hard job, when you follow the migration guide provided by Hibernate, but after having the project build and pass all the tests (including persistence tests using in-process HSQLDB) again we noticed a strange error at runtime, when it got deployed to app server and run on our target database - Oracle 11. It was happening when a Java enum value was passed into a Criteria query as a parameter:</p>
<script src="https://gist.github.com/marcinderylo/2b014770f92926a0cbd9.js" ></script>
<p>I browsed the documentation of Hibernate (which is rather helpful most of the time) but couldn't find anything mentioning changes in how one should map enums in entities (we're using XML files not annotations). Our mapping has been untouched for years:</p>
<script src="https://gist.github.com/marcinderylo/c8272b1ce221d2417a1b.js"></script>
<p>We found the solution when we realized that <i>org.hibernate.type.EnumType</i> has changed quite a lot between Hibernate versions 3.5 and 4.1. Now there's a possibility to specify a <b>useNamed</b> parameter in the mapping (with boolean value) which prevents EnumType from guessing the way to use the enum (ordinal() or name()) in the query. Adding this parameter to the mapping solved our problem.</p>
<p>As always, the one to blame is Oracle. Their driver is not fully compliant with JDBC 3.0 spec even if they say so. This <a href="https://forums.oracle.com/forums/thread.jspa?threadID=585880">link</a> revealed that this problem is known for years but of course Oracle is like the crazy nastyass honey badger - it doesn't give a shit. This article has also made clear to me that the problem is in the JDBC driver and that I have to look for a workaround. Fortunately, I didn't have to produce yet another custom UserType to make this work.</p>
<p>Good job, Oracle!</p>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-5591865808462136643.post-36870629620417086372012-09-18T14:16:00.003+02:002017-12-11T22:23:16.483+01:00How I built the EventStore on Linux.Yesterday Greg Young's <a href="http://geteventstore.com/">EventStore</a> has its public launch so I couldn't resist and had to check it out. Code's open-sourced on Github, the only problem was that... all my PCs run on Linux and I've never worked with .NET before. Fortunately, EventStore is cross-platform so it turned out not to be hard at all.<br />
<br />
First step was obvious (even for a JVM guy like me):<br />
<blockquote class="tr_bq">
apt-get install mono</blockquote>
Documentation of the project said that I should be using xbuild to build it from source so (with some help from apt-get which is good at finding the packages I'm looking for):<br />
<blockquote class="tr_bq">
apt-get install mono-xbuild</blockquote>
et voila! Motivated by first easy victory I run a quick<br />
<blockquote class="tr_bq">
cd src<br />
xbuild EventStore/EventStore.sln</blockquote>
and... the build crashed. That was not unexpected, and examination of error report quickly led me to another apt-get install:<br />
<blockquote class="tr_bq">
apt-get install mono-dmcs</blockquote>
<br />
The build went on but crashed soon after, with some cryptic messages about missing assemblies. Not knowing what to do I just checked what other mono-* packages are available - <i>mono-devel</i> looked promising so yet another package installation and ... a few seconds later I had the EventStore binaries ready! Yay!<br />
<br />
Running it is a no brainer and you can see the nice monitoring & management UI at <a href="http://127.0.0.1:2113/">http://127.0.0.1:2113</a> .<br />
<br />
Summing up: except for the fact that I didn't have any mono stuff installed (which you probably need if you're doing any development using it) EventStore was dead simple (and fast!) to build & run. Good job guys!<br />
<br />
Can't wait to play with it some more (and maybe port it to JVM?).Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-5591865808462136643.post-16289012974333590102012-05-23T23:15:00.000+02:002012-05-23T23:15:21.973+02:0033rd Degree conference - day 3Looking at the agenda, I knew exactly which talks I wanted to attend on last day of the conference.<br />
<h4>
Integrating JVM languages </h4>
by <a href="https://twitter.com/#!/venkat_s">Venkat Subramaniam</a><br />
<br />
Once again, Venkat gave a very entertaining talk, this time about the integration of various languages running on Java Virtual Machine (Java,Groovy,Scala,JRuby) and the problems one can get into when trying to do it. In general, the integration is quite smooth, but there are some edge cases when the solution is not really trivial. From what I've seen Groovy seems to have the most smooth integration, but things don't look bad with Scala or JRuby. While I didn't gained any immediately enlightening knowledge I got a good introduction into the subject and now I know that it's not that hard to do and knowing a few languages that run on JVM one can pick the one most suitable for the problem at hand and don't suffer too much when integrating it with the rest of the application. That's cool, especially that after Venkat's talk about Scala on the 2nd day our manager gave us green light to use it in our project when we learn the language a bit.<br />
<h4>
MongoDB : Scaling web applications</h4>
by<a href="https://twitter.com/#!/kensipe"> Ken Sipe</a><br />
<br />
This one was another eye-opener, not really for me - because I investigated the topic a bit before - but for some of my colleagues for sure. My boss got quite excited about it as he recognized immediately a part of our system that could be easily implemented using MongoDB as storage (and which has been in development for about 2 years now and still very far from being perfect or even production-ready). Ken shown us an example of real web site with Mongo storing it's data. He offered a few useful bits of advice, like modelling the documents based on the specific use cases, so that there's no need to fetch multiple documents for a single thing. He mentioned ways to scale Mongo and to fine tune its performance. Talk was very informative and as a result I was asked to create a proof-of-concept for replacing the mentioned part of our system with Mongo-based implementation (more on that in another post).<br />
<h4>
The Three Laws of Test Driven Development</h4>
by <a href="https://twitter.com/#!/unclebobmartin">Uncle Bob</a><br />
<br />
I guess I was not the only one really looking forward to this talk. That was the very first time I could meet Uncle Bob live (and I regret I didn't have any of his books for him to sign). As I have read a lot of Uncle's posts and watched a few presentations as well I knew what I could expect, but even then his live performance was an awesome thing to watch, listen & learn from. I guess that almost every phrase could be used as a really good quote.<br />
Introduction of TDD began with some sad numbers, as only about 5% of the industry is doing TDD. This number is however improving rapidly, and in a few years we can expect it to be much better.<br />
Uncle Bob dealt quickly with the myth that developers don't have time to write tests/do TDD. As he said, it's childish to think that we have to make a mess to be quick, even if this mess is going to slow us down in the longer run. When mess in the code base grows, more effort is put into moving it from place to place instead of developing new features. That's not the situation we want to have in our projects as it often ends with a redesign of the whole systems, made by the experienced guys (the "Tiger" team) - the same who made the whole mess in the first place. Of course, team doing the redesign has to be quick to catch up with the feature set of the system they are going to replace. And to be quick, they need to make some mess of course... See the pattern?<br />
Instead of falling into the trap of the big redesign, we should rather concentrate on clearing thes mess one little bit at a time. That's of course the famous Boy Scout Rule that Uncle Bob often mentions. Each time we touch our code, we should make some improvements. Even small ones. Even very small ones. And of course, when writing new code, we should avoid creating mess. Don't even dare to think to yourself: "I'll fix it later". Later does not exist. We all know it.<br />
<blockquote class="tr_bq">
"Bad mgmt can be suffered through but the bad code is the anchor that is bringing the company down"</blockquote>
Unfortunately, we are often reluctant to clean up the mess we find in the code we read. We think if we clean it and break it in the process we'll be responsible for it from now on. Or we might be afraid of touching it because we've got no idea what will happen (break) if we do. As Uncle Bob said:<br />
<br />
<br />
<blockquote class="tr_bq">
"We have created the monster and now the monster rules us" </blockquote>
That's unfortunately sad reality for many (most?) software projects. As professionals we should have control over our creations. Our software can't just work (any idiot can do that). It must be continuously flexible, easy to maintain & modify at any point in its life.<br />
<blockquote class="tr_bq">
"You don't want to be good at debugging. It's not a skill to be desired"<br />"You don't want to spend time debugging. You want to spend time not bugging"</blockquote>
Debugging is hard. And takes a lot of time. The good news is - we can avoid it. Maybe not 100% but most of the time. How? Use the Force, Luke. I mean, use TDD. With TDD done well (that's the trick - you have to do it well otherwise your code will suck as much as it would if you haven't. But to do it well you have to practice it!).<br />
Additional benefits we get when doing TDD are the formal design docs (yup, your tests), nice & decoupled code. And the possibility to refactor with fear.<br />
<br />
Uncle Bob also said more than a few words about fast tests. The suite of unit tests of FitNesse (1892 unit tests) is running on his Mac in under 50s. That's pretty awesome and shows how short feedback loop <u>unit</u> tests give. In our project a suite of 700 tests runs for a few minutes (~3) - most of them are functional tests and it's not very useful for doing TDD. And we have to change our mindset regarding such tests - there's no reason for acceptance tests to be slow. They even can't be slow. It's our job to make them blazing fast. There's no excuse for it.<br />
<blockquote class="tr_bq">
"If you want control over your code you'd better get yourself a suite of tests"</blockquote>
Another important thing is the trust you are willing to put into your test suite. It's like jumping out of a plane with a parachute - you'd better now have any holes in it. Software can be extremely easily broken, just flip a single bit and it's done (unlike your brain which can loose a couple of thousands of cells in a single drinking session and not be affected by this loss). You need a really good suite of tests, one that you can trust your life to. When it runs and passes, you should be convinced that your software works. If you're not and have to check it manually - what good are your tests for?<br />
<br />
And for the end, a few Questions & Answers, which made the whole audience laugh:<br />
<blockquote class="tr_bq">
Q: But we have a testing department, I don't have to write tests!<br />A: Screw you!</blockquote>
<blockquote class="tr_bq">
Q: What about refactorings?<br />A: It's a good idea to refactor your code. Next question"</blockquote>
<blockquote class="tr_bq">
Q: How you start TDD culture in company that doesn't have it?<br />A: You start shooting people at random. Don't get your hopes high regarding developing a TDD culture in your company. And remember - you can always change your organization or change your organization.</blockquote>
<br />
<br />
<h4>
Code Craft</h4>
by <a href="https://twitter.com/#!/ntschutta">Nat Schutta</a><br />
<br />
Next talk was very nice, going back to the basics - good code, bad code and how to improve it (tip: write less of it, less is more). While nothing earth-shattering, it was a real pleasure to listen to a good speaker, got reminded of many things that we might not think about too often. We got reminded to simplify the code, to talk to each other about it (most of us prefers to write code, not to read it, and it's critical to read code) - but we need to remember that we have to be critical of the code, not the people.<br />
Nat also warned us against thinking too much about code reuse - it should be a byproduct, not a rationale (but too often I participate in meetings when we talk about reusing the code that is not even written yet!).<br />
Nat also touched the topic of tests - we should treat them the same way we treat production code and if a developer is not writing them he's not really doing his job.<br />
And the last advice was where to start improving code - we should let the feat guide us. We should start where the code is really scary. That's where the biggest mess is, just begging us to get it cleaned up.<br />
<h4>
Demanding Professionalism</h4>
by <a href="https://twitter.com/#!/unclebobmartin">Uncle Bob</a><br />
<br />
I was really sad when this last keynote started, as I knew that I will have to leave early to catch my train back home.<br />
The talk started with a question what is the <u>software crisis</u>? As Uncle Bob put it:<br />
<blockquote class="tr_bq">
It's so hard to get the damn software done right</blockquote>
One of the major problems is the lack of professionalism in our industry. We see bugs as normal thing that happens rather than "OMG A BUG!". And we live in an illusion that there's no demand for professionalism in software. But thinking about it - how else are we going to deliver features fast, if not by being professional and carefully crafting software?<br />
There's an analogy often made, that building software is a bit like creating buildings. But in fact it's not - a normal architect creates the plans for the building because it's damn expensive to make changes after you started to lay the bricks down. In software, it's cheap so there's no point in having big design up-front. We've got to remember that we're not the masons - our code is not the product, it's the specification the compiler uses to build the product. We're more like architects, preparing plans for the compiler to follow.<br />
Unfortunately, changing your design often works only if the build step is cheap. If we make it expensive (for example long - with slow builds!) the cost of building increases and we have to do more up-front planning. Therefore it's our duty as developers to keep the builds short, so that they don't get in our way when you want to change our design. We cannot submit to the idea that build just takes that much time...<br />
<br />
... and unfortunately this is where 33rd degree conference ended for me. I left the presentation and went back home, with 'REST in practice' book I bought on the O'Reilly stand (James Lewis recommended this book and I must admit that it's a really good read).<br />
<br />
I'm looking forward to coming back for the next edition of 33rd degree, if it will be possible. In the meantime, I'll probably join <a href="http://2012.confitura.pl/">Confitura</a> conference in Warsaw, in June.Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-5591865808462136643.post-200436003997175942012-05-14T23:42:00.002+02:002012-05-14T23:42:47.096+02:0033rd Degree Conference - Day 2Okay, a long time since I wrote the first part of my 33rd degree journal and even a longer time since the conference itself. Still, I will try to write down what I learned, just to refresh my own memory.<br />
<br />
<h4>
Agile, Lean and Startups Practice & Principles to create ultimate value creation machine</h4>
by <a href="https://twitter.com/#!/barryoreilly">Barry O'Reilly</a><br />
<br />
Starting early (not really, but I had some late night discussions with my colleagues) in the morning with a non-technical talk. I'm (unfortunately?) from the corporate world rather than from startup environment so I picked this talk to get a better understanding of how startups work (maybe one day I'll need this knowledge, who knows?). Barry started by introducing (?) waterfall, agile, lean and startup and highlighting some of the differences. He presented how the <a href="http://en.wikipedia.org/wiki/PDCA">Deming cycle</a> applies to startups and gave a handful of useful tips:<br />
<blockquote class="tr_bq">
Ask: What's the smallest thing I can build that will give me a lot of feedback?</blockquote>
<blockquote class="tr_bq">
"Validate that what you're trying to build is the right thing to build.</blockquote>
In startup you don't have infinite time to do useless things as you might have in corporate world (oh yeah, I know something about it...).<br />
<blockquote class="tr_bq">
You need good understanding of the potential users to design a system suiting their needs </blockquote>
<blockquote class="tr_bq">
Street surveys: help the team interact with end users to understand their motivations </blockquote>
<blockquote class="tr_bq">
Developers don't just write code now, they have to understand their users</blockquote>
<blockquote class="tr_bq">
Get out of the building. Go to a coffee shop and talk to someone: Hey, I'm building something... </blockquote>
Barry suggested doing street surveys - the very thought of it scares the s**t out of me but I guess that would be a scary & insightful exercise, as it would take me as far from my comfort zone as possible. That's how we learn after all. There's a few things to remember when doing it:<br />
<blockquote class="tr_bq">
"Always ask Who? Why? How? What? and that kind of questions" </blockquote>
<blockquote class="tr_bq">
"Ask demographic questions first to check if you're talking to the right person"</blockquote>
He also presented a few useful tools that can help people to understand their business (<a href="http://en.wikipedia.org/wiki/Business_Model_Canvas">Business Model Canvas</a>, personas, User value stream maps) and make it work better. And he stressed how important for startups is learning how are you doing (various metrics) & learning from mistakes:<br />
<blockquote class="tr_bq">
Understanding what your customer wants is pure gold</blockquote>
<blockquote class="tr_bq">
Measure - data is the new oil</blockquote>
<blockquote class="tr_bq">
Don't waste your failures - don't celebrate failures but what you learned from them</blockquote>
<br />
I'll finish here as you can find the slideshow located <a href="http://www.slideshare.net/barryoreilly/agile-lean-and-startups">here</a>. I think that the talk, while concentrating on startups, has a lot of value for people coming from corporate world. I think that many of the patterns/tips applied to such environment would only make it better.<br />
<br />
<h4>
Micro Services - Java, the Unix Way</h4>
by <a href="https://twitter.com/#!/boicy">James Lewis</a><br />
<br />
Just noticed today - the <a href="http://www.slideshare.net/jamesalewis/java-microservices">slides</a> are finally available! Yay!<br />
<br />
The title of the talk intrigued me when I first saw it some time before the conference and I knew I'll participate. I think that was the best talk I've been to in the conference - maybe not the best show but I think most valuable from my point of view.<br />
James shared with us the story of a project he participated in - they've build a huge application out of tiny, independent services (divided along the business capabilities of the system - one or more service per capability), implementing using various technologies (individual teams was free to choose whatever technology worked for them), all communicating in the same way - via HTTP.<br />
<br />
<blockquote class="tr_bq">
"Micro service - small enough to fit in your head. Small enough so you can throw it away"</blockquote>
The services were small enough so that they could be discarded & rimplemented at any time. In fact, rewritting them would be even faster & cheaper than applying bigger modifications to them, should the need arise ("Rewrite over Maintain").<br />
<br />
<blockquote class="tr_bq">
"Organize your teams around your business capabilities"</blockquote>
Such divide & conquer approach allowed them to share the workload among many teams, not conflicting with one another (and remember the <a href="http://en.wikipedia.org/wiki/Conway's_law">Conway's law</a>!). Otherwise, they wouldn't be able to meet tight deadlines they had. Additional benefit of this architecture:<br />
<br />
<ul>
<li>can adjust the architecture of individual services according to the specific requirements (like huge data sets or low latency)</li>
<li>adhering to SRP (each application doing only one thing)</li>
</ul>
<blockquote class="tr_bq">
"If the class on the screen is bigger than by head it's too big"</blockquote>
<ul>
<li>individual services fits in one's head (simplicity!)</li>
</ul>
<br />
<blockquote class="tr_bq">
"Be of the web, not behind the web"</blockquote>
The services were talking to each other via REST APIs, using regular request-response calls and publishing ATOM-based event logs.<br />
The services were distributes as standalone JAR files (with Unix rc.d scripts), along with their configuration. To prevent developers from seeing the similarities in the code & extracting tons of common code, they were put in different VCS roots (with some library/infrastructure code being shared as separate artifacts, maintained in a open-source-like way).<br />
Later, James explained how such system scales (see the presentation), what tools have they used. He also stressed that the uniform interface of the services is critical and how to deal with eventual consistency in this case. He didn't manage to talk about versioning but he was asked about it after the talk and explained that they were using automated tests as contracts between the systems - as long as the tests were passing the applications could communicate with their collaborators. I find this a wonderfully simple (conceptually) way to ensure that systems can change & still work together.<br />
<br />
The presentation was a great example how huge things can built from small parts, using well-known, open technologies, without a need to spend years to develop an internal framework that nobody will be familiar with. Additionally, I found it interesting to see the same concepts Greg Young was talking about during his DDD/CQRS training were coming out in this talk (eventual consistency, bounded contexts, simplicity!). I guess great minds think alike and those techniques are not something new, that people could be afraid to use or have troubles with understanding.<br />
<br />
After the talk, I bought the 'REST in Practice' book that James recommended. I'm reading it right now and I see it will make me smarter, even if we're not doing REST in our projects at work.<br />
<h4>
Concurrency Without Pain in Pure Java</h4>
by <a href="https://twitter.com/#!/venkat_s">Venkat Subramaniam</a><br />
<br />
I arrived really late for this talk (stayed a bit longer near the TouK room to listen & talk to James Lewis after his presentation). As for every talk Venkat gave, the room was suffering from a heavy participants overflow so I wasn't really able to see/hear everything. I only saw Venkat showing how to use STM (using <a href="http://clojure.org/refs">Refs</a>) in Java (and Clojure, IIRC). While entertaining (as always!) this talk didn't bring much value to me. Maybe if I had participated from the beginning.<br />
<br />
<h4>
What's new in Groovy 2.0?</h4>
by <a href="https://twitter.com/#!/glaforge">Guillaume Laforge</a><br />
<br />
This was one of those presentation I wasn't paying 100% of my attention to. I don't know Groovy too well so learning what's new wasn't of much use to me but what I've seen looks like a really nice language. I'm a bit surprised that Groovy developers are going in the direction of allowing Groovy code to be statically compiled - I know performance might be an issue (and it certainly is for Groovy 1.x) but that's the tradeoff you make when using a dynamic language - sacrificing performance & compiler checks for reduced development friction & more expressiveness. But anyway, I like the dot- and parentheses-less code you can write with Groovy.<br />
<br />And of course - attending this presentation enabled to get me a seat for the next talk:<br />
<h4>
Scala for the Intrigued</h4>
by <a href="https://twitter.com/#!/venkat_s">Venkat Subramaniam</a><br />
<br />
This one I was really looking for. First - you know the show will be great if Venkat is the presenter (no free seats 15 minutes before the presentation start). Second - from what I have seen so far, Scala looked like a nice language. Maybe not entirely familar, but kind of luring me to give it a try. Therefore I wanted to see what cool features of the language Venkat will show us.<br />
First class support for XML, no primitives, implicits are only some of the goodies you get if you run away from Java language to embrace Scala. As Venkat said - Scala is Java with its flaws fixed. An expressive, low-ceremony language that doesn't need an IDE that will produce hundreds of lines of code for getters, setters etc for you:<br />
<blockquote class="tr_bq">
"Java: I just declare fields and my IDE magically vomit the rest of the getters, setters and constructors"</blockquote>
Additionally, Scala has traits (~ mixins) - something I was often missing when hacking Java code.<br />
Of course, the show was as good as expected and this presentation was a good ending for the second day of the presenatation (at least for me). Scala seems to be really promising and we even get support from our manager to learn Scala and use it (as a proof of concept initially) at work! Good news indeed.<br />
<br />Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-5591865808462136643.post-37656626287458691732012-04-12T23:22:00.003+02:002012-04-12T23:26:01.371+02:0033rd Degree Conference - day 1Thanks to my company, I was able to attend <a href="http://2012.33degree.org/">33rd Degree</a> conference in Kraków a few weeks ago. It was 3 days of great fun & enormous profit (my knowledge growth). Looking at the agenda I didn't suspect it will be such an awesome event.<br />
Let me summarize the talks I attended to and maybe some insights I gained.<br />
<h3>
<a href="http://2012.33degree.org/talk/show/24">Twitter : From Ruby on Rails to the JVM</a> by <a href="http://twitter.com/raffi">Raffi Krikorian</a></h3>
<div>
Opening keynote brought some impressive numbers about Twitter: each tweet causes emails being sent, Blackberry/iPhone/whatever pushes, resulting in 2.5E9 deliveries/day. After this introduction Raffi explained how Twitter, initially a RoR application ended up migrating some parts to the JVM. It turns out that at their scale Ruby's performance was definitely not sufficient. In their search for better performance they turned over to the JVM, but didn't pick its flagship, Java, as their language of choice. Instead, they picked Scala which felt more familiar to developers used to Ruby (they are also using Clojure in some parts!). Additionally, JVM's concurrency model was what they needed (seems that concurrency in Ruby really sucks).</div>
<div>
However, it turns out that out-of-the-box JVM was still not perfect for the real-time, massive scale application that Twitter is. Twitter applications are running on custom JVM builds, having custom garbage collection. Ugh, that seems like challenges that would really scare an average developer. I'm glad I know how others are approaching those issues so I can keep calm if I ever face such problems.</div>
<div>
Next Raffi gave us a short introduction to <a href="http://twitter.github.com/finagle/">Finagle</a>, Twitter's framework for protocol-agnostic RPC, handling a lot of issues for developers: retries, connection management, transient error handling, load-balancing, distributed tracing, service discovery etc. Code samples looked really nice, with concise Scala syntax and all issues not directly related to the business logic hidden by the framework (which doesn't look invasive at all).</div>
<div>
What I found interesting is that at the end Raffi stated that the fact they migrated from RoR to JVM doesn't mean that picking RoR in the first place was a mistake. With RoR you can get your application working really soon, and if you find out you need to scale to the point it's not enough you can look for alternatives. And that's the way he'd suggest startups to proceed.</div>
<div>
I really enjoyed the talk, but felt a bit sad that I don't get to deal with such large scale problems in my work.</div>
<h3>
<a href="http://2012.33degree.org/talk/show/56">Complexity of Complexity</a> by <a href="http://twitter.com/kensipe">Ken Sipe</a></h3>
<div>
Next keynote was less technical, but interesting nonetheless. Some of the things discussed were already well known for me, such as the difference between essential and accidental complexity but Ken also offered a great number of advises really worth remembering. As he says, many things (idempotency for example) seem are hard for us to understand just because we're not familiar with them. Therefore it's hard to say that some programming language is easy and another one is hard. He stated (it was some quote IIRC) that you should pick up the most powerful language of those available and suitable for the problem at hand. Doing otherwise is a mistake. </div>
<div>
Ken also mentioned CAP theorem and shared some lessons learned by eBay developers such as embracing inconsistency and minimizing and controlling dependencies. He talked about the wise choices they've made - keeping the core business components highly available and the non-core only mostly available. Such trade-offs should be made to do the right thing and not waste resources on problems that you don't really have to care that much about. That's something people tend to forget or ignore and try to solve every tiny problem (ignoring the ROI).<br />
I really liked one of the last sentences in the presentation: it's better/cheaper to develop product with good people than with cheap people.<br />
<br />
<h3>
<a href="http://2012.33degree.org/talk/show/6">Pointy haired bosses and pragmatic programmers: Facts and fallacies of software development</a> by <a href="http://twitter.com/venkat_s">Venkat Subramaniam</a></h3>
I never before seen Venkat live. I have seen some of this talks online, but that was quite long ago and I didn't exactly remember what I should expect. The presentation was awesome. Venkat is a true rockstar and an awesome speaker, able to get your attention even if he doesn't say anything really new. He started with comparing software development to surfing - unpredictible, dynamic and really fun (but beware the sharks!). He offered a simple advice how to win software projects - with passionate, competent and responsible people because the thing that affects us most is the people (like Romans affecting the diameter of rocket boosters). Also we got warned of best practices (and advised to run whenever we hear those words).<br />
Of course, as the title of the talk suggests, Venkat also went through a list of fallacies of software development:<br />
<br />
<ul>
<li>More money and time will solve our problems (In fact, it turns out that projects with far deadlines and huge budgets tend to fail). I have already experienced it.</li>
<li>It gotta be good because it's from that large vendor.</li>
<li>Dynamic languages aren't safe (yeah, and Java's static type system is - riiiiiight - about as safe as a monkey using a computer)</li>
</ul>
<div>
A few memorable, fun and/or inspiring quotes from Venkat:</div>
<div>
<ul>
<li>"Standardization before innovation is a bad idea"</li>
<li>"One thing you should never do is arguing with Java compiler"</li>
<li>"Don't fear to try new things, to make mistakes, to push the boundaries"</li>
<li>"A professional who doesn't learn to fail, fails to learn"</li>
<li>"Be unemotional in technical decisions, give things unbiased consideration"</li>
</ul>
<div>
Venkat finished his great show with a really good quote from Robert F. Kennedy, a quote every software professional should know (and agree with):</div>
</div>
<div style="text-align: center;">
<span style="background-color: black; color: white; font-family: georgia, serif; font-size: 14px; line-height: 18px; text-align: left;"><i>“Every time we turn our heads the other way when we see the law flouted, when we tolerate what we know to be wrong, when we close our eyes and ears to the corrupt because we are too busy or too frightened, when we fail to speak up and speak out, we strike a blow against freedom and decency and justice.”</i> </span></div>
<div style="text-align: left;">
<span style="background-color: black; color: white; text-align: -webkit-auto;">Howgh!</span></div>
<h3>
<a href="http://2012.33degree.org/talk/show/59">Build trust in your build to deployment flow</a> by Frederic Simon</h3>
</div>
<div>
This talk was a bit disappointing for me. First, I arrived late because we wasted a lot of time waiting for our pizza in a nearby fast-food (for some unknown reasons we got reservation without lunch at the conference...). Then, the part of the presentation I've seen seemed to be an ad for Artifactory. The only thing I've learned from the talk is that Artifactory looks like a far more sophisticated tool than Nexus we're using at the company (which only seems to have a really slow search capability).</div>
<div>
<br /></div>
<div>
<h3>
<a href="http://2012.33degree.org/talk/show/61">Non blocking, composable reactive web programming with Iteratees</a> by <a href="http://twitter.com/sadache">Sadek Drobi</a></h3>
</div>
<div>
Being unsure what to do next I decided to take a look at Play framework. The presenter warned us at the very beginning that he was badly jetlagged - and that was clearly visible, but I enjoyed the presentation. Scala's (which is the language Play 2.0 is written in) syntax seemed nice again, and the way that the framework handles chunks of data looks interesting. A short demo of the Typesafe Console made me go really <i>Wow</i>! I guess the talk convinced me to take a look at the framework when I get some spare time (and take a look at many other, even more interesting things first).<br />
<h3>
<a href="http://2012.33degree.org/talk/show/48">Every rose has its thorn : Taming the automated tests beast</a> by <a href="http://twitter.com/wseliga">Wojtek Seliga</a></h3>
</div>
<div>
For this talk the room was overflowing with people. Wojtek is a leader in one of the Atlassian's Jira development teams and shared with us his experiences related to automated tests. Atlassian developers are serious about automated testing and Jira has an enormous tests suite, from unit tests to functional to integration tests using HtmlUnit to Selenium tests. The whole suite is about (if I'm not wrong) 13k tests that take an awful lot of time to run, slowing down development and causing fear of committing code (with distributed teams in different time zones, when a build broken by one team can prevent other teams from doing anything useful).</div>
<div>
The presenter was very honest and clear about the mistakes they've made, such as putting all tests into a single project (actually a project per type of tests - unit/functional/etc) which makes the feedback loop extremally long. He shared a tip how to make their integration tests (going through the web UI) easier to maintain using what he called Page Objects (objects exposing actions you can take on given page but hiding the ugly details of parsing HTML etc from the test itself).</div>
<div>
The presentation was really awesome but it unfortunately ended with a sad accident involving a really ugly troll who came out shouting that Jira guys don't know how to write tests at all. When asked what would he do differently he yelled that we'd change the job if he were them and he left. Every time I saw him rising hand on different presentations later on I was expecting another flame but luckily it didn't happen. I regret I couldn't find traces of the troll online (though I remember his name well) - I would like to know where he works (if at all) just to be sure never to join such company ;)</div>
<div>
<br /></div>
<h3>
Summary of day 1</h3>
<div>
If I had any doubts about coming to the conference before, they were all gone after the first day. It was a great experience and learning. I've spent the evening (up to late in the night) discussing what we've learned with my colleagues who were there with me.</div>
<div>
(Oh, yeah, there was the beer party sponsored by ZeroTurnaround but as I don't drink beer it wasn't something I could get excited about.)</div>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-5591865808462136643.post-18534301845748989652012-02-14T21:32:00.000+01:002012-02-14T21:32:23.026+01:00Open sourcing Surveys projectIn late 2010 and first half of 2011 me and a few other friends (<a href="https://twitter.com/#!/dzamroz">Rafał Jamróz</a>, Jacek Bryła and Małgorzata Popiołek) have created a small Java+Flex application for creating, filling and evaluating surveys. It was intended to be used at the <a href="http://www.umcs.lublin.pl/">local university</a> but AFAIK was never really put into use. That's not a big deal, really, because it was an awesome opportunity to learn, away from everyday job's problems and deadlines.<br />
We have spent a lot of time doing refactoring (my main focus was on Java tests), testing new ideas. We even got a major re-write of the user interface when it turned out that our initial concept was not really usable by the target users (on backend the changes were major but not that hard to fit into existing design).<br />
<br />
<br />
Quite a lot of time has passed since we have finished working on it (in fact - abandoned it). From the very beginning we intended to open-source it but were not sure whether our contract will allow us to do it. In the end we were able to keep all the rights to the code (in exchange for 2 years of support period - but we don't spend a lot of time supporting the released version ;) and now the big day has come - <a href="https://github.com/marcinderylo/surveys">Surveys</a> and it's helper projects (<a href="https://github.com/marcinderylo/surveys-flex2java">ActionScript code generator</a> and some <a href="https://github.com/marcinderylo/surveys-commons">commons</a>) go available on the web - hosted on github.<br />
<br />
Initially we did host it on a private SVN repository on <a href="http://xp-dev.com/">Xp-dev.com</a> . We've done all of our development using the old, good SVN but decided to migrate it to git before public release. I used a <a href="http://www.jonmaddox.com/2008/03/05/cleanly-migrate-your-subversion-repository-to-a-git-repository/">short tutorial</a> on how to migrate a repo along with its history to git and it worked great (we've lost some of the history while still on SVN, while splitting projects, renaming svn repos etc.).<br />
<br />
To end this short self-advertisement I would like to say thanks to my collaborators - you were great! I really liked our "stand-up" breakfasts at work and our "iteration" reviews. I had a great time working with you on that project.<br />
<br />
P.S.Head revision might not be stable (I hope it still builds correctly!). To build Flex you might need some dependencies that are not (or maybe were not at that time) available in public Maven repos.Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-5591865808462136643.post-77641441940052719492011-07-12T19:02:00.000+02:002011-07-12T19:02:35.715+02:00FizzBuzz of DoomToday a colleague had to interview a bunch of students (on their 3rd or 4th year at the university I believe) wanting to have their internship at our company. Just before he went to talk to them I mentioned the <a href="http://weblog.raganwald.com/2007/01/dont-overthink-fizzbuzz.html">FizzBuzz</a> problem (huh?) as a nice example of simple screening questions and he decided to ask it the candidates.<br />
When I first heard about it I couldn't really believe this could be a problem for anyone (I suppose I was on my 3rd year of studies at the time). Today I got a hard proof I was terribly wrong. Out of 6 students only 2 gave an acceptable answer to the problem.<br />
<br />
Ouch! I don't really know what to think about it. Thought that FizzBuzz can actually be a problem for CS students makes me feel uneasy. Or maybe there's nothing to worry about? Time will showUnknownnoreply@blogger.com0tag:blogger.com,1999:blog-5591865808462136643.post-84056787441072449202011-07-05T09:12:00.001+02:002011-07-05T09:13:26.878+02:00Coding kataBefore yesterday I have done a coding kata (what is it? a short programming exercise that you will ideally perform daily, write some code and throw it away - for more detailed explanation see <a href="http://codekata.pragprog.com/2007/01/code_kata_backg.html">here</a>) and decided to start doing it daily. It was Roy Osherove's <a href="http://osherove.com/tdd-kata-1/">TDD kata 1</a> .On Sunday I've done it in Java, took be about 20 minutes to complete it (including the advanced part). Yesterday I did it again, this time in Python.<br />
I have learned a bit of Python while studying, done a couple of simple networking apps in it (curses-based IM, Tkinter mail client etc), but that's where my adventure with this fine language ended. Since then I've used it only for small scripts to handle boring tasks, and eventually my knowledge of it has faded.<br />
The basic scope of the String Calculator kata took me 1h to complete! I felt quite ashamed of my performance so decided to re-learn Python. There's a couple of different katas I want to try (including Uncle Bob's <a href="http://butunclebob.com/ArticleS.UncleBob.TheBowlingGameKata">Bowling Kata</a>), and have downloaded JetBrains' <a href="http://www.jetbrains.com/pycharm/">PyCharm</a> IDE to get a decent tooling support (especially documentation, as I have forgotten most of the standard Python library functions). The experience I had with it yesterday was satisfying and I think I will continue evaluating it and learning Python in the process.<br />
Hopefully I have enough self-discipline to do it!Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-5591865808462136643.post-56824665815793778982011-06-28T15:58:00.001+02:002011-06-28T15:59:26.838+02:00My CQRS trainingI've run an internal CQRS training for my team mates. Took 2 hours but we didn't manage to go through all topics I wanted to present. Hallway & canteen to the rescue - had another hour talking about CQRS and event sourcing. Here are my slides: <span class="Apple-style-span" style="font-family: Helvetica, Arial, sans-serif;"><a href="http://bit.ly/kADhjZ" original-title="" style="text-decoration: none;">http://bit.ly/kADhjZ</a>.</span><br />
<span class="Apple-style-span" style="color: #362b36; font-family: Helvetica, Arial, sans-serif;"><br />
</span><br />
<span class="Apple-style-span" style="color: #362b36;"><span class="Apple-style-span" style="font-family: inherit;">I suppose it's now time for a real world CQRS+ES project, huh? :D</span></span>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-5591865808462136643.post-87833193809333584142011-04-20T23:12:00.001+02:002011-11-02T20:55:23.204+01:00Notes from DDD & CQRS training - day 3Here's the last part of my notes from Greg Young's class in Poland. Enjoy!<br />
<br />
<span class="Apple-style-span" style="font-size: large;">Push vs Pull integration</span><br />
<b>Pull</b> is:<br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">Accounting <-- getAccountBalance() --- Sales</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> -------- balance ---------></span><br />
<span class="Apple-style-span" style="font-family: inherit;"><b>Push</b> is:</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">Accounting -- AccountBalanceChanged--> Sales</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><br />
</span><br />
<br />
<ul><li>With pull model we get tight coupling of the systems. With push systems are loosely coupled. System receiving events uses denormalizers to build whatever structural model is needs.</li>
<li>Why is push generally better than pull?</li>
<ul><li>What if we put Accounting system in Poland and Sales in South Africa? </li>
<ul><li>performance will suck when using pull integration model</li>
<li>performance won't be affected as Sales will build it's own view model that can be queried without calling Accounting system</li>
</ul><li><u>weakest link antipattern</u> will hurt systems using pull integration</li>
<li>web services (think -> pull) cause Bounded Contexts boundaries to blur - my team needs to understand how other applications look at my system</li>
<li><b>push reduces coupling between project teams</b> - we don't have to wait for other teams to implement their functionality</li>
<li>doing push means that we don't pollute our system with concepts of other systems</li>
<li>replacing a system with a new one</li>
<ul><li>hard in PULL model (have to support how everyone sees our system)</li>
<li>easy in PUSH (have to support only events)</li>
</ul><li>push keeps us from having a huge, messy canonical model</li>
</ul><li>With push integration we apply the same pattern we did for aggregates - reducing coupling through redundancy</li>
<li>When can pull be beneficial?</li>
<ul><li>when complex calculations must be performed on the data and we don't want to put such logic in every system</li>
<li>data from other system is <u>vital</u> for the business</li>
<li>it's hard to emulate PUSH with an adapter on top of another system</li>
</ul><li>out of events coming from other systems we can build any possible structural model we need</li>
<li>a system <b>publishes a language</b> other systems can listen to</li>
<li><span class="Apple-style-span" style="font-size: large;">PUSH should be the default integration model</span></li>
<li>we can degrade our SLAs in order to achieve higher uptime</li>
<ul><li>it's better to degrade SLA that being down</li>
<li>having errors is often better than being down</li>
<li>we introduce <u>eventual consistency</u></li>
<ul><li>if risk goes too high because of stale data the business can hit the red button to bring the system down </li>
</ul></ul><li>people are afraid of push integration because they are control freaks</li>
<ul><li>they like to have a central point that manages everything</li>
</ul><li>sending heartbeat messages (<i>"hey, i'm still alive"</i>) to let other systems know that we're running fine so that they can act accordingly in case we are down</li>
<li>with push we can do remote calculations without pissing off the users</li>
<li><span class="Apple-style-span" style="font-size: large;">push makes eventual consistency explicit</span> (we still have it implicit in PULL but prefer not to think about it)</li>
<li>doing push == applying OO principles between systems</li>
</ul><span class="Apple-style-span" style="font-size: large;"><br />
</span><br />
<span class="Apple-style-span" style="font-size: large;">Versioning</span> <i>"is dead simple"</i><br />
<br />
<ul><li>wouldn't it be easy if we only added things?</li>
<li>Let's consider version 1: </li>
</ul><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">class InventoryItem {</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> void deactivate() {// ...</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> Apply(new ItemDeactivated(id);</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> }</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">}</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">class InventoryItemDeactivated:Event{</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> public readonly Guid id;</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> InventoryItemDeactivated(Guid id){...}</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">}</span><br />
<ul><li>We'll move to version 2:</li>
</ul><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">// don't change existing event!<br />
class InventoryItemDeactivated:Event{<br />
public readonly Guid id;<br />
InventoryItemDeactivated(Guid id){...}<br />
}<br />
// instead just copy & paste & rename:<br />
public class InventoryItemDeactivated_V2:Event{<br />
public final Guid id;<br />
public final String comment;<br />
InventoryItemDeactivated_V2(Guid id,String comment)</span><br />
<div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> {...}<br />
}<br />
class InventoryItem {<br />
void deactivate(String comment) {<br />
if(comment.isNull()) </span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"> throw new ArgNullEx();<br />
Apply(new ItemDeactivated_V2(id, comment);<br />
// ...<br />
</span>}<br />
}</span><br />
<ul><li>copy & paste the apply() method to handle V2 event</li>
<ul><li>but - as no business logic needs the comment so we don't event copy it into an aggregate</li>
</ul><li>what about V57? gets a little dirty...</li>
<li>new version of event is convertable from the old version of event</li>
<ul><li>if i can't transform v1 to v2 it's not the same event type!!!!</li>
<li>new fields get default value in case of old version events</li>
<li>let's have a method that converts event to newer version</li>
</ul></ul><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">static InventoryItemDeactivatedEvent_V2 convert(</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> InventoryItemDeactivatedEvent e){<br />
return new InventoryItemDeactivatedEvent_V2(e.id, "BEFORE COMMENTS");</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> // or another default value</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">}</span><br />
<ul><ul><li>now we can delete code that deals with old versions of events</li>
</ul><li>we have to version our commands with exactly the same pattern</li>
</ul><span class="Apple-style-span" style="font-size: x-small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">class DeactivateInventoryItem:Command{<br />
public final Guid itemId;<br />
public final int originalVersion;<br />
// constructor...<br />
}<br />
class DeactivateInventoryItem_V2:Command{<br />
final Guid itemId;<br />
public final int originalVersion;<br />
public final String comment;<br />
// constructor<br />
}</span></span></div><div><span class="Apple-style-span" style="font-size: x-small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"></span>/</span><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">/let's jump into command handler:<br />
[Depreciated("13/04/2011")]<br />
public void handle(DeactivateInventoryItem m) {<br />
var item = repo.getById(m.id);<br />
item.deactivate("");<br />
}<br />
public void handle(DeactivateInventoryItem_V2 m) {<br />
var item = repo.getById(m.id);<br />
item.deactivate(m.comment);<br />
}</span><br />
<ul><li>we don't need any support for versioning in our serialization infrastructure</li>
<li>generally we keep 2-3 versions of a command and delete old versions(both handler and command) after some time</li>
<ul><li><i>"how many test you web pages with IE4? why? don't you wanna support them?" </i></li>
</ul><li>keeping multiple versions running concurrently lets the clients do the transition</li>
<li>we never change events!! </li>
<ul><li>we add a new event</li>
<li>a deleting change example: v3 without the comment:</li>
</ul></ul><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">class InventoryItemDeactivated_V3:Event {<br />
public final Guid id;<br />
// removed: public final String comment;<br />
InventoryItemDeactivated_V3(Guid id){...}<br />
}<br />
<br />
//in the convert() function just don't copy the comment!</span><br />
<ul><li>snapshots (using memento pattern):</li>
<ul><li>do it like commands - add a new handling method and keep it until it's no longer needed, then delete it</li>
</ul><li>to prevent events & commands from being changed</li>
<ul><li>don't write them, generate them from XSD</li>
<li>use some tool to detect changes made to XSD and reject checkins</li>
</ul><li><b>bigger problem:</b> we realize that our aggregate boundaries were wrong, what's now?</li>
<ul><li>write a little script to break events apart: </li>
<li>build the original aggregate, build a new aggregate from it and save it (keep the reference (id) to the old aggregate)</li>
<li>this is annoying task but doesn't happen very often</li>
<li>keeping the reference to original aggreagate help other systems integrated in PUSH way (like our read model?) keep their model intact</li>
</ul><li>prefer flat events over those containing little data objects - this is a trade-off between coupling and duplication </li>
<ul><li>it's harder to measure coupling than duplication so normally we don't see those problems</li>
<li>most of the time we introduce coupling to avoid duplication because duplication is easier to spot</li>
<li>flat events don't have problems when a data object definition changes (how would we version that?)</li>
</ul></ul><br />
<span class="Apple-style-span" style="font-size: large;">Merging</span><br />
<br />
<br />
<ul><li>how to get optimal level concurrency?</li>
<ul><li>merging prevents most of the problems with optimistic concurrency</li>
</ul></ul><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">public class MergingHandler : Consumes<t> {</t></span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> public MergingHandler(Consumes<t> next) {...}</t></span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> public void consume(T message) {</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> var commit = eventStore.getEventsSinceVersion(</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> message.AggregateId,message.ExpectedVersion); </span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> foreach(var e in commit) {</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> if(conflictsWith(message,e))</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> throw new RealConcurrencyEx();</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> }<span class="Apple-tab-span" style="white-space: pre;"> </span></span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> next.handle(message);</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> }</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">}</span><br />
<br />
<ul><li>doesn't comparing commands to events seem wrong?</li>
<ul><li>duplicates the business logic from the domain (aggregate)</li>
</ul></ul><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">// following code assumes usage of UOW</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">public class MergingHandler : Consumes<t> {</t></span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> public MergingHandler(Consumes<t> next) {...}</t></span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> public void consume(T message) {</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> var commit = eventStore.getEventsSinceVersion(</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> message.AggregateId,message.ExpectedVersion);</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> next.handle(message);</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> foreach(var e in commit) {</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> foreach(var attempted in UnitOfWork.Current.PeakAll()) {</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> // events that have been created by the aggregate during the operation</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> if(conflictsWith(attempted,e))</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> throw new RealConcurrencyEx();</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> }</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> }</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> }</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">}</span><br />
<br />
<br />
<ul><li>we can often have general rules for generic conflict detection, like:</li>
<ul><li>events of same type tend to conflict</li>
</ul><li>unfortunately, the above example still misses an important thing...</li>
</ul><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">public class MergingHandler : Consumes<t> {</t></span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> public MergingHandler(Consumes<t> next) {...}</t></span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> public void consume(T message) {</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> try {</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> BEGIN:</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> var commit = eventStore.getEventsSinceVersion(</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> message.AggregateId,message.ExpectedVersion); </span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> next.handle(message);</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> foreach(var e in commit) {</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> foreach(var attempted in UnitOfWork.Current.PeakAll()) {</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> if(conflictsWith(attempted,e))</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> throw new RealConcurrencyEx();</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> }</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> }</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> //normally that would be in another cmd handler:</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> UnitOfWork.current.commit();</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> }catch(ConcurrencyException e) {</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> goto BEGIN; // don't do that in production :)</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> }</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> }</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">}</span><br />
<br />
<ul><li>this is simple because we store events - try doing it on sql database with current state data!</li>
<li>in case of conflict rules that are not generic but domain-specific we usually add a conflictsWith(Event another) method on the event</li>
</ul><br />
<br />
<span class="Apple-style-span" style="font-size: large;">Eventual consistency</span><br />
<br />
<br />
<ul><li>don't ask experts: "does the data needs to be eventuall consistent?"</li>
<ul><li>ask: "is it ok to have data that is X time old"</li>
</ul></ul><br />
<span class="Apple-style-span" style="font-size: large;">NEVER USE WORD "INCONSISTENT" WITH BUSINESS PERSON. </span><span class="Apple-style-span" style="font-size: large;">SAY "OLD", "STALE" ETC</span><br />
<br />
<ul><li>for business people inconsistent=wrong</li>
<li>how to get around problems with eventual consistency:</li>
<ul><li>easy thing: "your comment is waiting for moderation"</li>
<li>last thing to do when everything else fails: fake the changes in the client. make it look like things have happened for the user making the changes</li>
<li>UI design & correct user's expectations</li>
<ul><li>educate the user: </li>
<ul><li>tell them that sometimes software takes a second to think about what it's doing.</li>
<li>if the data is not there immediately, wait 2 seconds and press F5. </li>
<li>if it's still not there immediately call tech support</li>
<li>after 1st week users get the point and will wait a bit longer if required</li>
<li><i>"they'are not all idiots"</i></li>
<li><i></i></li>
</ul><li>use task-based UIs to make system look consistent (maximize time between sending commands and issuing a query on the client)</li>
</ul></ul><li>do we have to handle everything in the same pipe? maybe we can high- and low-priority pipes for different things in the system?</li>
</ul><br />
<br />
<ul><li>Set-based validation</li>
<ul><li>what about validating that all usernames must be unique?</li>
<li>we only have consistency within a single AR</li>
<ul><li>do we want to an AllUsers aggregate? erm, maybe not...</li>
</ul></ul><ol><ol><li>ask: how bad is if two users get created with same username withing 500ms of each other? </li>
<li>we can see that something is wrong in an event handler (not a part of read model) and for example send an email?</li>
<li>if we don't trust our clients we can put a validating layer on top of command endpoint checking the constraints in the read layer (but anyway - if the don't behave well they just get bad user experience)</li>
</ol></ol><ul><li>more often than not if you ask about this topic you'll get redirected to <a href="http://codebetter.com/gregyoung/2010/08/12/eventual-consistency-and-set-validation/">this post</a></li>
<li><a href="http://codebetter.com/gregyoung/2010/08/12/eventual-consistency-and-set-validation/"></a><b><u>REMEMBER:</u> solve problems in a business-centric way</b></li>
</ul></ul><span class="Apple-style-span" style="font-size: large;">Never going down</span> (the write side)</div><div><ul><li></li>
<li>put a queue in front of the command handlers</li>
<ul><li>traffic spikes won't overload the system</li>
<li>but we can't ACK/NACK the command - we say we accepted the command and assume it will work</li>
<ul><li>client has to be <i>"pretty damn certain that the command won't fail"</i></li>
<li>might want to provide some minimal validation just before putting cmd into the queue</li>
</ul><li>most people just don't need such architecture, but <b>one-way command pattern</b> is extermaly valuable when they do<span class="Apple-tab-span" style="white-space: pre;"> </span></li>
</ul><li>most message-oriented middleware isn't service bus</li>
<li>point-to-point == observer pattern</li>
<ul><li>easy, great choice with only a few of queues to set up</li>
<li>gets complex with many connections, not scalable in this case</li>
</ul><li>hub & spoke - middle-man observer pattern</li>
<ul><li>we end up buying tibco or biztalk and start putting a lot of logic into it (workflows ...) and it quickly becomes a tangled mess</li>
<li>watching messages flow within organization is easy (debugging too)</li>
<li>single point of failure - when hub is down everything is down</li>
</ul><li>service bus</li>
<ul><li>we distribute the routing information</li>
<li>single point of failure no longer exists</li>
<li>can be hard to manage from network perspective</li>
<li>is a gross overkill in most cases</li>
<li>debugging message flows becomes a pain</li>
<li>extra features offered by service buses cause lots of logic to be put into transport</li>
</ul><li>a bit of humour: <a href="http://en.wikipedia.org/wiki/IP_over_Avian_Carriers">IP over Avian Carriers</a></li>
<ul><li>big lol but...</li>
<li><i>"never underestimate the throughput of a truck full of DVDs - highly latent, huge bandwidth"</i></li>
</ul></ul><br />
<span class="Apple-style-span" style="font-size: large;">Sagas</span><br />
<br />
<br />
<ul><li>what is a saga?</li>
<ul><li>long-running business process? "long" can mean different things ;)</li>
<li>something that spans multiple transaction boundaries and ensures a process of getting back to a known good state if we fail in one of the transactions</li>
</ul><li><span class="Apple-style-span" style="font-size: xx-small;">got some hand-made drawings but don't feel like trying to re-create them in GIMP. why can't I find on Linux something as easy to use as M$ Paint?)</span></li>
<li>most companies get their competitive advantage not from a single system but from a bunch of interoperating systems</li>
<li>we need a facilitator instead of a bunch of business experts from specific domains</li>
<ul><li>the PHBs in suits talking about kanban & lean (process optimization person - we don't want to act as one in this situation)</li>
</ul><li>sagas <b>do not contain business logic</b></li>
<li>set up a set of dependencies: </li>
<ul><li>who </li>
<li>needs </li>
<li>what </li>
<li>when?</li>
</ul><li>sagas move data to the right place at the right time for someone else to do the job</li>
<li>saga always starts in response to a single event coming out of domain model</li>
<li>choreographs the process and makes sure we reach the end</li>
<li>use a correlation id to know which events are related</li>
<ul><li>most of the cases it's a part of the message. </li>
<li>we might have multiple correlation ids.</li>
</ul><li>sagas are state machines </li>
<ul><li>but we don't have implement it as one (few people think in state machines)</li>
</ul><li>between events saga goes to sleep ( join calculus (think: wait, Future etc, continuations))</li>
<li>saga does the routing logic</li>
<ul><li>it does not create data, just routes it between systems</li>
</ul><li>some things have to happen before some amount of time passes</li>
<ul><li>like in the movie <a href="http://www.imdb.com/title/tt0209144/">Memento</a></li>
<li><a href="http://www.imdb.com/title/tt0209144/"></a>no long term memory, have someone else providing information</li>
<li>use alarm clock for that - pass it a message that is an envelope for the message saga will send (?)</li>
<li>we want to avoid having state if possible, it should appear when we need it</li>
</ul><li>types of sagas:</li>
<ul><li>request-response based sagas</li>
<li>document based sagas</li>
</ul><li>commands & events from individual systems become (are starting point for ) ubiquitous language</li>
<li>a saga often starts another saga (for example for handling rollbacks)</li>
<li>dashboards might be easily created from sagas data store (select * from sagastate ...)</li>
<li>if such a process is really important for our business why don't we model it (explicitly)?</li>
<li>sagas are extremally easy to test</li>
<ul><li>small DSL for describing sagas</li>
<ul><li>prove that you always exit correctly</li>
<li>generate all possible paths to exit</li>
</ul></ul><li>document oriented process</li>
<ul><li>like with paper documents multiple persons use & fill with more info</li>
<li>most processes we try to implement has already been done before computers, on paper</li>
<li>but we forgot how we did it (and do the analysis again)</li>
<li>document based sagas are what you need in such cases</li>
<li>in case of big documents we don't send the whole document back and forth, we set up some storage for them and only send the links</li>
</ul><li>RULE OF THUMB FOR VERSIONING SAGAS</li>
<ul><li>when i release a new version all sagas already running stay in old version, all new will be run in new version (unless we've found a really bad bug in old implementation)</li>
<li>changing running sagas is dangerous and should be avoided</li>
<li>this rule makes versioning simple</li>
</ul></ul><br />
<br />
<span class="Apple-style-span" style="font-size: large;">Scaling writes</span><br />
<br />
<br />
<ul><li>we only guarantee CA out from CAP on the write side so we can't partition it</li>
<li>we can do real-time systems with CQRS</li>
<li>stereotypical architecture: single db, multiple app servers with load balancer in front</li>
<ul><li>pros</li>
<ul><li>fault tolerance</li>
<li>can do software upgrade without going down</li>
<li>knowledge about it is widespread</li>
</ul><li>cons</li>
<ul><li>app servers must be stateless!</li>
<li>can't be scaled (just <i>buy a bigger database</i>)</li>
<li>database remains a single point of failure</li>
<li>database might be a performance bottleneck</li>
</ul><li>it's good but has limitations</li>
</ul><li>let's replace the database with a event store!</li>
<ul><li>there's no functional difference between this solution and previous one</li>
<li>loading aggregates on each request increases latency</li>
</ul><li>we might split event store into multiple stores, based on aggregate ID (sharding)</li>
<ul><li>this can (theoretically) go as far as having a single event store per aggregate</li>
<li>problem happens when one of the datastores goes down</li>
<ul><li>we could multiply them with a master-slave pattern</li>
<li>but: each slave increases latency</li>
</ul><li>this allows <u>scaling out</u> our event store</li>
</ul><li>in order to reduce latency we can switch from stateless to statefull app servers</li>
<ul><li>we have a <u>message router</u> (with fast, in-memory routing info) which knows which aggregate resides in each app server</li>
<li>loaded aggregate stays in memory of the app server</li>
<li>over time event store becomes write-only</li>
<li>when a app server goes down message router must distribute it's job among other servers</li>
<ul><li>this can cause latency spike unacceptable for some real-time systems</li>
</ul></ul><li>to solve the problem we can use a <b>warm replica</b> </li>
<ul><li>just as in previous example but:</li>
<ul><li>when message is routed to a server another server is told to shadow the aggregate that the message was directed to</li>
<ul><li>shadowing server loads the AR and subscribes to it's events</li>
</ul><li>events are delivered to shadowing systems by a publisher</li>
<ul><li>stays ~100ms behind original write</li>
<li>can use UDP multicast for publishing events</li>
</ul><li>when a server goes down shadowing server is only 100ms behind it and requires small operation to catch up with current state</li>
<li>this greatly reduces the latency spike when a server is going down</li>
<li>but...</li>
<li><b>we can get rid of the spike completely!</b></li>
<li>when shadowing server receives first command it can act <u>as if it was up-to-date</u></li>
<ul><li>but still listen to events from event store!</li>
<li>until it gets events it created itself it tries to merge</li>
<ul><li>same code as regular events merging!</li>
</ul><li>when it does get its own events it unsubscribes</li>
</ul><li>many businesses will accept the risk of possible merging problems to avoid latency spikes</li>
</ul><li>with this architecture there are no more reads from the event store!</li>
</ul></ul><br />
<br />
<span class="Apple-style-span" style="font-size: large;">Occasionally connected systems</span><br />
My notes here are barely readable drawings on paper with some (even less readable) text here and there. Will unfortunately have to skip it (I'm certainly NOT doing those drawings in GIMP!) but...<br />
Greg already had a <a href="http://skillsmatter.com/podcast/design-architecture/cqrs-not-just-for-server-systems/">presentation</a> on this subject recorded. It covers the same topics (watched it few days before the class).<br />
<br />
The interesting thing here is the conclusion: CQRS is nothing else as plain, old, good MVC (as initially done in Smalltalk) brought to architectural level.<br />
<b>None of these ideas are new</b><span class="Apple-style-span" style="font-size: large;">.</span><br />
Isn't it cool?<br />
The important lesson is:<br />
<span class="Apple-style-span" style="font-size: large;">Review what you have already done.</span><br />
<br />
== END OF DAY 3 ===<br />
and unfortunately of the whole training. A pity, I wouldn't mind at all spending few more days attending to such a great class! Thanks a lot for it, Greg!</div>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-5591865808462136643.post-70358206873562555572011-04-19T23:22:00.001+02:002011-11-02T20:54:01.153+01:00Notes from DDD & CQRS training - day 2That's when things got really interesting. The topics covered were more or less the same as in the <a href="http://cqrs.wordpress.com/video/">6.5h video</a> from one of Greg's previous trainings which I had watched some time before the training during a long, lonely night at a hotel in Germany, but still I was listening at 100% attention. Without further babble, here go my notes:<br />
<br />
<span class="Apple-style-span" style="font-size: large;">Read model</span><br />
<br />
<ul><li>simple, hard to screw up</li>
<li>to be done by low value/junior developers</li>
<li>can be outsourced</li>
<ul><li>can't find better thing to OS</li>
</ul><li>uses whatever model is appropriate</li>
</ul><div><span class="Apple-style-span" style="font-size: large;">Command handlers</span></div><div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">public interface Consumes<T> where T:Message{ </span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> //T would be a command(in case of command handlers) </span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> </span><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">//or an event in case of event handlers/projections</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> void consume(T);</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">}</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">public interface Message {</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> // just a marker interface</span></div></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">}</span></div><div><ul><li>they are the application services in CQRS-based systems, the external edge of the domain model</li>
<li>should contain no logic, not even a simple <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">if</span> statement</li>
<li>can implement cross-cutting concerns</li>
<ul><li>logging</li>
<li>transactions</li>
<li>authentication</li>
<li>authorization</li>
<li>batch commands</li>
<li>exceptions handling</li>
<li>merging</li>
</ul><li>handle cross-cutting concerns not directly in the same class that invokes aggregate method, but using composition (think <a href="http://en.wikipedia.org/wiki/Decorator_pattern">decorator pattern</a>).</li>
</ul><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">class DeactivateInventoryItemCommandHandler : </span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> Consumes<DeactivateInventoryItemCommand> {</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> /* constructor-injected repository */</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> void consume(DeactivateInventoryItemCommand msg) {</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> var item = repository.getById(msg.id);</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> item.deactivate(msg.comment);</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> // this makes batch cmd processing impossible</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> repository.save(item); </span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> }</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">}</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><br />
</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">class LoggingHandler<T> : Consumes<T> {</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> public LoggingHandler(Consumes<T> next) {</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> this.next = next;</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> }<span class="Apple-tab-span" style="white-space: pre;"> </span></span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> public void consume(T message){</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> Logger.write("received message:" + message);</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> next.consume(message);</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> }</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">}</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><br />
</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">var handler = new LoggingHandler(</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> new DeactivateInventoryItemCommandHandler(</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> repo));</span><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">// yay, we've got logging!</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><br />
</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">class AuthorizingHandler : Consumes<T>{</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> AuthorizingHandler(Consumes<T> next){...}</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> void consume(T message){</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> // check authorization then do:</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> next.consume(message);</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> }</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">}</span></div><ul><li><div><div></div></div></li>
<li>make command handler wrapping automatic with reflection:</li>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"></span></ul></div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">[RequiresPermission("admin")]</span><br />
<div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">class DeactivateInventoryItemCommandHandler : </span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> Consumes<DeactivateInventoryItemCommand> {....}</span><br />
<br />
<li>we can make our code our configuration</li><br />
<br />
<br />
</div><br />
<li>above is equal to doing functional composition (with interfaces). it could also be done explicitly:</li><br />
<br />
<br />
<div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">// let's have a lambda:</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">return x => DeactivateInventoryItemCommandHandler(</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> new TestRepository<InventoryItem>(), x); </span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> // this is DI in functional language</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> // using function currying - that's so cool!</span></div><div><br />
</div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">public void DeactivateInventoryItemCommandHandler</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> </span><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">(Repository<InventoryItem repo,</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> DeactivateInventoryItemCommand) {...}</span></div><div><span class="Apple-style-span" style="font-size: large;">Projections</span></div><div><ul><li>consume many events to update a view model</li>
<li>an important explicit concept</li>
<li>will have multiple methods, each handling another type of event</li>
<li>are in 1-to-1 relation with tables (sometimes, but rarely, 1-N)</li>
</ul><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">class InventoryItemCurrentCountProjection : </span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> Consumes<InventoryItemDeactivated/*Event*/>, </span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> Consumes<IventoryItemCreated> , ... </span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>// more events needed to update the view model </span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> // can't directly translate to Java :(</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">{</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>void consume(InventoryItemDeactivated message) {</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>// do sth</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>}<span class="Apple-tab-span" style="white-space: pre;"> </span></span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>void consume(IventoryItemCreated message) {</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>// do sth else</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>}</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">}</span></div><u>BOOK TO READ:</u> <i>The little LISPer</i></div><div><span class="Apple-style-span" style="font-size: large;"><br />
</span></div><div><span class="Apple-style-span" style="font-size: large;"><br />
</span></div><div>CQRS can be done using a single data store for writes & reads. Like building the read model based on SQL views. But we can drive the specialization of write & read side even further. Finally, they've got totally different characteristics.</div><div>And reports run on 3NF database are so sloooow.</div><div>Enter:</div><div><span class="Apple-style-span" style="font-size: large;">Events</span></div><div><ul><li>verbs in past tense - they are things that have already happened, actions completed in the past (think <i>passé composé</i>)</li>
<li>listeners can disagree with them but <span class="Apple-style-span" style="font-size: large;">can't say NO</span></li>
<ul><li>can only compensate</li>
</ul><li>can be used for synchronizing multiple different models</li>
</ul></div><div>So, we'll have our domain model implemented with (n)Hibernate emit events so that we can have our beloved 3NF database and denormalize into multiple read models (to get near infinite scalability)? Just having a 2PC transaction between the write db and a queue?</div><div><br />
</div><div><span class="Apple-style-span" style="font-size: x-large;">Nope. This is guaranteed to fail.</span></div><div>Why? </div><div><ul><li>ORM creates series of deltas</li>
<li>we have to prove that <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">Δ(Hibernate) = Δ(events)</span><span class="Apple-style-span" style="font-family: inherit;"> - not easy</span></li>
<li><span class="Apple-style-span" style="font-family: inherit;">models can get out of sync in case of a bug</span></li>
<ul><li><span class="Apple-style-span" style="font-family: inherit;">such problems can be hard to spot</span></li>
<li>impossible to fix data model broken this way</li>
</ul></ul><span class="Apple-style-span" style="font-size: large;">So, what shall we do?</span></div><div><ul><li>get rid of the ORM so our <b>events are our only source of truth</b></li>
<li>we can have projections populating our 3NF model</li>
<ul><li>but is it worth the costs and increased size of our code base?</li>
</ul><li>this is <b>the poison pill architecture</b></li>
<ul><li>will get you to <b>event sourcing</b></li>
<li>getting rid of 3NF model will let you get rid of </li>
<ul><li>your DBA freaks</li>
<li>costs of DB licences (business will like it!)</li>
</ul></ul></ul><span class="Apple-style-span" style="font-size: x-large;">Event sourcing </span>At last!</div><div><ul><li>in functional programming terms: <u>current state = left fold of past behaviours</u></li>
<li>existing business systems (systems of problem domain, not necessarily computer systems, think: accounting) use history, not current state (like bank account balance)</li>
<li>deriving state from events allows us to change implementation of domain model easily, without affecting object persistence = disconnects the domain model from storage</li>
<li>events cannot be vetoed but we can compensate:</li>
<ul><li>partial compensating actions (difficult, we don't want to go this way)</li>
<li>full compensating actions (accounting people - and developers! - prefer it)</li>
<ul><li>compensate the whole transaction & add another one, correct</li>
</ul></ul><li>ES gives you an additive (append)-only behavioural model</li>
<li>we don't loose any information we would loose with structural model</li>
<ul><li>we can build any structural model from our events</li>
<li>event log let's you see the system as it was at any point of time</li>
<ul><li>this means you can go back in time</li>
<li>which is extremally valuable for debugging!</li>
</ul><li>you can re-run everything that the system has ever done on latest (or any) version of software</li>
</ul><li>when using MongoDB or Cassandra (or sth similar) aggregates can become documents you append events to</li>
<li>user's intention should be carrier through from commands to events</li>
<li>events are not equal to commands, even if from implementation point of view they might be identical</li>
<li>events can be <u>enriched</u> with results of business operations (authorization code of credit card operations, sales tax etc)</li>
<ul><li>this prevents duplication of business logic between various places</li>
</ul></ul><span class="Apple-style-span" style="font-size: large;">Event sourced aggregates</span></div><div><ul><li>a base class is OK</li>
<li>important methods:</li>
<ul><li><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">applyChange(event)</span></li>
<ul><li>calls an event handling method of the aggregate (apply) for the concrete event type</li>
<li>registers events that have happened if it's a new event</li>
</ul><li>public methods defining the business interface of the aggregate</li>
<ul><li>business logic, conditionals live here</li>
</ul><li>private methods defined in concrete aggregate classes handling events</li>
<ul><li>no conditionals</li>
<li>only setting data</li>
</ul><li>l<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">oadFromHistory(IEnumerable<Event></span></li>
<ul><li>accepts an event stream to restore the aggregate from the history</li>
<li>calls the apply method for each event (that's why those methods don't have behaviour, only set the data)</li>
</ul></ul><li>repository</li>
<ul><li>saves only uncommitted changes of the aggregate and marks them as committed in the aggregate (clears the uncommitted events list)</li>
</ul><li>a command makes aggregate produce 0..N events</li>
<li>you need a unit-of-work to support batch command processing</li>
<ul><li>if you don't need it an explicit call to <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">repository.save()</span> in your event handler should be ok</li>
<li>UOW could be configured to accept events from only 1 aggregate and changing that setting to allow batch processing</li>
</ul></ul></div><div>What if<span class="Apple-style-span" style="font-size: large;"> </span>our aggregates have so many events that restoring aggregate state from them becomes a serious performance problem?</div><div><span class="Apple-style-span" style="font-size: large;">Rolling snapshots</span></div><div><ul><li>event log changes: [1,2,3,4,5,6,7] becomes [1,2,3,4,5, snapshot, 6, 7]</li>
<li>don't use direct serialization of aggregates</li>
<ul><li>use <a href="http://en.wikipedia.org/wiki/Memento_pattern">Memento pattern</a></li>
<li>snapshots can be versioned</li>
</ul><li>build snapshots in a separate snapshotter process</li>
</ul><div style="font-size: x-large;"><span class="Apple-style-span" style="font-size: large;">Testing with Event sourcing</span></div><div><span class="Apple-style-span"></span><br />
<div><ul><li><span class="Apple-style-span">DDD testing - no asserting against getters, just the behaviour</span></li>
<span class="Apple-style-span">
<li>an example scenario:</li>
</span></ul></div><div><span class="Apple-style-span"><br />
</span></div><div><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">public class when_deactivating_an_deactivated_inventory_item :</span></span></div><div><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> AggregateSpecification<inventoryitem> {</inventoryitem></span></span></div><div><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> public IEnumerable<event> given() {</event></span></span></div><div><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> yield return New.inventoryItemCreatedWithId(5);</span></span></div><div><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> yield return </span><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">New.inventoryItemDeactivatedWithId(5);</span></span></div><div><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> }</span></span></div><div><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> public override void when() {</span></span></div><div><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> aggregate.Deactivate();</span></span></div><div><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> }</span></span></div><div><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> [Then]</span></span></div><div><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> public void an_invalid_argument_exception_is_thrown() {</span></span></div><div><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> Assert.isType<invalidoperationexception>{thrown};</invalidoperationexception></span></span></div><div><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> }</span></span></div><div><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> [Then]</span></span></div><div><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> public void no_events_are_produced() {</span></span></div><div><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> Assert.isEmpty(events);</span></span></div><div><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> }</span></span></div><div><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">}</span></span></div><div><ul><li><span class="Apple-style-span">there's no magic in it, the base test class is dead simple:</span></li>
<span class="Apple-style-span"> </span></ul></div><div><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">public abstract class AggregateSpecification<t> </t></span></span></div><div><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> where T:AggregateRoot {</span></span></div><div><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> public abstract IEnumerable<event> Given();<span class="Apple-tab-span" style="white-space: pre;"> </span></event></span></span></div><div><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> public abstract void When();</span></span></div><div><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> protected T aggregate;</span></span></div><div><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> protected Exception caught;</span></span></div><div><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> protected List<event> events;</event></span></span></div><div><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><br />
</span></span></div><div><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> [Setup]</span></span></div><div><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> public void Setup() {</span></span></div><div><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> try {</span></span></div><div><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> aggregate = new T();</span></span></div><div><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> aggregate.loadFromHistory(given);</span></span></div><div><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> When();</span></span></div><div><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> events = new List<event>(</event></span></span></div><div><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> aggregate.getUncommittedChanges());</span></span></div><div><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> } catch (Exception ex) {</span></span></div><div><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> caught = ex;</span></span></div><div><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> }</span></span></div><div><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> }</span></span></div><div><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">}</span></span></div><div><ul><li><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-family: 'Times New Roman';">documentation can be generated from those tests</span></span></span></li>
<span class="Apple-style-span">
<li>or: write the tests in natural language and generate test classes from them</li>
<ul><li>then you (and business people) can see your progress as you make test cases pass</li>
<li>such tests can be used as communication tool</li>
<li>generate such docs in html or whatever format on every CI build so that business can see them at any time</li>
<li>override toString() on every event to get human-readable output that can be used in such tests</li>
</ul><li>personal note: this is f*cking awesome!</li>
<li>we could also do it like:</li>
</span></ul></div><div><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">public class when_deactivating_an_deactivated_inventory_item :</span></span></div><div><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> AggregateSpecification<inventoryitem> {</inventoryitem></span></span></div><div><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><br />
</span></span></div><div><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"></span></span><br />
<div><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> public IEnumerable<event> given() {</event></span></span></div><div><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> yield return New.inventoryItemCreated.WithId(5);</span></span></div><div><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> yield return New.inventoryItemDeactivated.WithId(5);</span></span></div><div><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> }</span></span></div><div><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><br />
</span></span></div><div><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> public override Command when() {// difference here!</span></span></div><div><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> return New.DeactivateInventoryItem.WithId(5);</span></span></div><div><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> }</span></span></div><div><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><br />
</span></span></div><div><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> [Then]</span></span></div><div><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> public void an_invalid_argument_exception_is_thrown() {</span></span></div><div><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> Assert.isType<invalidoperationexception>{thrown};</invalidoperationexception></span></span></div><div><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> }</span></span></div><div><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> [Then]</span></span></div><div><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> public void no_events_are_produced() {</span></span></div><div><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> Assert.isEmpty(events);</span></span></div><div><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> }</span></span></div></div><div><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">}</span></span></div><div><ul><li><span class="Apple-style-span">entire testing can be expressed with events & commands</span></li>
<span class="Apple-style-span">
<li>or maybe have a DSL to express those tests in platform-independent way? like:</li>
</span></ul></div><div><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><Given></span></span></div><div><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span><!-- events serialized to XML --</span><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">></span></span></div><div><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"></Given</span><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">></span></span></div><div><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><When</span><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">></span></span></div><div><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span></span><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><</span><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">!-- command serialized to XML --</span><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">></span></span></div><div><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"></When</span><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">></span></span></div><div><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><Expect</span><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">></span></span></div><div><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span></span><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><</span><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">!-- assertions expressed in XML --</span><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">></span></span></div><div><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"></Expect</span></span></div><div><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">></span></span></div><div><ul><li><span class="Apple-style-span">then get (for example) Ruby to make it ever nicer to look at</span></li>
<span class="Apple-style-span">
<li><u>HINT</u>: give business people a comfortable way to share their knowledge to development team</li>
<li>calling a method of an object == sending a message to an object</li>
<li>refucktoring</li>
<ul><li>changing a test is making a _new_ test</li>
</ul><li>versioning -> new tests with new versions</li>
<li><u>HINT</u>: you don't want your devs understand the framework - you want them to<b> understand the CONCEPT</b></li>
</span></ul></div></div><div style="font-size: x-large;"><span class="Apple-style-span" style="font-size: large;">Building an event store </span><span class="Apple-style-span" style="font-size: small;">on top of a SQL db</span></div><div><span class="Apple-style-span"></span><br />
<div><ul><li><span class="Apple-style-span">there's a <a href="http://cqrs.wordpress.com/documents/building-event-storage/">detailed explanation</a> available at cqrsinfo.com</span></li>
<span class="Apple-style-span">
<li>RDBMS provides transactions out-of-the-box</li>
<li>with multiple event stores you can only guarantee events ordering within aggregate boundary (you can do global ordering with single event store)</li>
<li>metadata can be stored along with events (server the event originated in, security context, user, timestamp etc)</li>
<li>uses optimistic concurrency and carries the version between server & client</li>
<li>for storing events a stored procedure is recommended to avoid multiple server-db roundtrips:</li>
</span></ul></div><div><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">BEGIN</span></span></div><div><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> var s = select currentversion from aggregate </span></span></div><div><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> where aggregateid = @1</span></span></div><div><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> if(s==null)</span></span></div><div><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> s = 0</span></span></div><div><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> INSERT INTO AGGREGATES ....</span></span></div><div><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> if( s != expectedVersion)</span></span></div><div><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> throw new ConcurrencyException();</span></span></div><div><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> foreach(event e)</span></span></div><div><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> s++</span></span></div><div><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> INSERT INTO EVENTLOG ...</span></span></div><div><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> update aggregate set currentversion = s</span></span></div><div><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">END</span></span></div><div><ul><li><span class="Apple-style-span">snapshotting </span></li>
<span class="Apple-style-span"> <ul><li>brings in another table ( to avoid concurrency exceptions with the servers writing real events into the store)</li>
<li>snapshotting is done asynchronously by a snapshotter</li>
<li>when to snapshot? when we've got a certain number of events not included in last snapshot (different aggregates can have different snapshotting rules depending on the type etc)</li>
<li>snapshots are NOT necessity for most systems, only a heuristic brought in when we need performance boost on the write side</li>
<li>snaphots can be versioned differently from domain model (thanks to usage of Memento pattern for snapshots)</li>
<li><b>don't do snapshots by default</b></li>
</ul><li>event store is a queue (<i>little mutant freak database-queue hybrid baby</i>)</li>
</span></ul></div></div><div style="font-size: x-large;"><span class="Apple-style-span" style="font-size: large;">CQRS vs CAP theorem</span></div><div><ul><li>CQRS doesn't break the <a href="http://en.wikipedia.org/wiki/CAP_theorem">CAP theorem</a></li>
<li>we don't get all 3 properties <b>at the same time</b></li>
<li>domain (write) side needs <b>C</b> and <b>A</b></li>
<li>read model needs <b>A</b> and <b>P</b></li>
</ul>events, commands and dto are very strong boundaries allowing us to specialize within them</div><div><br />
</div><span class="Apple-style-span" style="font-size: large;">CQRS from business perspective</span></div><div><ul><li>are all developers created equal?</li>
<ul><li>if your answer is yes you're just wrong</li>
<li>if your answer is <b>no</b> - why same people work on domain, UI & data storage?</li>
</ul><li>how much time (%) do you really spend working with your domain? 25%? 30%? 40%?</li>
<li>reasons to create systems in private sector:</li>
<ul><li>make money</li>
<li>save money</li>
<li>manage risk (let's have it just in case)</li>
</ul><li>organizations with high level of maturity can have bigger teams</li>
<li>CQRS can get more people into the team (up to 2.5x) without decreasing maturity level</li>
<ul><li>people can work in 3 teams independent of each other</li>
<li>communication between teams is low</li>
<li>create schema (think XSD) describing DTOs, commands & events in the estimation phase</li>
<ul><li>if you can't - what the hell are you estimating?!</li>
</ul></ul><li>don't allow features to cross iteration boundaries - we want working system, not components, at the end of the iteration</li>
<ul><li>keep teams working on the same feature at the same time</li>
</ul><li>when working with UI you can mock out read model & commands endpoint</li>
<ul><li>same with developing other parts of the system</li>
</ul><li>there are 4 parts of every task/story: domain, GUI, read model, <u>integration</u></li>
</ul></div><div><span class="Apple-style-span" style="font-size: large;">Moving to CQRS+ES architecture</span></div><div><ul><li>one aggregate at a time</li>
<li>ask yourself: how are we gonna kill the system?</li>
<ul><li>when ES-based system dies the events log is all that is left behind</li>
<ul><li>you can migrate from ES to different system by creating a projection matching target data model</li>
</ul></ul></ul><span class="Apple-style-span" style="font-size: large;">CQRS vs stereotypical architecture</span></div><div><ul><li>CQRS</li>
<ul><li>writing to read side sucks</li>
<li>reading is easy</li>
</ul><li>stereotypical architecture</li>
<ul><li>writes are easy</li>
<li>queries suck</li>
</ul><li>we're making a trade-off</li>
<li>both architectures produce an <b>eventually consistent</b> system</li>
<li>what about integration?</li>
<ul><li>CQRS+ES system has integration model build-in!</li>
<ul><li>our read model is in fact integrating with our domain</li>
<li>so we have actually tested our integration model!</li>
<li>we have a nice, <b>push integration model</b></li>
<ul><li>not an ugly, pull model</li>
</ul></ul></ul></ul>=== END OF DAY 2 ===</div><div><br />
</div><div>That's it for now, advanced topics coming next in notes from day 3.</div><div><br />
</div><div>Nighty-night!</div>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-5591865808462136643.post-22805538992904945552011-04-18T23:18:00.009+02:002011-04-18T23:32:21.405+02:00Notes from DDD & CQRS training - day 1<span class="Apple-style-span" style="font-size: x-small;">My notes from the 1st day (11/04/2011) of the DDD/CQRS training by Greg Young, just as I took them - very little post-processing applied so it might be of little help for anyone but me (or maybe other participants of the training).</span><br />
<br />
UIs:<br />
<br />
<ul><li>CRUD (these suck)</li>
<li>task-based (users like those)</li>
</ul><div><b>Aggregate</b>:</div><div><ul><li>group of object we treat together as a whole</li>
<li>affect only a single aggregate - that lets you avoid distributed transactions (think <a href="http://en.wikipedia.org/wiki/Shard_(database_architecture)">horizontal partitioning/sharding</a>)</li>
<li>put the method next to the state it operates on is</li>
<li>denormalization helps to get the design right</li>
</ul><div><b>Booksto read</b>:</div></div><div><ul><li><i>Streamlined object modelling </i></li>
<ul><li>time interval object</li>
<li><span class="Apple-style-span" style="font-size: x-large;">make implicit explicit</span></li>
</ul><li><i>Object-oriented software construction</i> 2nd edition by Bertrand Meyer</li>
<ul><li>describes <a href="http://en.wikipedia.org/wiki/Command-query_separation">CQS</a> </li>
</ul></ul><span class="Apple-style-span" style="font-size: x-large;">saving two objects = bad</span></div><div><br />
</div><div><ul><li>business doesn't care about consistency</li>
<li>breaking bidirectional relationships</li>
<ul><li>ask: <i>do those things need to be consistent? </i></li>
<li>drop consistency of invariant</li>
</ul><li><span class="Apple-style-span" style="font-size: x-large;">domain model != data model</span></li>
<li>if needed, a Domain Service can ensure consistency (this should really be used only as a last resort!)</li>
<li>collection of Transaction objects can have a domain meaning</li>
<li>AggregateRoot (AR) name makes sense for the entire aggregate</li>
<li>too much magic is bad (think <a href="http://en.wikipedia.org/wiki/Object-relational_mapping">ORM</a>)</li>
<li>between aggregates use soft links (IDs) instead of references</li>
</ul><u>TIP:</u> keeping track of Optimistic Concurrency Exceptions makes an interesting statistic</div><div><br />
</div><div><u>EXERCISE:</u> test-drive <b>Probability</b> value object class with methods like <i>combine(Probability)</i>, <i>not()</i> etc, encapsulating a Java's BigDecimal (.NET's Decimal?). The tricky part: you can't have any kind of accessor methods to expose the internal state. What do you test first?</div><div><br />
</div><div>And now... suppose that standard BigDecimal implementation is too slow for your system. You have to change the implementation of the Probability class but retain the API. How many tests do you have to change?</div><div><br />
</div><div><span class="Apple-style-span" style="font-size: x-small;">personal note: this turned out to be an easy, yet an interesting exercise. Funny, how it changes the way you write code when you don't have those evil getters around. I really, really liked it!</span></div><div><br />
</div><div><b>Repository:</b></div><div><ul><li>Evans: works on aggregates, provides domain language to persistence infrastructure</li>
<li>Fowler: purely technical stuff</li>
</ul><br />
<ul><li>make contracts in the domain:</li>
<ul><li>as narrow as possible</li>
<li>as explicit as possible</li>
</ul><li>this will lower the conceptual coupling</li>
</ul><b>Service:</b></div><div><ul><li>any piece of procedural code</li>
<li>can be:</li>
<ul><li>infrastructure</li>
<li>domain</li>
<li>application</li>
</ul><li>but it the end they are all facades</li>
<li>if you do things right you might never need services</li>
<li>interface segregation</li>
<ul><li>single method interfaces</li>
<li>role interfaces</li>
</ul></ul></div><div><a href="http://alistair.cockburn.us/Hexagonal+architecture">Hexagonal architecture</a> - ports & adapters</div><div><u><br class="Apple-interchange-newline" />TIP:</u> why not check check-ins for illegal dependencies (like domain depending on something else) and reject those that don't follow the rules?</div><div><br />
<b>On SOLID principles:</b></div><div><ul><li>they are just heuristics</li>
<li>don't try to stick to them no matter the cost (duplication sometimes can be a good thing!)</li>
</ul><div><u>EXAMPLE:</u> When not to adhere to Interface Segregation?</div><div><ul><li>when all methods go the the same source</li>
</ul><ul><ul></ul></ul><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">class Stream implements ICanSeek,ICanRead,ICanWrite</span></div><div></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">// client code:<br />
void DoesSomething(ICanSeek seeker, ICanRead reader) {<br />
seeker.seekTo(0);</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> while (var x = reader.read() != null) {</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> /...</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> }</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">}</span></div><div><span class="Apple-style-span" style="font-size: x-small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"></span><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">ICanSeekRead extends ICanSeek,ICanRead </span><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">!= Foo implements ICanSeek, ICanRead</span></span></div><ul><li>DI/IoC:</li>
<ul><li>ServiceLocator is totally OK when resolving things <u>at the same layer</u></li>
<li>about injecting into entities: most dependencies match the lifecycle of methods, not objects </li>
</ul></ul><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">void Submit(ISearchDriverLicences s) {</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> s.searchFor("something");</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">}</span></div><ul><ul><li>in functional programming DI can be implemented with <a href="http://en.wikipedia.org/wiki/Currying">function currying</a></li>
</ul></ul><div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">void F() {//coupling from F to G</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> G.Something();</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">}</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">interface ISomething{</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> something();</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">}</span></div><div><span class="Apple-style-span" style="font-size: x-small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">void F(ISomething s) {</span><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> </span></span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> s.something();</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">}</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">class ISomethingImpl:ISomething {</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> // sometimes DI is too much:</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> void something(){</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> Console.WriteLine("Hello world");</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> }</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">}</span></div></div><ul><li>we're overusing tools, frameworks </li>
<ul></ul></ul><blockquote>frameworks pollute our brains</blockquote><br />
Back to <b>services</b>:<br />
<br />
<ul><li>ApplicationServices </li>
<ul><li>should be role interfaces, one for every use case of the system</li>
<li>you should have <b>no business logic</b> in them (not even an <i>if</i> statement!)</li>
</ul></ul></div><div><div><b>isValid() antipattern</b></div><ul><li>pure evil!</li>
<li>don't do that!</li>
<li>causes GIGO (Garbage In, Garbage Out)</li>
<li>entities end up being in one of 3 possible states:</li>
<ul><li>valid</li>
<li>invalid</li>
<li>have no frakking clue</li>
</ul><li>encapsulation is about protecting state - don't let people jam it!</li>
</ul><b>Specification</b></div><div><ul><li><span class="Apple-style-span" style="font-size: x-small;">(<a href="http://en.wikipedia.org/wiki/Specification_pattern">wikipedia</a>)</span></li>
<li>predicate logic (think <a href="http://en.wikipedia.org/wiki/Prolog">Prolog</a>)</li>
<li>might need getters (protected/internal) exposed</li>
<ul><li>but people will start using them as soon as they see them</li>
</ul><li>composite specification</li>
</ul></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">public class AService {</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> AService( IEnumerable<Specification<Customer>> </span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> rules){}</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><br />
void deactivate(Customer c) {</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> if(!rules.areAllValid(c) { </span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> throw new IllegalArgException(); </span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> }</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> ...</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> }</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">}</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><br />
</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">=== END OF DAY 1 ===</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> </span></div><div>Unfortunately, those notes don't show how absolutely awesome the training was. Really got my eyes wide open on many issues that I was somehow missing before.</div><div><br />
</div><div>On a related note - people really do use functional programming in real-world applications! After hearing that from Greg I started learning <a href="http://clojure.org/">Clojure</a>. I had a Prolog & Haskell course back at the university. I didn't like the Prolog part but really enjoyed writing minimized code in Haskell. Now I just have to find some time to refresh by skills at functional programming. Or better - find some use for it so I can justify re-learning it at work ;)</div><div><br />
</div>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-5591865808462136643.post-15918391450169280132011-04-18T22:18:00.001+02:002011-11-02T20:56:58.973+01:00DDD & CQRS trainingLast week I participated to a great training by <a href="http://codebetter.com/gregyoung/">Greg Young</a> in Kraków. I was amazed how much knowledge can get stuffed into my brain in mere 3 days. Prior to the training I have watched a couple of Greg's presentations (yeah, including the 6.5h-long video from a CQRS training), read blogs, followed the <a href="https://groups.google.com/group/dddcqrs/">DDD/CQRS news group</a> but still found myself sitting down as if I were hypnotized for 3x8 hours. Not once during the training Greg's answer let me think that he was talking about something he was unsure of. I find it annoying that some people (read: consultants) give talks about things they don't have any experience with.<br />
<br />
I suppose I won't waste any more time trying to duplicate <a href="http://piotrbuda.eu/2011/04/cqrs-with-greg-young-aftermath/">Piotr's blog entry</a> about the training and will start re-writting my notes immediately.<br />
<br />
<br />
Damn, just found the feedback form Greg asked us to fill in for him. The blog entry will have to wait for a moment.Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-5591865808462136643.post-81997144623291402602011-04-18T21:53:00.001+02:002011-11-02T20:51:08.604+01:00Initial babbleThe time has just come for me to write my first blog entry ever. Okay, maybe not write - publish. Has already written a few but never got to finish & publish one.<br />
<div><br />
<div>On my quest to pretend that I'm more of a social creature that I really am, I also set up a Twitter account In fact it was Greg Young who pushed me to take this desperate step. He found super weird that no one was tweeting during IT conferences in Poland. Maybe some people just don't want to miss their only chance to actually have a face2face chat with real people? Dunno, I just can't imagine wasting my time on Twitter while attending Greg's great <a href="http://en.wikipedia.org/wiki/Domain-driven_design">DDD</a>&<a href="http://cqrs.wordpress.com/">CQRS</a> training (will- hopefully- write more about it in the days to come). I suppose some people (like myself) prefer to stay quiet until they've got something interesting to say. I prefer doing that than talking aloud about things I really got no idea of.<br />
<div><br />
</div><div>Oh wait, I think I got <a href="http://www.youtube.com/watch?v=AE4zF36dPxE&t=2m35s">side-tracked</a> so will get back on the track and finish this short post. I hope I will have some interesting stuff to share with people on this blog. Don't really want to write HelloWorld-style entries but I suppose it could be useful for myself while learning a new technology or another evil Java framework. Will start with my notes from the training mentioned above, that will give me a change to re-read and re-think it. And will make it more durable than the paper I scribbled it on. Hopefully one day someone will find it worth reading. </div><div><br />
</div><div>This entry makes no sense whatsoever but I will publish it nonetheless, just to get myself started with blogging. </div><div><br />
</div><div>Stay tuned for more, I sincerely hope it will come.<br />
<div><br class="Apple-interchange-newline" /></div></div></div></div>Unknownnoreply@blogger.com0