<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
<title type="text">IEnumerable &lt;DevStory&gt;</title>
<generator uri="https://github.com/mojombo/jekyll">Jekyll</generator>
<link rel="self" type="application/atom+xml" href="http://www.ienumerable.it/feed.xml" />
<link rel="alternate" type="text/html" href="http://www.ienumerable.it" />
<updated>2015-12-23T12:04:57+01:00</updated>
<id>http://www.ienumerable.it/</id>
<author>
  <name>Andrea Balducci</name>
  <uri>http://www.ienumerable.it/</uri>
  <email>mtb.snowboard@gmail.com</email>
</author>


<entry>
  <title type="html"><![CDATA[Cost of logging in your architecture]]></title>
 <link rel="alternate" type="text/html" href="http://www.ienumerable.it/2015/04/09/LogPerformance.html" />
  <id>http://www.ienumerable.it/2015/04/09/LogPerformance</id>
  <published>2015-04-09T00:00:00+02:00</published>
  <updated>2015-04-09T00:00:00+02:00</updated>
  <author>
    <name>Andrea Balducci</name>
    <uri>http://www.ienumerable.it</uri>
    <email>mtb.snowboard@gmail.com</email>
  </author>
  <content type="html">&lt;h2 id=&quot;rebuilding-querymodels-from-an-eventstore&quot;&gt;Rebuilding QueryModels from an EventStore&lt;/h2&gt;

&lt;p&gt;Rebuilding all read-models (projections) from an EventStore can be slow, because we are processing hundreds of thousands of events with several projections. This is one area where having a boost in performance is crucial and it is where I want to understand &lt;strong&gt;how much our logging infrastructure impact on performance&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For this scenario I have a small batch of events (~4k) and evlog4net logging level set at DEBUG level; this will generates ~35k log messages in this reference scenario.&lt;/p&gt;

&lt;p&gt;Projections are grouped by slots, each slot contains a certain number of projections, and each slots processes events in a separate thread (the exact architecture will be subject of future post)&lt;/p&gt;

&lt;h2 id=&quot;first-run&quot;&gt;First run&lt;/h2&gt;

&lt;p&gt;Here is what happened during the first run.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/logperformance/first.jpg&quot; alt=&quot;First Run - no log enabled&quot; /&gt;&lt;/p&gt;

&lt;p&gt;This is a low resolution image, but it represents how much time the system needs to rebuild all projections with no log enabled. &lt;em&gt;The Y-Axis represents how many events remain to dispatch for each slot (each graph is one slot), X-Axis represents time.&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;This is the reference scenario, now logging is enabled at DEBUG level, both for our MongoBufferedAppender and for ColoredConsoleAppender.&lt;/p&gt;

&lt;h2 id=&quot;what-happens-with-all-logs-enabled&quot;&gt;What happens with all logs enabled&lt;/h2&gt;

&lt;p&gt;The situation really changed a lot:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/logperformance/second.jpg&quot; alt=&quot;Second Run - ALL logs enabled&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Even if you have no X-Axis legend, it is really evident that the whole process is slowed down a lot having log enabled.&lt;/p&gt;

&lt;blockquote&gt;

  &lt;p&gt;We do not need exact measurement, even if the image is a low resolution one and we have no legend on X-Axis it is evident that: &lt;strong&gt;Enabling logging is slowing down everything&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We have also a really strange behaviour: most of the projections consumes events lineraly, three slots are really slower (this is normal), but when the other slots finished rebuild, the three slow slots speed up considerably. This means that Logging infrastructure is somewhat bounding toghether performances of different slots.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Believe it or not, the reason is, ColoredConsoleAppender&lt;/strong&gt;. We have multiple services running in Console applications with &lt;a href=&quot;https://github.com/Topshelf/Topshelf&quot;&gt;TopShelf&lt;/a&gt;; they can run as a service in production environment, but we use console appender to have a visual clue of what is happening during development/debug, when services are run as standard console applications.&lt;/p&gt;

&lt;h2 id=&quot;stopping-coloredconsoleappender&quot;&gt;Stopping ColoredConsoleAppender&lt;/h2&gt;

&lt;p&gt;The next run is done simply setting threshold level of ColoredConsoleAppender to INFO instead of DEBUG. this reduce number of logs to ~500 for the entire run. Here is the result.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/logperformance/third.jpg&quot; alt=&quot;Third Run - only mongodbappender&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The whole rebuild is really faster. It is still slower that having no log enabled but we have a real better scenario. Again, you do not need exact measurement, the impact of disabling ColoredConsoleAppender is so great that it is evident that Logging to console has a huge impact on performances.&lt;/p&gt;

&lt;p&gt;Actually I never liked too much console appender in log4net for various reason.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;It slows down your application&lt;/li&gt;
  &lt;li&gt;It is difficult to read logs, console app have a limited buffer space and logs disappear quickly.&lt;/li&gt;
  &lt;li&gt;Log disappear when the program is closed&lt;/li&gt;
  &lt;li&gt;You have no way to query log, you only have a huge sequence of text scrolling on a console app&lt;/li&gt;
  &lt;li&gt;If the program crashes usually you see a red log with the exception and the console app immediately closes befoure you can read what happened.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All these consideration lead to an obvious conclusion: Console Appender is not useful, the only purpose is showing you that the program &lt;strong&gt;is doing something and it is not blocked somewhere&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;

  &lt;p&gt;If you want to use logging infrastructure to have an idea of &lt;strong&gt;progress&lt;/strong&gt; of your application, please convince yourself that this is not a good idea. Using logs to verify that the application is &lt;em&gt;doing something&lt;/em&gt; has little utility and it is not the reason logs are built for.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now it is time to the final run.&lt;/p&gt;

&lt;h2 id=&quot;using-mongodbappender-with-writer-on-a-dedicated-thread-and-loosefix&quot;&gt;Using MongoDbAppender with writer on a dedicated thread and LooseFix&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;We can further improve performance if you know how log4net works internally.&lt;/strong&gt; Our MongoDbAppender inherits from BufferingAppenderSkeleton and you can read on my english blog why it slows down performances: &lt;a href=&quot;http://www.codewrecks.com/blog/index.php/2015/03/27/bufferingappenderskeleton-performance-problem-in-log4net/&quot;&gt;BufferingAppenderSkeleton performance problem&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Armed with this knowledge I’ve done a final run using LooseFix and asking mongo appender to use a dedicated thread to save logs and here is the result.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/logperformance/fourth.jpg&quot; alt=&quot;Fourth Run - mongodbappender with LooseFix and dedicated thread&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Even if the image is small, you can verify that this image is quite similar to the first one. This is the desired situation, logging infrastructure cannot be completely transparent in performances, but if the loss in performance is negligible, the advantage of logging lots of information is invaluable.&lt;/p&gt;

&lt;p&gt;MongoDbAppender have several advantages over ColoredConsoleAppender&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;It is durable; logs are maintained after the application is closed&lt;/li&gt;
  &lt;li&gt;You can query to find logs with lots of conditions (even regular expression)&lt;/li&gt;
  &lt;li&gt;You can setup a simple process to move logs from various Mongo source to a single location (Ex Elasticsearch + Kibana)&lt;/li&gt;
  &lt;li&gt;If you poll log collection and read most recent 10 logs and total count you can have &lt;strong&gt;idea of &lt;em&gt;progress&lt;/em&gt;&lt;/strong&gt; (this is not a perfect solution, but at least you can use for this purpose if you want).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;what-we-learned&quot;&gt;What we learned&lt;/h2&gt;

&lt;p&gt;This example give us some guidelines on how to handle log in production:&lt;/p&gt;

&lt;blockquote&gt;

  &lt;p&gt;Logging is useful and the more information you log, the easier is to find a problem. The golden rule is: measure performance penalties in production, &lt;strong&gt;use only a single appender&lt;/strong&gt; to persists logs in a &lt;strong&gt;durable&lt;/strong&gt; medium that &lt;strong&gt;allow searching&lt;/strong&gt; and you are ready to go.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Gian Maria.&lt;/p&gt;

  &lt;p&gt;&lt;a href=&quot;http://www.ienumerable.it/2015/04/09/LogPerformance.html&quot;&gt;Cost of logging in your architecture&lt;/a&gt; was originally published by Andrea Balducci at &lt;a href=&quot;http://www.ienumerable.it&quot;&gt;IEnumerable &lt;DevStory&gt;&lt;/a&gt; on April 09, 2015.&lt;/p&gt;</content>
</entry>


<entry>
  <title type="html"><![CDATA[Setting up a good Test Fixture is not easy]]></title>
 <link rel="alternate" type="text/html" href="http://www.ienumerable.it/2015/03/21/Setting-up-good-fixture.html" />
  <id>http://www.ienumerable.it/2015/03/21/Setting-up-good-fixture</id>
  <published>2015-03-21T00:00:00+01:00</published>
  <updated>2015-03-21T00:00:00+01:00</updated>
  <author>
    <name>Andrea Balducci</name>
    <uri>http://www.ienumerable.it</uri>
    <email>mtb.snowboard@gmail.com</email>
  </author>
  <content type="html">&lt;h2 id=&quot;the-mytical-perfect-unit-test-fixture&quot;&gt;The mytical perfect Unit Test Fixture&lt;/h2&gt;

&lt;p&gt;After years of unit testing I’m really convinced that the real complexity in writing a good Unit Test is &lt;strong&gt;setting up a strong &lt;a href=&quot;http://xunitpatterns.com/test%20fixture%20-%20xUnit.html&quot;&gt;test fixture&lt;/a&gt;&lt;/strong&gt;. Here is an example: in &lt;em&gt;Jarvis&lt;/em&gt; we have a test that runs fine in R# test runner, in Nunit GUI test runner, in Team City build test runner, but is red when it runs inside &lt;em&gt;Visual Studio Test Runner&lt;/em&gt; with Nunit Test adapter.&lt;/p&gt;

&lt;p&gt;After a brief investigation we discovered that the cause was a different handling of System.Threading.Thread.CurrentPrincipal object within the various test runners. Here is our situation&lt;/p&gt;

&lt;h2 id=&quot;what-is-happening-inside-vs&quot;&gt;What is happening inside VS?&lt;/h2&gt;

&lt;p&gt;Here is a stupid test that confirmed our suspicions.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-csharp&quot; data-lang=&quot;csharp&quot;&gt;&lt;span class=&quot;na&quot;&gt;[TestFixture]&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;verify_principal&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;    [Test]&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;verify_principal_is_empty&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;Assert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;That&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Threading&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Thread&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CurrentPrincipal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Identity&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Is&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Or&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Empty&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This simple test verify that &lt;strong&gt;the name of the identity associated to the thread used to run the test is null or empty&lt;/strong&gt;. This test runs green with every test runner, except with Nunit test adapter in Visual Studio.&lt;/p&gt;

&lt;p&gt;When test is executed in Visual Studio, CurrentPrincipal identity is a valid Windows Identity and &lt;strong&gt;it’s equal to your current Windows user&lt;/strong&gt;, and this makes some of our test fails when executed inside visual studio. This confirms me that something different happens inside Visual Studio and I want to fix it.&lt;/p&gt;

&lt;h2 id=&quot;fixture-fixture-fixture&quot;&gt;Fixture Fixture Fixture&lt;/h2&gt;

&lt;p&gt;The test that failed is this one&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-csharp&quot; data-lang=&quot;csharp&quot;&gt;&lt;span class=&quot;na&quot;&gt;[Test]&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;raising_events_without_user_context_should_throw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;router&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;AggregateRootEventRouter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SampleAggregate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;State&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;();&lt;/span&gt;
	&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ex&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Assert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Throws&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;InvalidPrincipalException&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;(()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;router&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Dispatch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SampleAggregateCreated&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SampleAggregateId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)));&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This test verifies that: &lt;em&gt;if you try to raise a Domain Event without user context, the engine should throw an exception&lt;/em&gt;. Clearly this test fails with Visual Studio Nunit test adapter, because CurrentPrincipal.Identity is equal to current user but it runs perfectly with other test runners.&lt;/p&gt;

&lt;p&gt;Actually we can blame VS Test Runner for this behaviour, but &lt;strong&gt;the real cause of the &lt;a href=&quot;http://xunitpatterns.com/Erratic%20Test.html&quot;&gt;erratic test&lt;/a&gt; is due to an imperfect test fixture&lt;/strong&gt;. Let’s this for a moment on the purpose of this test; it is going to verify: &lt;strong&gt;how our engine behave if no user context is set&lt;/strong&gt;. It works perfectly in all test runners except Visual Studio because they runs the test without an identity set in CurrentPrincipal, but this fact is not an assumption of nunit framework.&lt;/p&gt;

&lt;p&gt;If you believe that the real culprit is VS Test Runner, consider what happened if, before this text executes, anohter test sets a valid Principal in Thread.CurrentPrincipal property and it does not restore it to original value when the test is finished. You will end with a failure in all test runners, but the failure  happens only if the test that sets principal is executed before this one. What you have is&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;You run all test, test is red&lt;/li&gt;
  &lt;li&gt;You run the test alone, test is green (because the test that changes CurrentPrincipal is not run)&lt;/li&gt;
  &lt;li&gt;You run all test again, test is red (ouch)&lt;/li&gt;
  &lt;li&gt;You change the name of some test and the test returns green (maybe because the test that changes CurrentPrincipal is run after the erratic test&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is called &lt;a href=&quot;http://xunitpatterns.com/Erratic%20Test.html&quot;&gt;erratic test&lt;/a&gt;, because it is a &lt;strong&gt;test that can fail due to other external conditions&lt;/strong&gt;. Such kind of tests bring real pain when they fails, because you need to understand if the test fails because the underling assumption is wrong (you have a bug) or if it’s an external situation that makes it fail (the bug is in the test). In the long run this kind of test should be either fixed or removed from your suite of test.&lt;/p&gt;

&lt;p&gt;The above test is better refactored in this way:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-csharp&quot; data-lang=&quot;csharp&quot;&gt;&lt;span class=&quot;na&quot;&gt;[Test]&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;raising_events_without_user_context_should_throw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;old_identity&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Threading&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Thread&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CurrentPrincipal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Threading&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Thread&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CurrentPrincipal&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GenericPrincipal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GenericIdentity&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{});&lt;/span&gt;
	&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;router&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;AggregateRootEventRouter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SampleAggregate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;State&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;();&lt;/span&gt;
	&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ex&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Assert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Throws&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;InvalidPrincipalException&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;(()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;router&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Dispatch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SampleAggregateCreated&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SampleAggregateId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)));&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Threading&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Thread&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CurrentPrincipal&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;old_identity&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This test is superior for a number of reasons&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;It explicitly clears the user context before the test.&lt;/li&gt;
  &lt;li&gt;The test is explicitly telling you that the engine is using System.Threading.Thread.CurrentPrincipal to check current user.&lt;/li&gt;
  &lt;li&gt;This test is stable and runs correctly in every test runner.&lt;/li&gt;
  &lt;li&gt;This test is stable even if a previous test set a valid CurrentPrincipal in current Thread for some other reason.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;lesson-learned&quot;&gt;Lesson learned&lt;/h2&gt;

&lt;p&gt;To create stable and reproducible tests, &lt;strong&gt;you need to be sure that the system is the desired state in Fixture Set Up phase, and with desired state I mean every external component or piece of the system that is exercised in the text&lt;/strong&gt;. A typical error is believeing that desired fixture was already setup for you by some other “entity” like the test runner or other tests.&lt;/p&gt;

&lt;p&gt;Gian Maria.&lt;/p&gt;

  &lt;p&gt;&lt;a href=&quot;http://www.ienumerable.it/2015/03/21/Setting-up-good-fixture.html&quot;&gt;Setting up a good Test Fixture is not easy&lt;/a&gt; was originally published by Andrea Balducci at &lt;a href=&quot;http://www.ienumerable.it&quot;&gt;IEnumerable &lt;DevStory&gt;&lt;/a&gt; on March 21, 2015.&lt;/p&gt;</content>
</entry>


<entry>
  <title type="html"><![CDATA[Always execute your code before moving it in production]]></title>
 <link rel="alternate" type="text/html" href="http://www.ienumerable.it/2015/02/24/Always-execute-your-code.html" />
  <id>http://www.ienumerable.it/2015/02/24/Always-execute-your-code</id>
  <published>2015-02-24T00:00:00+01:00</published>
  <updated>2015-02-24T00:00:00+01:00</updated>
  <author>
    <name>Andrea Balducci</name>
    <uri>http://www.ienumerable.it</uri>
    <email>mtb.snowboard@gmail.com</email>
  </author>
  <content type="html">&lt;h2 id=&quot;code-that-was-never-executed-in-production&quot;&gt;Code that was never executed in production&lt;/h2&gt;

&lt;p&gt;One of the greatest risk in software development is &lt;strong&gt;letting untested code slip in production&lt;/strong&gt;. The general rule is: &lt;em&gt;you should always execute your code and verify that it behaves as you expected before moving to production&lt;/em&gt;. Clearly we should prefer automated testing over manual testing, but at least we need to be sure that every part of the code was at least executed once before promote it to production.&lt;/p&gt;

&lt;h2 id=&quot;a-real-example&quot;&gt;A real example&lt;/h2&gt;

&lt;p&gt;Suppose we have this code that represents an Id based on a simple string.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-csharp&quot; data-lang=&quot;csharp&quot;&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;StringId&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Value&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;implicit&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;operator&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;StringId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Equals&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;object&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;obj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
       &lt;span class=&quot;c1&quot;&gt;//....&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And we have also a Customer class based on this type of Id&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-csharp&quot; data-lang=&quot;csharp&quot;&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;CustomerId&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;StringId&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;CustomerId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rawValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Value&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rawValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Customer&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CustomerId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Id&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Name&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Surname&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Int32&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Age&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Double&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TotalOrderAmount&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Finally we have some services that handle accessing data in Sql Database with NHibernate and we have a function that return all customers. To simplify this discussion lets consider a service that keeps data in memory.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-csharp&quot; data-lang=&quot;csharp&quot;&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;CustomerService&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Dictionary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CustomerId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Customer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_inMemoryRepo&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Dictionary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CustomerId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Customer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;();&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;AddCustomer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Customer&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;customer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;_inMemoryRepo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;customer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;customer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;      
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IEnumerable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Customer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GetAllCustomers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_inMemoryRepo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Values&lt;/span&gt;
           &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OrderBy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TotalOrderAmount&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
           &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ThenBy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Trivial code isn’t it? Since it is super simple probably you think that there is no need for testing. If you believe that the above code is simple and correct, you missed a bug.&lt;/p&gt;

&lt;p&gt;Let’s try to write a simple unit test that exercise the code.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-csharp&quot; data-lang=&quot;csharp&quot;&gt;&lt;span class=&quot;na&quot;&gt;[TestMethod]&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;verify_get_all_customers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;CustomerService&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sut&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CustomerService&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;sut&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AddCustomer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Customer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Id&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CustomerId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;c1&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TotalOrderAmount&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;10.0d&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;sut&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AddCustomer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Customer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Id&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CustomerId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;c2&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TotalOrderAmount&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;5.0d&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;sut&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AddCustomer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Customer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Id&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CustomerId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;c3&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TotalOrderAmount&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;16.0d&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;

    &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sut&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GetAllCustomers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Select&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Should&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Have&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SameSequenceAs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;c2&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;c1&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;c3&amp;quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This test is oversimplified, but it represent a similar test that you can write if the service access database trough repository interface.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This test is green, but you have a bug!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The real problem shows up only with certain test data. This new test can highlight the bug.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-csharp&quot; data-lang=&quot;csharp&quot;&gt;&lt;span class=&quot;na&quot;&gt;[TestMethod]&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;verify_get_all_customers_with_same_amount&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;CustomerService&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sut&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CustomerService&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;sut&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AddCustomer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Customer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Id&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CustomerId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;c1&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TotalOrderAmount&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;16.0d&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;sut&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AddCustomer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Customer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Id&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CustomerId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;c2&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TotalOrderAmount&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;10.0d&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;sut&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AddCustomer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Customer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Id&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CustomerId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;c3&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TotalOrderAmount&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;16.0d&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;

    &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sut&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GetAllCustomers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Select&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Should&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Have&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SameSequenceAs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;c2&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;c1&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;c3&amp;quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now examine the differencies: basically it is the same test as before, but &lt;strong&gt;now we have two customers with the same TotalOrderAmount&lt;/strong&gt;, and the test fails with this message.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;System.ArgumentException: At least one object must implement IComparable.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And this is caused by the .ThenBy LINQ instruction. This instruction &lt;em&gt;tries to order objects based on Id property, but since it is a complex type, LINQ does not know how to order based on CustomerId class&lt;/em&gt;. The previous test never exercised the condition specified by the .ThenBy&lt;/p&gt;

&lt;p&gt;The solution is really trivial, just implement the IComparable interface for the StringId base class and everything is green. The real problem happens when &lt;em&gt;this error is discovered in production and you need to do some quick fix&lt;/em&gt;.&lt;/p&gt;

&lt;h2 id=&quot;lesson-learned&quot;&gt;Lesson learned&lt;/h2&gt;

&lt;p&gt;This kind of problem is caused by letting slip in production code that was never executed, nor manually, nor with Unit Testing. This kind of code constitutes a time bomb in your system that can explode in every moment.&lt;/p&gt;

&lt;p&gt;A possible solution is trying to cover all lines of code with Unit Test code coverage, &lt;strong&gt;but code coverage is no perfect. In the previous example if you run only the first unit test (the one that succeeds) you got 100% code coverage for CustomerService class&lt;/strong&gt;. This happens because the code that was really not covered is inside the implementation of the ThenBy LINQ operator.&lt;/p&gt;

&lt;p&gt;This can be a classic example on how difficult is writing Unit Tests that are able to discover every bug in your code.&lt;/p&gt;

&lt;p&gt;Gian Maria.&lt;/p&gt;

  &lt;p&gt;&lt;a href=&quot;http://www.ienumerable.it/2015/02/24/Always-execute-your-code.html&quot;&gt;Always execute your code before moving it in production&lt;/a&gt; was originally published by Andrea Balducci at &lt;a href=&quot;http://www.ienumerable.it&quot;&gt;IEnumerable &lt;DevStory&gt;&lt;/a&gt; on February 24, 2015.&lt;/p&gt;</content>
</entry>


<entry>
  <title type="html"><![CDATA[Ubiquitous Language]]></title>
 <link rel="alternate" type="text/html" href="http://www.ienumerable.it/2014/10/07/Ubiquitous-language.html" />
  <id>http://www.ienumerable.it/2014/10/07/Ubiquitous-language</id>
  <published>2014-10-07T00:00:00+02:00</published>
  <updated>2014-10-07T00:00:00+02:00</updated>
  <author>
    <name>Andrea Balducci</name>
    <uri>http://www.ienumerable.it</uri>
    <email>mtb.snowboard@gmail.com</email>
  </author>
  <content type="html">&lt;h2 id=&quot;what-is&quot;&gt;What is&lt;/h2&gt;
&lt;blockquote&gt;
Programmers should speak the language of domain experts to avoid
miscommunication, delays, and errors. To avoid mental translation between domain
language and code, design your software to use the language of the domain.
Reflect in code how users of the software think and speak about their work.
One powerful approach is to create a domain model.
&lt;br /&gt;&lt;br /&gt;
The ubiquitous language is a living language. Domain experts influence design
and code and the issues discovered while coding influence domain experts.
When you discover discrepancies, it&#39;s an opportunity for conversation and joint
discovery. Then update your design to reflect the results.
&lt;/blockquote&gt;
&lt;p&gt;&lt;em&gt;&lt;a href=&quot;http://www.jamesshore.com/Agile-Book/ubiquitous_language.html&quot;&gt;The Art of Agile Development&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;is-it-all-about-terms&quot;&gt;Is it all about terms?&lt;/h2&gt;
&lt;p&gt;Some time ago I had the pleasure to meet with some friends for a
&lt;a href=&quot;http://www.eventbrite.it/e/guisa-meeting-1-tickets-2972429617&quot;&gt;GUISA meeting&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://twitter.com/andysal74&quot;&gt;Andrea Saltarello&lt;/a&gt; gave the
“Ubiquitous Language Smackdown” talk in which he shared his experience.
We made a very similar experience ourselves (same terms, same communication issues
with our customer), but I was firmly convinced that this approach could be used
only on projects and was not suitable for products where domain experts are our
clients (we craft business software for SME and Public Sector).&lt;/p&gt;

&lt;p&gt;Based on our experience every client speaks it’s own language;
it can depends on the market, the geographical location (even within the same
country) and company size.&lt;/p&gt;

&lt;p&gt;Among our products there’s a &lt;a href=&quot;http://en.wikipedia.org/wiki/Manufacturing_execution_system&quot;&gt;Manufacturing execution system&lt;/a&gt;;
if we talk to a mechanical parts manufacturer we can refer to “Bill of Materials”,
but if we talk to a fashion manufacturer and we say “Bill of Materials” the games
are over: “your product is not for us, we don’t deal with BOM”.
Their bill of materials (IT: “distinta base”) is “Scheda tecnica”; I don’t know
how to correctly translate it with the correct meaning in english, maybe there’s
not this distinction. If we talk with a PCB assembly company, “Scheda tecnica”
means “Product Sheet”.&lt;/p&gt;

&lt;p&gt;With all these terms referring to the &lt;strong&gt;same piece of functionality&lt;/strong&gt; how can
we design and code our model in an Ubiquitous way?&lt;/p&gt;

&lt;p&gt;We gave up on UL until…&lt;/p&gt;

&lt;h2 id=&quot;no-its-all-about-meaning&quot;&gt;No, it’s all about Meaning…&lt;/h2&gt;

&lt;p&gt;One year later I was asked to do a three days class on CQRS+ES, usually I drop
these kind of requests because it’s not our business, our goal is to delivery
(working) software to our customers; teaching others to do the same is community stuff.&lt;/p&gt;

&lt;p&gt;This time I made an exception, and something happened: “Semantic… semantic…
semantic…” I found myself talking &lt;em&gt;all the time&lt;/em&gt; about domain semantics and
how domain semantics can help us to shape our models.&lt;/p&gt;

&lt;p&gt;Probably that GUISA talk was the inception, unconsciously we started to use and
profit UL in a new way (thanks again
&lt;a href=&quot;https://twitter.com/andysal74&quot;&gt;Andrea&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;The whole thing emerged clearly with &lt;a href=&quot;http://ziobrando.blogspot.it/2013/11/introducing-event-storming.html&quot;&gt;Evenstorming&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
There&#39;s a sign on the wall but she wants to be sure&lt;br /&gt;  
Cause you know sometimes words have two meanings&lt;br /&gt;
&lt;br /&gt;
Stairway to Heaven - Led Zeppelin
&lt;/blockquote&gt;

&lt;p&gt;We can’t use Ubiquitous Language with different customers and in our code base
but we can use it on a smaller scope: a single organization.&lt;br /&gt;
Within a single organization Ubiquitous Language is an invaluable discovery tool;
Ubiquitous Language exploration has become the cornerstone of our
&lt;a href=&quot;http://ziobrando.blogspot.it/2013/11/introducing-event-storming.html&quot;&gt;Evenstorming&lt;/a&gt;
process (..more on &lt;a href=&quot;http://www.slideshare.net/andreabalducci/alam-aeki-guida-illustrata-alla-modellazione-di-un-dominio-con-event-sourcing-event-storming&quot;&gt;slideshare&lt;/a&gt;).&lt;/p&gt;

&lt;h2 id=&quot;and-behaviour&quot;&gt;…and Behaviour.&lt;/h2&gt;
&lt;p&gt;As expected, when we found that the same term is used by the people in the
organization with different meanings we have probably saved many hours of work;
I ask the users to write down on a wide blank post-it the meaning of every single
term as soon as it materialize in any command / event / readmodel post-it.&lt;/p&gt;

&lt;p&gt;The discussion starts and leads us very quickly to domain discovery down at
the rainbow’s end!&lt;/p&gt;

&lt;p&gt;Yes, that’s the fastest way to get to the “Pot of Gold”:
&lt;strong&gt;term =&amp;gt; meaning =&amp;gt; use cases =&amp;gt; behavior&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Stay tuned for the next post, I’ll tell you how Ubiquitous Language helped us
to discover behaviour and model the “Document” aggregate in our DMS.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(spoiler: it’s not a single Aggregate root)&lt;/em&gt;&lt;/p&gt;

  &lt;p&gt;&lt;a href=&quot;http://www.ienumerable.it/2014/10/07/Ubiquitous-language.html&quot;&gt;Ubiquitous Language&lt;/a&gt; was originally published by Andrea Balducci at &lt;a href=&quot;http://www.ienumerable.it&quot;&gt;IEnumerable &lt;DevStory&gt;&lt;/a&gt; on October 07, 2014.&lt;/p&gt;</content>
</entry>


<entry>
  <title type="html"><![CDATA[Configurations]]></title>
 <link rel="alternate" type="text/html" href="http://www.ienumerable.it/2014/09/24/configuration.html" />
  <id>http://www.ienumerable.it/2014/09/24/configuration</id>
  <published>2014-09-24T00:00:00+02:00</published>
  <updated>2014-09-24T00:00:00+02:00</updated>
  <author>
    <name>Andrea Balducci</name>
    <uri>http://www.ienumerable.it</uri>
    <email>mtb.snowboard@gmail.com</email>
  </author>
  <content type="html">&lt;h2 id=&quot;why-configurations-are-important&quot;&gt;Why configurations are important&lt;/h2&gt;
&lt;p&gt;When you start working with .NET technologies it seems natural to place application settings inside app.config/web.config files, but this approach usually fails to be useful in long term for various reasons:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;When a software is composed by multiple services it is good to have a single configuration point&lt;/li&gt;
  &lt;li&gt;Config file mixes application specific settings with .NET settings (es. assembly redirect and connection string)&lt;/li&gt;
  &lt;li&gt;Xml is not the best human readable format&lt;/li&gt;
  &lt;li&gt;Frictions for automatic deploy (&lt;a href=&quot;http://msdn.microsoft.com/en-us/library/vstudio/dd465318(v=vs.100).aspx&quot;&gt;web.config transform&lt;/a&gt;, &lt;a href=&quot;http://visualstudiogallery.msdn.microsoft.com/69023d00-a4f9-4a34-a6cd-7e854ba318b5&quot;&gt;SlowCheetah&lt;/a&gt;, etc)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;resist-the-urge-for-complexity&quot;&gt;Resist the urge for complexity&lt;/h3&gt;
&lt;p&gt;As a good rule of thumb, architectures capable of launching rocket into space should be avoided, unless launching a rocket is the real need. If you only need a better configuration manager for a set of services, simplicity should be the key.&lt;/p&gt;

&lt;blockquote&gt;

  &lt;p&gt;Simplicity is the ultimate sophistication. &lt;a href=&quot;http://www.brainyquote.com/quotes/quotes/l/leonardoda107812.html&quot;&gt;Leonardo da Vinci&lt;/a&gt;&lt;/p&gt;

  &lt;p&gt;Keep It Simple, Stupid. &lt;a href=&quot;http://en.wikipedia.org/wiki/KISS_principle&quot;&gt;Wikipedia&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Since I love designing software architectures the risk is producing unnecessary complexity, and I’m trying to change this attitude. The goal should be designing the simplest thing that could possibly work:&lt;/p&gt;

&lt;blockquote&gt;

  &lt;p&gt;Solving simple problem with complex solution, #FAIL.&lt;/p&gt;

  &lt;p&gt;Solving simple problem with simple solution, #GOOD.&lt;/p&gt;

  &lt;p&gt;Solving complex problem with complex solution, #GOOD.&lt;/p&gt;

  &lt;p&gt;Solving complex problem with simple solution, #GENIUS.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Jarvis need “now”, is moving settings away from multiple config files and having a single “configuration manager”; a json file with all the configuration is good enough to start. There are also some little pain for configuration, leading to a simple Configuration Manager class to encapsulate access to json configuration file with some facilities.&lt;/p&gt;

&lt;h3 id=&quot;keep-in-mind-devops&quot;&gt;Keep in mind DevOps&lt;/h3&gt;
&lt;p&gt;Releasing sofware &lt;a href=&quot;http://devopsreactions.tumblr.com/post/57234308379/setting-up-a-product-following-vendors-instructions&quot;&gt;must be an easy and well documented procedure&lt;/a&gt; and Operational people should be facilitated in troubleshooting wrong configruations.&lt;/p&gt;

&lt;p&gt;One of the pain point to address with the new configuration manager is getting rid of this code.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-csharp&quot; data-lang=&quot;csharp&quot;&gt;&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sysUrl&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MongoUrl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ConfigurationManager&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ConnectionStrings&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;system&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ConnectionString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sysdb&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MongoClient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sysUrl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GetServer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GetDatabase&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sysUrl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DatabaseName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This code can bite during deployment. Suppose a connection string is missing; when the service starts it chrashes without any useful log or clue of what is wrong. Logging raw exception can be good for developers, but fails to be useful for operational people. If you got a MongoException or a NullReferenceException with a stack trace you have absolutely no clue of &lt;strong&gt;what is wrong&lt;/strong&gt; and &lt;strong&gt;where you can fix the error&lt;/strong&gt;. One of the goal of good configuration manager is creating good logs full of useful information to troubleshoot wrong settings.&lt;/p&gt;

&lt;p&gt;Thanks to a new configuration manager, I can simply substitute standard ConfigurationManager with the new implementation, leading to code version 2.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-csharp&quot; data-lang=&quot;csharp&quot;&gt;&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sysUrl&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MongoUrl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CqrsConfigurationManager&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Instance&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GetSetting&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;connectionStrings.system&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sysdb&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MongoClient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sysUrl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GetServer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GetDatabase&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sysUrl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DatabaseName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The only difference is in the new CqrsConfigurationManager class; if the setting is missing I got a meaningful log: &lt;em&gt;Required setting ‘connectionStrings.system’ not found in configuration: http://localhost/Jarvis/Debug/config.json&lt;/em&gt;. This log gives two important information: &lt;strong&gt;What&lt;/strong&gt; is missing and &lt;strong&gt;where&lt;/strong&gt; I should add the configuration.&lt;/p&gt;

&lt;h3 id=&quot;fail-as-first-as-possible-and-with-good-log&quot;&gt;Fail as first as possible (and with good log)&lt;/h3&gt;

&lt;p&gt;The  situation is still not optimal because it address only missing configuration but not bad ones. &lt;em&gt;What happens if the configuration is present but is wrong (es. wrong mongo connection string)&lt;/em&gt;? The answer is: &lt;strong&gt;it depends&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Usually the code will throw &lt;strong&gt;&lt;em&gt;some&lt;/em&gt;&lt;/strong&gt; exception &lt;strong&gt;&lt;em&gt;somewhere&lt;/em&gt;&lt;/strong&gt; and only &lt;strong&gt;&lt;em&gt;when&lt;/em&gt;&lt;/strong&gt; the configuration is really used. The &lt;strong&gt;&lt;em&gt;when&lt;/em&gt;&lt;/strong&gt; problem is one of the worst. If your software needs the address of a special mongo instance where it should save commands that raised exception during execution and that settings is wrong, the service starts without any error log, giving you false confidence that everything is good.&lt;/p&gt;

&lt;p&gt;It is only when the code uses that connection string that you start having error logs, probably containing: MongoDbException: &lt;em&gt;Unable to connect to server fingolfin:27017: No such host is known&lt;/em&gt; and absolutely no clue on how to fix it.&lt;/p&gt;

&lt;p&gt;The rule is: &lt;strong&gt;&lt;em&gt;I want my software to detect as soon as possible wrong configuration settings, and log every information needed to do the fix!&lt;/em&gt;&lt;/strong&gt;. This lead  to code version 3.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-csharp&quot; data-lang=&quot;csharp&quot;&gt;&lt;span class=&quot;n&quot;&gt;MongoDatabase&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sysdb&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;CqrsConfigurationManager&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Instance&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;WithSetting&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;connectionStrings.system&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;setting&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sysUrl&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MongoUrl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;setting&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;sysdb&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MongoClient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sysUrl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GetServer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GetDatabase&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sysUrl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DatabaseName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;sysdb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GetStats&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The semantic is simple; WithSetting accepts an optional lambda that should &lt;strong&gt;consume and/or validate the setting in a single step&lt;/strong&gt;. If no exception is thrown or lambda returns empty string, configuration is considered to be good. If the connection string is wrong I immediately got an exception: &lt;em&gt;Error during usage of configuration ‘connectionStrings.system’ - Config location: http://localhost/Jarvis/Debug/config.json - error: Unable to connect to server fingolfin:27017: No such host is known.&lt;/em&gt;. This log contains enough details to understand &lt;strong&gt;what&lt;/strong&gt; configuration is wrong and &lt;strong&gt;where&lt;/strong&gt; it should be fixed.&lt;/p&gt;

&lt;p&gt;This is especially good if the setting is complex, ex: a comma separated list of integers.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-csharp&quot; data-lang=&quot;csharp&quot;&gt;&lt;span class=&quot;n&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Int32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parsedConfig&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;();&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;CqrsConfigurationManager&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Instance&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;WithSetting&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;coefficientList&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;setting&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;splitted&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;setting&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sc&quot;&gt;&amp;#39;,&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Int32&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tmp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;foreach&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;number&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;splitted&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Int32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TryParse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;out&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tmp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;The value &amp;quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;number&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;+&lt;/span&gt;
                    &lt;span class=&quot;s&quot;&gt;&amp;quot; is not a number. I&amp;#39;m expecting a list of integer number comma separated.&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;parsedConfig&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tmp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If a wrong string &lt;em&gt;13,24,3O9&lt;/em&gt; is found in configuration file (there is an O letter instead of zero in last number), the system will log this message: &lt;strong&gt;&lt;em&gt;Error during usage of configuration ‘coefficientList’ - Config location: http://localhost/Jarvis/Debug/config.json - error: The value 3O9 is not a number. I’m expecting a comma separated list of integer.&lt;/em&gt;&lt;/strong&gt;. Whenever a setting is consumed by the application, it is useful to consider a little variant of the famous rule found in &lt;a href=&quot;http://c2.com/cgi/wiki?CodeForTheMaintainer&quot;&gt;Code for the maintainer&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;

  &lt;p&gt;Always code as if the person who ends up &lt;em&gt;installing&lt;/em&gt; your software is a violent psychopath who knows where you live!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Next post will deal on: &lt;em&gt;Where do you specify location of json config file used by CqrsConfigurationManager?&lt;/em&gt;&lt;/p&gt;

  &lt;p&gt;&lt;a href=&quot;http://www.ienumerable.it/2014/09/24/configuration.html&quot;&gt;Configurations&lt;/a&gt; was originally published by Andrea Balducci at &lt;a href=&quot;http://www.ienumerable.it&quot;&gt;IEnumerable &lt;DevStory&gt;&lt;/a&gt; on September 24, 2014.&lt;/p&gt;</content>
</entry>


<entry>
  <title type="html"><![CDATA[Architecture]]></title>
 <link rel="alternate" type="text/html" href="http://www.ienumerable.it/2014/09/18/jarvis-architecture.html" />
  <id>http://www.ienumerable.it/2014/09/18/jarvis-architecture</id>
  <published>2014-09-18T00:00:00+02:00</published>
  <updated>2014-09-18T00:00:00+02:00</updated>
  <author>
    <name>Andrea Balducci</name>
    <uri>http://www.ienumerable.it</uri>
    <email>mtb.snowboard@gmail.com</email>
  </author>
  <content type="html">&lt;h2 id=&quot;jarvis-dev-stack&quot;&gt;Jarvis Dev stack&lt;/h2&gt;
&lt;p&gt;In the previous post we introduced Jarvis, in this we’ll talk about the development stack and the architecture.&lt;/p&gt;

&lt;p&gt;The client is an Html5 AngularJs Single Page Application,
our backend is mostly c#.&lt;/p&gt;

&lt;figure&gt;
  &lt;a href=&quot;/images/jarvis-building-blocks.jpg&quot;&gt;
    &lt;img src=&quot;/images/jarvis-building-blocks.jpg&quot; alt=&quot;Jarvis building blocks&quot; /&gt;
  &lt;/a&gt;
&lt;/figure&gt;

&lt;p&gt;The core domains are implemented in eventsourcing and cqrs on top of &lt;a href=&quot;http://neventstore.org&quot;&gt;NEventstore&lt;/a&gt; with a custom implementation of CommonDomain.&lt;br /&gt;
For &lt;a href=&quot;http://neventstore.org&quot;&gt;NEventstore v5&lt;/a&gt; we needed a better implementation of &lt;a href=&quot;https://github.com/NEventStore/NEventStore.Persistence.MongoDB&quot;&gt;Mongo Persistence Engine&lt;/a&gt; so I started pushing our fixes on Github.. some pull requests after I was invited to join the team (thank you &lt;a href=&quot;https://twitter.com/randompunter&quot;&gt;Damian&lt;/a&gt;).&lt;br /&gt;
That was our first giveback to the dev community, then I patched / enhanced the majority of the core libraries we used in this project.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;That’s (imho) how open source is supposed to work, less complains and more pull requests.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Jarvis core domains are hosted in few (&lt;a href=&quot;https://github.com/Topshelf/Topshelf&quot;&gt;Topshelf&lt;/a&gt; based) windows services  talking each other with &lt;a href=&quot;https://github.com/rebus-org/Rebus&quot;&gt;Rebus&lt;/a&gt; and &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/ms711472(v=vs.85).aspx&quot;&gt;MSMQ&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;a href=&quot;http://www.asp.net/web-api&quot;&gt;webapi&lt;/a&gt; services are hosted in IIS and secured with integrated authentication.&lt;/p&gt;

&lt;h2 id=&quot;data-flow&quot;&gt;Data flow&lt;/h2&gt;

&lt;h3 id=&quot;frontend-api&quot;&gt;Frontend api&lt;/h3&gt;
&lt;p&gt;Jarvis data flow is “realtime async”: our frontend api accepts and validate user commands, translate them in domain commands and push them to our commandbus for delivery.&lt;/p&gt;

&lt;h3 id=&quot;domain-services&quot;&gt;Domain services&lt;/h3&gt;
&lt;p&gt;The destination worker handle the command, with automatic retry and failover, invoking the corresponding aggregate methods, it’s a sort of RPC over service bus: there is not a strict one to one mapping between commands and methods.&lt;/p&gt;

&lt;p&gt;The target aggregate emits events in response to method calls to change its state, the events are persisted in NEventStore waiting for consumers: &lt;a href=&quot;http://cqrs.wikidot.com/doc:projection&quot;&gt;projections&lt;/a&gt;
and
&lt;a href=&quot;http://msdn.microsoft.com/en-us/library/jj591569.aspx&quot;&gt;process managers&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;process-managers&quot;&gt;Process managers&lt;/h3&gt;
&lt;p&gt;Every &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/jj591569.aspx&quot;&gt;process manager&lt;/a&gt; place a subscription on Rebus for the events it is interested in.
To be more accurate a process manager can subscribe to events and messages; a message doesn’t have domain semantic and is exchanged with external high latency services.
The process manager react to events sending new commands and messages.&lt;/p&gt;

&lt;h3 id=&quot;high-latency-services&quot;&gt;High latency services&lt;/h3&gt;
&lt;p&gt;We need to rely on external services for text extraction, document conversion and analisys; all the cpu intensive and high latency tasks are hosted by a service worker installed on one or more machines with a simple round robin routing for task distribution.&lt;/p&gt;

&lt;h3 id=&quot;projections&quot;&gt;Projections&lt;/h3&gt;
&lt;p&gt;Our &lt;a href=&quot;http://cqrs.wikidot.com/doc:projection&quot;&gt;projections&lt;/a&gt; service works in pull mode; projections are grouped by affinity; every group has a subscpription to a polling client on the evenstore and run in its own thread.
Our querymodel is denormalized on &lt;a href=&quot;http://www.mongodb.org&quot;&gt;MongoDb&lt;/a&gt; and &lt;a href=&quot;http://www.elasticsearch.org&quot;&gt;Elasticsearch&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;push-notifications&quot;&gt;Push notifications&lt;/h3&gt;
&lt;p&gt;Query model updates are pushed to subscribers with &lt;a href=&quot;http://signalr.net&quot;&gt;SignalR&lt;/a&gt; and processed by AngularJs for interface updates.&lt;/p&gt;

&lt;figure&gt;
  &lt;a href=&quot;/images/jarvis-architecture.jpg&quot;&gt;
    &lt;img src=&quot;/images/jarvis-architecture.jpg&quot; alt=&quot;Jarvis architecture&quot; /&gt;
  &lt;/a&gt;
&lt;/figure&gt;

&lt;h2 id=&quot;whats-next&quot;&gt;What’s next&lt;/h2&gt;
&lt;p&gt;This architecture worked well for our first customer, we have over 100 concurrent users, databases, frontend api and worker services on the same vmware box.
Cpu is mostly between 1-2%, ram consumption flat and the whole roundript usually takes few milliseconds.&lt;/p&gt;

&lt;p&gt;Rebuilding all the 50+ projections from 350k+ commits takes almost 10 minutes (we are single thread), we need to improve in this area.&lt;/p&gt;

&lt;p&gt;Our querymodel is about 4gb, we expect to grow (at least) by a &lt;a href=&quot;/about-this-blog/&quot;&gt;100x factor&lt;/a&gt; in the next two months.&lt;/p&gt;

&lt;p&gt;We want to split our domains in isolated services and remove the friction for every deploy: we deploy twice a week, some weeks every day (or twice a day).&lt;/p&gt;

&lt;p&gt;To achieve this goal &lt;a href=&quot;/about/gianmariaricci/&quot;&gt;Gian Maria&lt;/a&gt; is working on a configurations dispatcher service and getting rid of all the connection strings and application settings palced in the web/app.config.&lt;/p&gt;

&lt;p&gt;More in the next post.&lt;/p&gt;

  &lt;p&gt;&lt;a href=&quot;http://www.ienumerable.it/2014/09/18/jarvis-architecture.html&quot;&gt;Architecture&lt;/a&gt; was originally published by Andrea Balducci at &lt;a href=&quot;http://www.ienumerable.it&quot;&gt;IEnumerable &lt;DevStory&gt;&lt;/a&gt; on September 18, 2014.&lt;/p&gt;</content>
</entry>


<entry>
  <title type="html"><![CDATA[What is Jarvis?]]></title>
 <link rel="alternate" type="text/html" href="http://www.ienumerable.it/2014/09/13/what-is-jarvis.html" />
  <id>http://www.ienumerable.it/2014/09/13/what-is-jarvis</id>
  <updated>2014-09-14T00:00:00-00:00</updated>
  <published>2014-09-13T00:00:00+02:00</published>
  
  <author>
    <name>Andrea Balducci</name>
    <uri>http://www.ienumerable.it</uri>
    <email>mtb.snowboard@gmail.com</email>
  </author>
  <content type="html">&lt;h2 id=&quot;file--new--intranet&quot;&gt;File &amp;gt; New &amp;gt; Intranet&lt;/h2&gt;

&lt;p&gt;This is the first step of this &lt;a href=&quot;/about-this-blog/&quot;&gt;journey&lt;/a&gt;, we want to tell you what we have built so far.&lt;/p&gt;

&lt;h3 id=&quot;one-year-ago-we-started-an-intranet-20-project-for-a-small-bank&quot;&gt;One year ago we started an “Intranet 2.0” project for a small bank.&lt;/h3&gt;

&lt;p&gt;The project main goal was to improve the ease of access to key informations, avoid personal (and sometimes out of sync) document folders, on user’s desktop.&lt;/p&gt;

&lt;p&gt;We found a &lt;a href=&quot;https://dir.yahoo.com&quot;&gt;“Yahoo Directory”&lt;/a&gt; of about 4.000+ relevant documents (250.000+ pages).&lt;/p&gt;

&lt;p&gt;To simplify document retrieval, every office developed a custom taxonomy to catalog corporate documents.&lt;/p&gt;

&lt;blockquote&gt;
In the beginning there was Chaos,&lt;br /&gt;
And within this Chaos was Power,&lt;br /&gt;
Great Power without Form
&lt;/blockquote&gt;

&lt;p&gt;Forget Google and try to search the internet browsing the &lt;a href=&quot;https://dir.yahoo.com&quot;&gt;“Yahoo Directory”&lt;/a&gt;.. you got it!&lt;/p&gt;

&lt;p&gt;Our first goal was: no more phone calls to “knowledge owners” to find “that document” or endless filesystem style browsing in search of relevant informations.&lt;/p&gt;

&lt;p&gt;So our first domain was a &lt;a href=&quot;http://en.wikipedia.org/wiki/Document_management_system&quot;&gt;DMS&lt;/a&gt;.&lt;/p&gt;

&lt;figure&gt;
&lt;a href=&quot;https://www.flickr.com/photos/kiarras_marinero/8455661691&quot; title=&quot;library by kiarras, on Flickr&quot;&gt;&lt;img src=&quot;https://farm9.staticflickr.com/8532/8455661691_577e00039c_z.jpg&quot; width=&quot;640&quot; height=&quot;426&quot; alt=&quot;library&quot; /&gt;&lt;/a&gt;
  &lt;figcaption&gt;&lt;a href=&quot;https://flic.kr/p/dTctCx&quot; title=&quot;library by kiarras, on Flickr&quot;&gt;library by kiarras, on Flickr&lt;/a&gt;.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Then we moved on:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Support Ticketing with Knowledge Base,&lt;/li&gt;
  &lt;li&gt;Corporate address book,&lt;/li&gt;
  &lt;li&gt;Home Banking workflow,&lt;/li&gt;
  &lt;li&gt;Point Of Sale workflow,&lt;/li&gt;
  &lt;li&gt;Resource scheduling system,&lt;/li&gt;
  &lt;li&gt;Corporate bookmarks,&lt;/li&gt;
  &lt;li&gt;Corporate chat &amp;amp; file exchange,&lt;/li&gt;
  &lt;li&gt;Active Directory sync,&lt;/li&gt;
  &lt;li&gt;Personal &amp;amp; team calendars,&lt;/li&gt;
  &lt;li&gt;Organisation chart,&lt;/li&gt;
  &lt;li&gt;IT asset inventory,&lt;/li&gt;
  &lt;li&gt;Analytics.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Some domains have been implemented with &lt;a href=&quot;http://martinfowler.com/bliki/CQRS.html&quot;&gt;CQRS&lt;/a&gt;+&lt;a href=&quot;http://martinfowler.com/eaaDev/EventSourcing.html&quot;&gt;ES&lt;/a&gt;, others with CRUD.&lt;/p&gt;

&lt;p&gt;Next post I’ll cover the current architecture and our dev stack.&lt;/p&gt;

&lt;p&gt;Stay tuned!&lt;/p&gt;

  &lt;p&gt;&lt;a href=&quot;http://www.ienumerable.it/2014/09/13/what-is-jarvis.html&quot;&gt;What is Jarvis?&lt;/a&gt; was originally published by Andrea Balducci at &lt;a href=&quot;http://www.ienumerable.it&quot;&gt;IEnumerable &lt;DevStory&gt;&lt;/a&gt; on September 13, 2014.&lt;/p&gt;</content>
</entry>


<entry>
  <title type="html"><![CDATA[About this blog]]></title>
 <link rel="alternate" type="text/html" href="http://www.ienumerable.it/2014/09/09/about-this-blog.html" />
  <id>http://www.ienumerable.it/2014/09/09/about-this-blog</id>
  <published>2014-09-09T00:00:00+02:00</published>
  <updated>2014-09-09T00:00:00+02:00</updated>
  <author>
    <name>Andrea Balducci</name>
    <uri>http://www.ienumerable.it</uri>
    <email>mtb.snowboard@gmail.com</email>
  </author>
  <content type="html">&lt;h3 id=&quot;intro&quot;&gt;Intro&lt;/h3&gt;
&lt;p&gt;This blog is about a journey we want to share: we are building a new software product, learning day by day something new from our users, from our mistakes, from our friends.&lt;/p&gt;

&lt;h3 id=&quot;why-we-are-doing-this-quid-pro-quo&quot;&gt;Why we are doing this? (Quid pro quo)&lt;/h3&gt;
&lt;p&gt;No this blog is not a marketing effort, it’s a giveback to the dev community; a giveback we hope can improve our learning journey through your feedback and maybe avoid you a headache for the same mistakes we made.&lt;/p&gt;

&lt;blockquote class=&quot;twitter-tweet&quot;&gt;&lt;p&gt;Learn in the open. Have no shame to publish your code and ask questions and go after it.&lt;/p&gt;&amp;mdash; Kelly Sommers (@kellabyte) &lt;a href=&quot;https://twitter.com/kellabyte/status/504105483569860608&quot;&gt;August 26, 2014&lt;/a&gt;&lt;/blockquote&gt;

&lt;p&gt;ok.. show me the code.&lt;/p&gt;

&lt;h3 id=&quot;what-you-will-find-on-this-blog&quot;&gt;What you will find on this blog?&lt;/h3&gt;
&lt;p&gt;We plan to publish all the code with you (yes, the whole product.. not just code snippets) in 6-9 months when we hope to reach a full featured 1.0 release and have 500+ active paying users.&lt;/p&gt;

&lt;p&gt;We’ll share more about the product (domain insights), tradeoffs and our current dev stack (AngularJS, .Net, NEventstore, CQRS / ES / DDD, MongoDB, Elasticsearch) in the next weeks.&lt;/p&gt;

&lt;p&gt;So.. No code? No party! Hold on… &lt;a href=&quot;http://www.slideshare.net/ziobrando/model-storming&quot;&gt;software development is a learning process, working code is a side effetc&lt;/a&gt;&lt;/p&gt;

&lt;blockquote class=&quot;twitter-tweet&quot;&gt;&lt;p&gt;Stop thinking SW projects like building process, and start thinking Collaborative Learning Processes. Everything becomes clear. &lt;a href=&quot;https://twitter.com/hashtag/agile?src=hash&quot;&gt;#agile&lt;/a&gt; &lt;a href=&quot;https://twitter.com/hashtag/ux?src=hash&quot;&gt;#ux&lt;/a&gt;&lt;/p&gt;&amp;mdash; Alberto Brandolini (@ziobrando) &lt;a href=&quot;https://twitter.com/ziobrando/status/507156257552470016&quot;&gt;September 3, 2014&lt;/a&gt;&lt;/blockquote&gt;

&lt;p&gt;That’s the point, we started this journey one year ago and we are pretty happy with this way of thinking / doing things.&lt;/p&gt;

&lt;p&gt;We want to share what we have learned so far and what we’ll learning in the next months (and yes.. some code too).&lt;/p&gt;

&lt;h3 id=&quot;who-we-are&quot;&gt;Who we are&lt;/h3&gt;
&lt;p&gt;My name is &lt;a href=&quot;/about/andreabalducci/&quot;&gt;Andrea&lt;/a&gt;, I run a small (4 devs) software house in Italy and I’m very active in the local dev communities.&lt;/p&gt;

&lt;p&gt;I failed twice at blogging, this is my 3rd try and the first one in English (well beyond my comfort zone).&lt;/p&gt;

&lt;p&gt;I asked a close friend in the dev community to join us for the next months, we have a new customer and we need to scale up to 100x in terms of data, 4x in terms of active users and a backlog with a lot of new interesting stuff.&lt;/p&gt;

&lt;p&gt;Let me welcome on board &lt;a href=&quot;/about/gianmariaricci/&quot;&gt;Gian Maria&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;My Name is Gian Maria, I’m an independent consultant on .NET technologies, ALM and Microsoft Team Foundation Server and I’m passionate about everything about developing.&lt;/p&gt;

&lt;p&gt;I have a huge interest about DDD and modern software architectures and I was really amazed about the product Andrea built in really short time with its company, so when he start needing help I was really excited to jump in it. The best part of starting collaborating in this project is probably the idea of publish everything online to share [ code | opinions | comments | everything ] with DDD community.&lt;/p&gt;

&lt;p&gt;In the end…. I’m really exited and I hope this will reflects in my blog posts, stay tuned.&lt;/p&gt;

&lt;h3 id=&quot;wrap-up&quot;&gt;Wrap-up&lt;/h3&gt;
&lt;p&gt;Me and Gian Maria we’ll keep this blog up to date with our journey, and we hope to have guest posts from our friends sharing a similar path (and some code) on other projects.
Yes, we are looking at you &lt;a href=&quot;https://twitter.com/ste8&quot;&gt;Stefano&lt;/a&gt; and  &lt;a href=&quot;https://twitter.com/A_Giorgetti&quot;&gt;Alessandro&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;thank-you-guys&quot;&gt;Thank you guys&lt;/h3&gt;
&lt;p&gt;This journey wouldn’t be possible without:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://twitter.com/mauroservienti&quot;&gt;Mauro Servienti&lt;/a&gt;: inadvertently gave me the idea for the product name on our trip to &lt;a href=&quot;http://www.frasassi.com/&quot;&gt;Frasassi caves&lt;/a&gt;;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://twitter.com/ste8&quot;&gt;Stefano Ottaviani&lt;/a&gt;: for choosing this project for his &lt;a href=&quot;http://blogs.ugidotnet.org/ste8/archive/2014/03/03/pubblicazione-della-tesina-su-ddd-e-cqrs.aspx&quot;&gt;graduation thesis&lt;/a&gt;;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://twitter.com/andysal74&quot;&gt;Andrea Saltarello&lt;/a&gt;: Ubiquitous language, Ubiquitous language, Ubiquitous language!;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://twitter.com/ziobrando&quot;&gt;Alberto Brandolini&lt;/a&gt;: for introducing us to &lt;a href=&quot;http://ziobrando.blogspot.it/2013/11/introducing-event-storming.html&quot;&gt;Evenstorming&lt;/a&gt; in the early stages and for sharing a &lt;a href=&quot;http://www.slideshare.net/ziobrando/idea-postit-test-verdi&quot;&gt;talk&lt;/a&gt; inspired by a subdomain of this project;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://twitter.com/amelchiori&quot;&gt;Alessandro Melchiori&lt;/a&gt;: the first talk about CQRS I’ve attended (as a powerpoint assistant.. “next slide please”)… you owe me a beer;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://twitter.com/A_Giorgetti&quot;&gt;Alessandro Giorgetti&lt;/a&gt;: “DDD can’t work! &lt;a href=&quot;https://angularjs.org/&quot;&gt;Angular&lt;/a&gt;? No, &lt;a href=&quot;http://knockoutjs.com/&quot;&gt;KnockoutJS&lt;/a&gt; is fine”. Now he’s mastering DDD &amp;amp; AngularJs in the healthcare.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Our chats about aggregates, process managers, ubiquitous language, eventstorming, CQRS and Domain Driven Design are the building blocks of this journey.&lt;/p&gt;

&lt;p&gt;A special mention goes to &lt;a href=&quot;https://twitter.com/abdullin&quot;&gt;Rinat Abdullin&lt;/a&gt; for inspiring this blog with his &lt;a href=&quot;http://abdullin.com/long/happypancake/&quot;&gt;HappyPancake post&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Curious? Suggestions?&lt;/strong&gt; we are waiting your feedback and we have room in our blog backlog.&lt;/p&gt;

&lt;script async=&quot;&quot; src=&quot;//platform.twitter.com/widgets.js&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;


  &lt;p&gt;&lt;a href=&quot;http://www.ienumerable.it/2014/09/09/about-this-blog.html&quot;&gt;About this blog&lt;/a&gt; was originally published by Andrea Balducci at &lt;a href=&quot;http://www.ienumerable.it&quot;&gt;IEnumerable &lt;DevStory&gt;&lt;/a&gt; on September 09, 2014.&lt;/p&gt;</content>
</entry>


<entry>
  <title type="html"><![CDATA[Wish we could say more]]></title>
 <link rel="alternate" type="text/html" href="http://www.ienumerable.it/2014/09/04/wish-we-could-say-more.html" />
  <id>http://www.ienumerable.it/2014/09/04/wish-we-could-say-more</id>
  <published>2014-09-04T00:00:00+02:00</published>
  <updated>2014-09-04T00:00:00+02:00</updated>
  <author>
    <name>Andrea Balducci</name>
    <uri>http://www.ienumerable.it</uri>
    <email>mtb.snowboard@gmail.com</email>
  </author>
  <content type="html">&lt;h1 id=&quot;section&quot;&gt;09.09.2014&lt;/h1&gt;

&lt;h3 id=&quot;coming-soon&quot;&gt;coming soon…&lt;/h3&gt;

&lt;p&gt;&lt;span style=&quot;color:white&quot;&gt;hits in meta, if you don’t have already inspected page source :P&lt;/span&gt;&lt;/p&gt;

  &lt;p&gt;&lt;a href=&quot;http://www.ienumerable.it/2014/09/04/wish-we-could-say-more.html&quot;&gt;Wish we could say more&lt;/a&gt; was originally published by Andrea Balducci at &lt;a href=&quot;http://www.ienumerable.it&quot;&gt;IEnumerable &lt;DevStory&gt;&lt;/a&gt; on September 04, 2014.&lt;/p&gt;</content>
</entry>

</feed>
