<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>IndexOutOfRange</title>
    <description>Architecture, .NET, performance, and everything I stumble upon while writing coding.</description>
    <link>https://IndexOutOfRange.com</link>
    <atom:link href="https://IndexOutOfRange.com/feed.xml" rel="self" type="application/rss+xml" />
    
      <item>
        <title>MongoDB vs RavenDB</title>
        <description>&lt;img src='https://indexoutofrange.com/data/2019-12-01-RavenDBvsMongoDB/logo.png' /&gt;&lt;p&gt;I need a document database. Why? There are areas in my problem generating (&lt;a href=&quot;/How-to-calculate-17-billion-similarities/&quot;&gt;How to calculate 17 billion similarities&lt;/a&gt;) pet &lt;a href=&quot;/The-importance-of-running-on-crapp/&quot;&gt;project cookit&lt;/a&gt; that are just asking for a document modelling approach.&lt;/p&gt;

&lt;p&gt;Most people will say that this is a straightforward problem to solve:&lt;/p&gt;

&lt;div class=&quot;center&quot;&gt;
 &lt;div class=&quot;button&quot;&gt;Slap on MongoDB, and you are ready to go. &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;It is NOT a good idea.&lt;/p&gt;

&lt;!--MORE--&gt;

&lt;!-- Begin MailChimp Signup Form --&gt;

&lt;link href=&quot;//cdn-images.mailchimp.com/embedcode/horizontal-slim-10_7.css&quot; rel=&quot;stylesheet&quot; type=&quot;text/css&quot; /&gt;

&lt;style type=&quot;text/css&quot;&gt;
	#mc_embed_signup{
        clear:left; 
        font:14px Helvetica,Arial,sans-serif; 
        width:100%; 
        margin-top: 40px;
        margin-bottom: 40px;
        height:100px;
    }
    #mc_embed_signup .newsletter div{
        height: 100px;
    }
    #mc_embed_signup form{
        position: relative;
        top: -90px;
    }
	/* Add your own MailChimp form style overrides in your site stylesheet or in this style block.
	   We recommend moving this block and the preceding CSS link to the HEAD of your HTML file. */
&lt;/style&gt;

&lt;div id=&quot;mc_embed_signup&quot;&gt;
    &lt;div class=&quot;gradient newsletter&quot;&gt;
        &lt;div style=&quot;background:#000000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#1C0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#380000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#550000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#710000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#8D0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#AA0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#C60000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#E20000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF3800&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF5500&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF7100&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF8D00&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFAA00&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFC600&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFE200&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFFF00&quot;&gt;&lt;/div&gt;
    &lt;/div&gt;
    &lt;form action=&quot;https://IndexOutOfRange.us15.list-manage.com/subscribe/post?u=b1c1099bf7f49b95c64107c99&amp;amp;id=6a5eb68eb7&quot; method=&quot;post&quot; id=&quot;mc-embedded-subscribe-form&quot; name=&quot;mc-embedded-subscribe-form&quot; class=&quot;validate&quot; target=&quot;_blank&quot; novalidate=&quot;&quot;&gt;
        &lt;div id=&quot;mc_embed_signup_scroll&quot;&gt;
        &lt;label for=&quot;mce-EMAIL&quot; style=&quot;color: white;&quot;&gt;Get email notifications about new posts:&lt;/label&gt;
        &lt;input type=&quot;email&quot; value=&quot;&quot; name=&quot;EMAIL&quot; class=&quot;email&quot; id=&quot;mce-EMAIL&quot; placeholder=&quot;email address&quot; required=&quot;&quot; /&gt;
        &lt;!-- real people should not fill this in and expect good things - do not remove this or risk form bot signups--&gt;
        &lt;div style=&quot;position: absolute; left: -5000px;&quot; aria-hidden=&quot;true&quot;&gt;&lt;input type=&quot;text&quot; name=&quot;b_b1c1099bf7f49b95c64107c99_6a5eb68eb7&quot; tabindex=&quot;-1&quot; value=&quot;&quot; /&gt;&lt;/div&gt;
        &lt;div class=&quot;clear&quot;&gt;&lt;input type=&quot;submit&quot; value=&quot;Subscribe&quot; name=&quot;subscribe&quot; id=&quot;mc-embedded-subscribe&quot; class=&quot;button&quot; /&gt;&lt;/div&gt;
        &lt;/div&gt;
    &lt;/form&gt;
&lt;/div&gt;

&lt;!--End mc_embed_signup--&gt;

&lt;h1 id=&quot;tltr&quot;&gt;TLTR&lt;/h1&gt;

&lt;p&gt;This article started as a way to structurize the comparison process but grew a bit more ( just like my &lt;a href=&quot;/Choosing-centralized-logging-and-monitoring-system/&quot;&gt;previous comparison&lt;/a&gt;). Here is a table of content to give you an overview and make it easier to see the sections:&lt;/p&gt;

&lt;h1 id=&quot;table-of-content&quot;&gt;Table of content:&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;#why-slapping-on-mongodb-isn-t-the-right-idea-&quot;&gt;Why slapping on MongoDB isn’t the right idea?&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#if-not-mongodb-than-what-&quot;&gt;If not MongoDB than what?&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#mongodb-vs-ravendb---fast-comparison&quot;&gt;MongoDB vs. RavenDB - Fast comparison&lt;/a&gt;
    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#docker-image-size&quot;&gt;Docker image size&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#free-on-premise-tier&quot;&gt;Free on-premise tier&lt;/a&gt;
    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#what-is-missing-from-the-free-version-when-compared-to-the-paid-one-&quot;&gt;What is missing from the free version when compared to the paid one?&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#paid-vs-free-comparison&quot;&gt;Paid vs. free comparison.&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#what-features-ravendb-limits-in-the-free-version-&quot;&gt;What features RavenDB limits in the free version?&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#what-mongodb-limits-in-the-free-version-&quot;&gt;What MongoDB limits in the free version?&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#cloud-offerings&quot;&gt;Cloud offerings&lt;/a&gt;
    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#backups&quot;&gt;Backups&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#cloud-offering-conclusion&quot;&gt;Cloud offering Conclusion&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#clustering-model&quot;&gt;Clustering model&lt;/a&gt;
    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#clustering-goals&quot;&gt;Clustering goals&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#mongodb-vs-ravendb-clustering&quot;&gt;MongoDB vs. RavenDB clustering&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#mongodb&quot;&gt;MongoDB&lt;/a&gt;
        &lt;ul&gt;
          &lt;li&gt;&lt;a href=&quot;#mongodb-replication&quot;&gt;MongoDB replication&lt;/a&gt;&lt;/li&gt;
          &lt;li&gt;&lt;a href=&quot;#mongodb-horizontal-scaling&quot;&gt;MongoDB horizontal scaling&lt;/a&gt;
            &lt;ul&gt;
              &lt;li&gt;&lt;a href=&quot;#how-does-it-work-from-the-client-s-perspective-&quot;&gt;How does it work from the client’s perspective?&lt;/a&gt;&lt;/li&gt;
            &lt;/ul&gt;
          &lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#ravendb-clustering&quot;&gt;RavenDB clustering&lt;/a&gt;
        &lt;ul&gt;
          &lt;li&gt;&lt;a href=&quot;#ravendb-replication&quot;&gt;RavenDB replication&lt;/a&gt;&lt;/li&gt;
          &lt;li&gt;&lt;a href=&quot;#ravendb-horizontal-scaling&quot;&gt;RavenDB horizontal scaling&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#clustering-conclusion&quot;&gt;Clustering conclusion&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#multi-document-transactions&quot;&gt;Multi-document transactions&lt;/a&gt;
    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#what-are-multi-document-transactions-&quot;&gt;What are multi-document transactions?&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#mongodb-vs-ravendb&quot;&gt;MongoDB vs. RavenDB&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#query-language&quot;&gt;Query Language&lt;/a&gt;
    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#mongodb-querying-language&quot;&gt;MongoDB querying language&lt;/a&gt;
        &lt;ul&gt;
          &lt;li&gt;&lt;a href=&quot;#ravendb-query-language&quot;&gt;RavenDB query language&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#direct-comparison&quot;&gt;Direct comparison&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#query-language-conclusion&quot;&gt;Query language conclusion&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#indexing&quot;&gt;Indexing&lt;/a&gt;
    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#why-is-indexing-vital-in-document-databases-&quot;&gt;Why is indexing vital in document databases?&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#ravendb-vs-mongodb-indexes&quot;&gt;RavenDB vs. MongoDB indexes&lt;/a&gt;
        &lt;ul&gt;
          &lt;li&gt;&lt;a href=&quot;#mongodb-indexes&quot;&gt;MongoDB indexes&lt;/a&gt;&lt;/li&gt;
          &lt;li&gt;&lt;a href=&quot;#ravendb-indexes&quot;&gt;RavenDB indexes&lt;/a&gt;
            &lt;ul&gt;
              &lt;li&gt;&lt;a href=&quot;#auto-indexes&quot;&gt;Auto indexes&lt;/a&gt;&lt;/li&gt;
            &lt;/ul&gt;
          &lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#indexing-comparison&quot;&gt;Indexing comparison&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#summary&quot;&gt;Summary&lt;/a&gt;
    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#mongodb-1&quot;&gt;MongoDB&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#ravendb&quot;&gt;RavenDB&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#so--what-will-it-be-&quot;&gt;So, what will it be?&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;why-slapping-on-mongodb-isnt-the-right-idea&quot;&gt;Why slapping on MongoDB isn’t the right idea?&lt;/h1&gt;

&lt;ol&gt;
  &lt;li&gt;Slapping on any piece of technology into a system is &lt;strong&gt;fundamentally a bad idea&lt;/strong&gt;. No matter where You read/heard/saw a recommendation of a product, always consider the &lt;strong&gt;context&lt;/strong&gt; of the problem and the recommended solution.
You can read about my context &lt;a href=&quot;/How-is-cookit-build/&quot;&gt;here&lt;/a&gt;, &lt;a href=&quot;/The-importance-of-running-on-crapp/&quot;&gt;here&lt;/a&gt; and &lt;a href=&quot;/How-to-calculate-17-billion-similarities/&quot;&gt;here where I try to calculate 17 billion similarities&lt;/a&gt;
I need a document database for storing denormalized entries that will:
    &lt;ul&gt;
      &lt;li&gt;Handle a versatile load - background calculations are very computation heavy&lt;/li&gt;
      &lt;li&gt;Have a reasonable learning curve - I want to concentrate on delivering value, not get stuck in the docs for the first week&lt;/li&gt;
      &lt;li&gt;Will just work - the less my time it needs, the better&lt;/li&gt;
      &lt;li&gt;Not bite me in the least expected moment&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;I worked with MongoDB in the past (not my choice, it was already there), and that wasn’t a pleasant ride. To give some examples of problems we had:
    &lt;ul&gt;
      &lt;li&gt;&lt;strong&gt;Querry times&lt;/strong&gt; for the same query with different parameters (“Steve” was OK, but “Garry” wasn’t) varied by a factor of 100. Up to above 20 seconds on a database that was less than 2GB in size.&lt;/li&gt;
      &lt;li&gt;Using &lt;a href=&quot;https://robomongo.org&quot;&gt;&lt;strong&gt;Robo 3T&lt;/strong&gt;&lt;/a&gt; as the default database browser felt like being transported into the year 2000. It was slow, clunky, and tended to crash.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;MongoDB lacked multi-document transactions&lt;/strong&gt;. When I used MongoDB, it just announced the support for multi-document transactions. With that said, it wasn’t encouraged because of significant performance penalties.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The lack of multi-document transactionality didn’t seem like a big deal at the start. But after some time, we saw that we were writing more and more code to handle the second, or next, document update fail. In hindsight, this was to expected because:&lt;/p&gt;

&lt;div class=&quot;center&quot;&gt;
 &lt;div class=&quot;button&quot;&gt;&lt;b&gt;You can't remove complexity from a system. You can only move it around.&lt;/b&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;blockquote&gt;
  &lt;p&gt;Now MongoDB supports the option to enable multi-document transactions, but it &lt;a href=&quot;https://docs.mongodb.com/manual/core/transactions/&quot;&gt;has significant performance degradation implications&lt;/a&gt;).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;Google also reached the same conclusion. When the database doesn’t have multi-document transactions, people will put this logic into the application code. A company that started the NoSQL movement is not using a relational database - Spanner. &lt;strong&gt;Having proper transaction support is cheaper in the long run.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To sum up the problems:
My last interaction with MongoDB was about two years ago, so not all of them might still be valid. But just checking if they are present without having something to compare it to is a waste of time. Technology doesn’t stand still, and new ideas are turned into products all the time.&lt;/p&gt;

&lt;h1 id=&quot;if-not-mongodb-than-what&quot;&gt;If not MongoDB than what?&lt;/h1&gt;

&lt;p&gt;The title of the post gave it away a bit, but my contender is &lt;strong&gt;RavenDB&lt;/strong&gt;.&lt;/p&gt;

&lt;div class=&quot;center&quot;&gt;
 &lt;div class=&quot;button&quot;&gt;&lt;img src=&quot;/data/2019-12-01-RavenDBvsMongoDB/saywhat.gif&quot; /&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;A valid question here might be &lt;em&gt;why am I considering Raven when there are other more popular document databases on the market?&lt;/em&gt; A few reasons:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;The main man behind Raven is Ayende. Also known as Oren Eini, but I am betting the more people will recognize the first “name” or from his &lt;a href=&quot;https://ayende.com/blog/&quot;&gt;blog&lt;/a&gt; (he has been publishing a post a day since 2004!). Why is this important? He has a track record of collaborating and creating very well thought out, performance-orientated projects that still are one of the best in .NET ecosystem.&lt;/li&gt;
  &lt;li&gt;A by-product of reading Ayende’s blog is the insight into RavenDB development process over the years. What were the critical design decisions and how they matured over time. To point a few:
    &lt;ul&gt;
      &lt;li&gt;Sticking to &lt;a href=&quot;https://ayende.com/blog/164066/ravendb-acid-base&quot;&gt;multi-document transactions from the start&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;The effort put into making the database require as little Ops as possible with things like &lt;a href=&quot;https://ravendb.net/docs/article-page/4.1/csharp/indexes/creating-and-deploying#auto-indexes&quot;&gt;automatically creating indexes based on database usage&lt;/a&gt;.&lt;/li&gt;
      &lt;li&gt;Running on &lt;a href=&quot;https://ayende.com/blog/188481-A/running-ravendb-with-low-memory&quot;&gt;extremely limited hardware (Raspberry Pi level of limitations)&lt;/a&gt; as a test process.&lt;/li&gt;
      &lt;li&gt;Very early development of clustering features in the database.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;I always wanted to check it out. But for a long time, it never had a free tier, and my curiosity didn’t justify the expense.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So, let’s compare those two.&lt;/p&gt;

&lt;h1 id=&quot;mongodb-vs-ravendb---fast-comparison&quot;&gt;MongoDB vs. RavenDB - Fast comparison&lt;/h1&gt;

&lt;p&gt;When looking from a very far distance, those two databases might look very similar. Both are document databases that accept JSON, offer transactions, have indexing options, and scale horizontally. 
Moving a bit closer shows, in many cases, the opposite approach to those areas in both databases.
First, let’s take a very high-level overview of capabilities:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;Feature&lt;/th&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;MongoDB&lt;/th&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;RavenDB&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;OS&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Windows &lt;br /&gt; Linux&lt;br /&gt; Mac OS &lt;br /&gt; Solaris&lt;br /&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Windows &lt;br /&gt; Linux &lt;br /&gt; Mac OS &lt;br /&gt; Raspberry Pi&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Official Docker Image&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;a href=&quot;https://hub.docker.com/_/mongo&quot;&gt;Linux and Windows-based&lt;/a&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;a href=&quot;https://hub.docker.com/r/ravendb/ravendb/&quot;&gt;Linux and Windows-based&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Schema&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;No, but there is schema validation*1&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;No&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Support for types&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;a href=&quot;https://docs.mongodb.com/manual/reference/operator/query/type/&quot;&gt;Partly&lt;/a&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;a href=&quot;https://ravendb.net/docs/article-page/4.1/csharp/server/kb/numbers-in-ravendb&quot;&gt;Partly&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Querry language&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;custom, more &lt;a href=&quot;https://docs.mongodb.com/manual/reference/sql-comparison/&quot;&gt;map-reduce like syntax&lt;/a&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;SQL like &lt;a href=&quot;https://ravendb.net/docs/article-page/4.2/csharp/indexes/querying/what-is-rql&quot;&gt;RQL&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Monitoring&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;a href=&quot;https://docs.mongodb.com/manual/administration/monitoring/&quot;&gt;Free console tools &lt;br /&gt; or paid OpsManager&lt;/a&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;a href=&quot;https://ravendb.net/docs/article-page/4.2/csharp/server/administration/statistics&quot;&gt;free HTTP endpoint&lt;/a&gt; &lt;br /&gt; free &lt;a href=&quot;https://ravendb.net/docs/article-page/4.2/csharp/studio/server/server-dashboard&quot;&gt;UI (Studio Manager)&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;SNMP support&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;a href=&quot;https://docs.mongodb.com/manual/tutorial/monitor-with-snmp/&quot;&gt;In the paid version&lt;/a&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;a href=&quot;https://ravendb.net/buy&quot;&gt;In the paid version&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Clustering model&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;a href=&quot;https://docs.mongodb.com/manual/replication/&quot;&gt;Primary-secondary version with Replica Sets or sharding&lt;/a&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;a href=&quot;https://ravendb.net/docs/article-page/4.1/csharp/client-api/cluster/how-client-integrates-with-replication-and-cluster&quot;&gt;Multi-primary&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt; &lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt; &lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt; &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt; &lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;Indexes&lt;/strong&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt; &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Primary indexes&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;a href=&quot;https://docs.mongodb.com/manual/indexes/#default-id-index&quot;&gt;Yes&lt;/a&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Yes&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Secondary indexes&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Yes&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Yes&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Auto indexes&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;No*2&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;a href=&quot;https://docs.mongodb.com/manual/indexes/#default-id-index&quot;&gt;Yes&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Multiple fields in one index&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;a href=&quot;https://docs.mongodb.com/manual/indexes/#default-id-index&quot;&gt;Yes (Compound Index)&lt;/a&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;a href=&quot;https://ravendb.net/docs/article-page/4.1/csharp/indexes/map-indexes&quot;&gt;Yes (Map indexes)&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Multi-collection indexes&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;a href=&quot;https://docs.mongodb.com/manual/applications/indexes/&quot;&gt;No&lt;/a&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;a href=&quot;https://ravendb.net/docs/article-page/4.2/csharp/indexes/multi-map-indexes&quot;&gt;Yes&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Spatial indexes&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;a href=&quot;https://docs.mongodb.com/manual/geospatial-queries/#geospatial-indexes&quot;&gt;Yes&lt;/a&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;a href=&quot;https://ravendb.net/docs/article-page/4.2/csharp/indexes/indexing-spatial-data&quot;&gt;Yes&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Hierarchical indexes&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;No&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;a href=&quot;https://ravendb.net/docs/article-page/4.2/csharp/indexes/indexing-hierarchical-data&quot;&gt;Yes&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt; &lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt; &lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt; &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt; &lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;Cloud offering&lt;/strong&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt; &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Fully managed?&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Yes&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Yes&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Clouds supported&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;a href=&quot;https://www.mongodb.com/cloud/atlas&quot;&gt;AWS&lt;br /&gt;Azure&lt;br /&gt;GCP&lt;br /&gt;&lt;/a&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;a href=&quot;https://cloud.ravendb.net/pricing&quot;&gt;AWS&lt;br /&gt;Azure&lt;br /&gt;&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Consumption plan available&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;No&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;No&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;By hour payment?&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Yes&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Yes&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Sample price for an hour&lt;br /&gt; (AWS, N. Virginia, 3 nodes, &lt;br /&gt;4 GB of RAM, 20GB storage, 2vCPU)&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;$0.20&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;$0.216 yearly upfront&lt;br /&gt; $0.227 yearly no up-front &lt;br /&gt; $0.239 on demand&lt;br /&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Backups&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;a href=&quot;https://www.mongodb.com/cloud/atlas/pricing&quot;&gt;First 1 GB is free&lt;br /&gt;$2.50 per GB/month for the rest&lt;/a&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;a href=&quot;https://cloud.ravendb.net/pricing&quot;&gt;First 1GB is free&lt;br /&gt;$1.00 per GB/month for the rest&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Backups retention policy&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;a href=&quot;https://docs.atlas.mongodb.com/backup/continuous-backups/&quot;&gt;1 day&lt;/a&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;a href=&quot;https://docs.atlas.mongodb.com/backup/continuous-backups/&quot;&gt;14 days&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt; &lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt; &lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt; &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt; &lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;Free tier&lt;/strong&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt; &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Free on-premise&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;a href=&quot;https://www.mongodb.com/products/mongodb-enterprise-advanced&quot;&gt;Yes&lt;/a&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;a href=&quot;https://ravendb.net/buy&quot;&gt;Yes&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt; &lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;Free Cloud offering&lt;/strong&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt; &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Storage&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;a href=&quot;https://www.mongodb.com/cloud/atlas&quot;&gt;0.5 GB&lt;/a&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;a href=&quot;https://cloud.ravendb.net/pricing&quot;&gt;10 GB&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Memory&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;a href=&quot;https://www.mongodb.com/cloud/atlas&quot;&gt;Shared RAM&lt;/a&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;a href=&quot;https://cloud.ravendb.net/pricing&quot;&gt;512 MB&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;CPU&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;no info&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;a href=&quot;https://cloud.ravendb.net/pricing&quot;&gt;2 vCPU&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;&lt;strong&gt;Legend:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;*1&lt;/strong&gt; - MongoDB, from version 3.2 has introduced &lt;a href=&quot;https://docs.mongodb.com/manual/core/schema-validation/&quot;&gt;schema validation&lt;/a&gt; that allows for some schema verification to be made but doesn’t address the performance implications of lack of a schema.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;*2&lt;/strong&gt; - &lt;a href=&quot;https://www.mongodb.com/blog/post/improving-mongodb-performance-with-automatically-generated-index-suggestions&quot;&gt;it can be done with Mongo Atlas&lt;/a&gt; but isn’t available in the free version and doesn’t work out of the box.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;docker-image-size&quot;&gt;Docker image size&lt;/h2&gt;

&lt;p&gt;This one is a bit neet peaky, but hear me out. I tend to look at the size of the Docker images. You can call me picky, but having a small Docker image affects a few things:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;It makes continuous deployment faster and simpler&lt;/li&gt;
  &lt;li&gt;Smaller containers start faster&lt;/li&gt;
  &lt;li&gt;My well being. I know that creating a small image requires some effort. This is why a smaller image feels a bit more polished.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What makes this more interesting is that both databases have Windows container images for Docker (yes, those are a thing). The sizes:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt; &lt;/th&gt;
      &lt;th&gt;Windows&lt;/th&gt;
      &lt;th&gt;Linux&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;MongoDB&lt;/td&gt;
      &lt;td&gt;6.07GB &lt;br /&gt;(&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mongo:4.2.0-windowsservercore&lt;/code&gt;)&lt;/td&gt;
      &lt;td&gt;139.96 MB &lt;br /&gt;(&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mongo:4.2.0&lt;/code&gt;)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;RavenDB&lt;/td&gt;
      &lt;td&gt;1.48GB &lt;br /&gt;(&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ravendb/ravendb:4.2.4-patch-42020-windows-nanoserver&lt;/code&gt;)&lt;/td&gt;
      &lt;td&gt;177.23 MB &lt;br /&gt;(&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ravendb/ravendb:4.1.9-patch-41022-ubuntu.18.04-x64&lt;/code&gt;)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Difference&lt;/td&gt;
      &lt;td&gt;MongoDB image is 4.59GB larger&lt;/td&gt;
      &lt;td&gt;RavenDB is 37,27 MB larger&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;The Linux base image size difference is negligible, but the Windows size difference is huge. Why this size difference exists? Different base images. MongoDB uses the Windows &lt;strong&gt;Core&lt;/strong&gt; base image. RavenDB uses Windows &lt;strong&gt;Nano&lt;/strong&gt;, which is a stripped version of Windows (Microsoft is aiming for it to be below 400MB). I know Windows Docker images aren’t on the hype train, and probably will never be. But in some cases, they are the only option, and I hoped that the official image would be better.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;After some additional digging, MongoDB looked into running on Windows Nano, but they are waiting on &lt;a href=&quot;https://github.com/docker-library/official-images/issues/3383&quot;&gt;multi-stage build support for Windows images&lt;/a&gt;. It is a valid argument, but multi-stage builds are &lt;a href=&quot;https://docs.docker.com/develop/develop-images/multistage-build/&quot;&gt;available only from version 17.05 of Docker for Linux images&lt;/a&gt;, and we used Docker before and managed to bypass this limitation :(&lt;/p&gt;
&lt;/blockquote&gt;

&lt;!-- Begin MailChimp Signup Form --&gt;

&lt;link href=&quot;//cdn-images.mailchimp.com/embedcode/horizontal-slim-10_7.css&quot; rel=&quot;stylesheet&quot; type=&quot;text/css&quot; /&gt;

&lt;style type=&quot;text/css&quot;&gt;
	#mc_embed_signup{
        clear:left; 
        font:14px Helvetica,Arial,sans-serif; 
        width:100%; 
        margin-top: 40px;
        margin-bottom: 40px;
        height:100px;
    }
    #mc_embed_signup .newsletter div{
        height: 100px;
    }
    #mc_embed_signup form{
        position: relative;
        top: -90px;
    }
	/* Add your own MailChimp form style overrides in your site stylesheet or in this style block.
	   We recommend moving this block and the preceding CSS link to the HEAD of your HTML file. */
&lt;/style&gt;

&lt;div id=&quot;mc_embed_signup&quot;&gt;
    &lt;div class=&quot;gradient newsletter&quot;&gt;
        &lt;div style=&quot;background:#000000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#1C0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#380000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#550000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#710000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#8D0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#AA0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#C60000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#E20000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF3800&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF5500&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF7100&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF8D00&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFAA00&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFC600&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFE200&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFFF00&quot;&gt;&lt;/div&gt;
    &lt;/div&gt;
    &lt;form action=&quot;https://IndexOutOfRange.us15.list-manage.com/subscribe/post?u=b1c1099bf7f49b95c64107c99&amp;amp;id=6a5eb68eb7&quot; method=&quot;post&quot; id=&quot;mc-embedded-subscribe-form&quot; name=&quot;mc-embedded-subscribe-form&quot; class=&quot;validate&quot; target=&quot;_blank&quot; novalidate=&quot;&quot;&gt;
        &lt;div id=&quot;mc_embed_signup_scroll&quot;&gt;
        &lt;label for=&quot;mce-EMAIL&quot; style=&quot;color: white;&quot;&gt;Get email notifications about new posts:&lt;/label&gt;
        &lt;input type=&quot;email&quot; value=&quot;&quot; name=&quot;EMAIL&quot; class=&quot;email&quot; id=&quot;mce-EMAIL&quot; placeholder=&quot;email address&quot; required=&quot;&quot; /&gt;
        &lt;!-- real people should not fill this in and expect good things - do not remove this or risk form bot signups--&gt;
        &lt;div style=&quot;position: absolute; left: -5000px;&quot; aria-hidden=&quot;true&quot;&gt;&lt;input type=&quot;text&quot; name=&quot;b_b1c1099bf7f49b95c64107c99_6a5eb68eb7&quot; tabindex=&quot;-1&quot; value=&quot;&quot; /&gt;&lt;/div&gt;
        &lt;div class=&quot;clear&quot;&gt;&lt;input type=&quot;submit&quot; value=&quot;Subscribe&quot; name=&quot;subscribe&quot; id=&quot;mc-embedded-subscribe&quot; class=&quot;button&quot; /&gt;&lt;/div&gt;
        &lt;/div&gt;
    &lt;/form&gt;
&lt;/div&gt;

&lt;!--End mc_embed_signup--&gt;

&lt;h1 id=&quot;free-on-premise-tier&quot;&gt;Free on-premise tier&lt;/h1&gt;

&lt;p&gt;Another area that requires a more in-depth look is the free tier offering. RavenDB, for a long time, discarded the need for a free tier in their product. MongoDB started as a free database and added a paid enterprise version later on.&lt;/p&gt;

&lt;p&gt;RavenDB free version comes with [some limitations]((https://ravendb.net/buy):&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;max cluster size: 3&lt;/li&gt;
  &lt;li&gt;max cores in a cluster: 3&lt;/li&gt;
  &lt;li&gt;max cluster memory usage: 6GB&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those limits are a bit of a pain, especially since MongoDB doesn’t have restrictions on the free tier. While I wish those weren’t there, I understand why they are present.&lt;/p&gt;

&lt;p&gt;But, the limits aren’t the only thing that is different between the free versions. There is also what is left out between paid and free for both databases.&lt;/p&gt;

&lt;h3 id=&quot;what-is-missing-from-the-free-version-when-compared-to-the-paid-one&quot;&gt;What is missing from the free version when compared to the paid one?&lt;/h3&gt;

&lt;p&gt;The main reason why all free databases have a paid version is to offer support and different licensing options for enterprise users. Both databases moved some features to the enterprise tier:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Encryption at the storage level&lt;/li&gt;
  &lt;li&gt;Snapshot backups&lt;/li&gt;
  &lt;li&gt;SNMP (&lt;strong&gt;S&lt;/strong&gt;imple &lt;strong&gt;N&lt;/strong&gt;etwork &lt;strong&gt;M&lt;/strong&gt;anagement &lt;strong&gt;P&lt;/strong&gt;rotocol) support&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If I could have one option moved to free, that would be storage level encryption. It could save us from a few data leaks.
Now for the differences in missing features.&lt;/p&gt;

&lt;h3 id=&quot;paid-vs-free-comparison&quot;&gt;Paid vs. free comparison.&lt;/h3&gt;

&lt;h3 id=&quot;what-features-ravendb-limits-in-the-free-version&quot;&gt;What features RavenDB limits in the free version?&lt;/h3&gt;
&lt;p&gt;First of all, RavenDB has &lt;a href=&quot;https://ravendb.net/buy&quot;&gt;an excellent page comparing the versions&lt;/a&gt;&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;Area&lt;/th&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;Feature name&lt;/th&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;What it is?&lt;/th&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;Does it have a MongoDB counterpart?&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Replication&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;a href=&quot;https://ravendb.net/docs/article-page/4.2/csharp/studio/database/tasks/ongoing-tasks/pull-replication&quot;&gt;Pull Replication&lt;/a&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;This feature could use a better explanation in the documentation, but &lt;a href=&quot;https://ayende.com/blog/185153-C/ravendb-4-2-features-pull-replication-edge-processing&quot;&gt;Ayendes blog to the rescue&lt;/a&gt;. This is a very interesting feature for synchronizing databases/database clusters that are separated or don’t have a permanent connection. &lt;br /&gt;RavenDB - please make this more readable and easier to understand.&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;No counterpart on MongoDB side&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Replication&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;a href=&quot;https://ravendb.net/docs/article-page/4.2/csharp/studio/database/tasks/ongoing-tasks/external-replication-task&quot;&gt;External replication&lt;/a&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;The ability to replicate the database outside of the cluster. Useful for backup and recovery scenarios.&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;No counterpart on MongoDB side&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Clustering&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Dynamic database distribution across the cluster&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;As I said earlier, RavenDB puts a lot of effort into creating a no-Ops system. And this feature is an excellent example. When one of the nodes in the RavenDB cluster goes down, the cluster manager can distribute the remaining databases to keep a proper number of replicas.&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;No counterpart on MongoDB side&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;h3 id=&quot;what-mongodb-limits-in-the-free-version&quot;&gt;What MongoDB limits in the free version?&lt;/h3&gt;

&lt;p&gt;The most important missing features when comparing free MongoDB to its paid version (called &lt;a href=&quot;https://www.mongodb.com/products/mongodb-enterprise-advanced&quot;&gt;MongoDB Enterprise Advanced&lt;/a&gt;) are:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;Area&lt;/th&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;Feature name&lt;/th&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;What it is?&lt;/th&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;Does it have a RavenDB counterpart?&lt;/th&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;Comment&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Ops&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;a href=&quot;https://www.mongodb.com/products/ops-manager&quot;&gt;OpsManger&lt;/a&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;A all-in-one tool for monitoring and managing MongoDB.&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;For:&lt;br /&gt;- metrics RavenDB has a &lt;a href=&quot;https://ravendb.net/docs/article-page/4.2/csharp/server/administration/statistics&quot;&gt;metrics HTTP endpoint&lt;/a&gt; exposed by the database itself. &lt;br /&gt; - for visual management, RavenDB has &lt;a href=&quot;https://ravendb.net/features/management-studio-gui&quot;&gt;Management Studio&lt;/a&gt;.&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt; &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Performance&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;a href=&quot;https://docs.mongodb.com/manual/core/inmemory/index.html&quot;&gt;&lt;strong&gt;In-memory storage engine&lt;/strong&gt;&lt;/a&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;A &lt;strong&gt;in-memory only&lt;/strong&gt; storage. &lt;strong&gt;Without any persistence.&lt;/strong&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;RavenDB has &lt;a href=&quot;https://ravendb.net/docs/article-page/4.2/Csharp/server/configuration/core-configuration#runinmemory&quot;&gt;RunInMemory option&lt;/a&gt;.&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;My first thought was that it would work like &lt;br /&gt;&lt;a href=&quot;https://docs.microsoft.com/en-us/sql/relational-databases/in-memory-database?view=sql-server-ver15&quot;&gt;SQL Server In-Memory Database&lt;/a&gt; which would be a killer feature.&lt;br /&gt; Without persistence, I don’t see this option as a very useful one.&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Visualization&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;a href=&quot;https://www.mongodb.com/products/compass&quot;&gt;Compas&lt;/a&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Kibana-like system for MongoDB&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;RavenDB has it’s &lt;a href=&quot;https://ravendb.net/features/management-studio-gui&quot;&gt; Management Studio&lt;/a&gt; which also offers data visualization options, but I didn’t make a direct comparison.&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt; &lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;h1 id=&quot;cloud-offerings&quot;&gt;Cloud offerings&lt;/h1&gt;

&lt;p&gt;Both companies offer a very similar model for providing managed cloud services: Select the cloud provider and virtual machine types, and they take care of the rest.
While RavenDB has a very simple configurator, MongoDB Atlas has significantly more knobs and switches.
I tried to do my best in doing an apples to apples comparison and here is what I came up with:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;Configuration&lt;/th&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;MongoDB cost&lt;/th&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;RavenDB cost&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Provider: AWS&lt;br /&gt;Region: N. Virginia&lt;br /&gt;Number of nodes: 3&lt;br /&gt; RAM: 4 GB&lt;br /&gt;Storage 20GB&lt;br /&gt;CPU: 2vCPU&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;$0.20/h&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;$0.239/h on demand&lt;br /&gt;$0.227/h yearly no up-front&lt;br /&gt;$0.216/h yearly upfront&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt; &lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt; &lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt; &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Provider: AWS&lt;br /&gt;Region: N. Virginia&lt;br /&gt;Number of nodes: 3&lt;br /&gt; RAM: 16 GB&lt;br /&gt;Storage 1000GB&lt;br /&gt;CPU: 4vCPU&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;$1.09/h&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;$1.109/h on demand&lt;br /&gt;$1.056/h yearly no up-front&lt;br /&gt;$1.003/h yearly upfront&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;blockquote&gt;
  &lt;p&gt;Take into account that this is comparing only the hardware, not the performance you get for your money.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;backups&quot;&gt;Backups&lt;/h2&gt;

&lt;p&gt;Why go deep into backups? Read and see. Both services offer the same pricing strategy:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;the first 1GB is free&lt;/li&gt;
  &lt;li&gt;anything above that is charged per gigabyte a month.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;p&gt;MongoDB also offers &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Cloud Provider Snapshots&lt;/code&gt; but since it doesn’t &lt;a href=&quot;https://docs.atlas.mongodb.com/backup/cloud-provider-snapshots/&quot;&gt;guarantee consistency of the backup&lt;/a&gt; (what is the point in having backups if we don’t know if make sense?) I’m excluding them.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;RavenDB&lt;/strong&gt; is very clear how backups work. And they &lt;a href=&quot;https://ravendb.net/docs/article-page/4.2/csharp/cloud/cloud-backup-and-restore#the-mandatory-backup-routine&quot;&gt;are mandatory&lt;/a&gt; - I like that “we will push You into the pit of success approach”:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;full backups are taken every 24 hours&lt;/li&gt;
  &lt;li&gt;incremental every 30 minutes&lt;/li&gt;
  &lt;li&gt;full backups are kept for 14 days (again this period can be extended, but not reduces - I like that)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With &lt;strong&gt;MongoDB&lt;/strong&gt; Continous Backups the policy is a bit murky. The backups are kept for 24 hours and allow for recovering in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;a selected point in time within the last 24 hours&lt;/code&gt; (citation taken from the &lt;a href=&quot;https://docs.atlas.mongodb.com/backup/continuous-backups/&quot;&gt;docs&lt;/a&gt;). Why is this a murky description? Because it lacks information about the granularity of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;point in time&lt;/code&gt;. Is it a second, minute or 15 minutes?
There is also an option to enable &lt;a href=&quot;https://docs.atlas.mongodb.com/backup/continuous-backups/#snapshot-schedule&quot;&gt;Scheduled Snapshots&lt;/a&gt; that look like a counterpart to what RavenDB is offering with some differences in numbers:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th style=&quot;text-align: left&quot;&gt; &lt;/th&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;MongoDB&lt;/th&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;RavenDB&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Minimum available granularity&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;1 hour&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;30 minutes&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Minimum retention period&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;a href=&quot;https://docs.atlas.mongodb.com/backup/continuous-backups/#snapshot-schedule&quot;&gt;2 days&lt;/a&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;14 days&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Maximum retention period&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;a href=&quot;https://docs.atlas.mongodb.com/backup/continuous-backups/#snapshot-schedule&quot;&gt;5 days, or 30 if they are taken every 24 hours&lt;/a&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;a href=&quot;https://ravendb.net/docs/article-page/4.2/csharp/cloud/cloud-backup-and-restore#the-mandatory-backup-routine&quot;&gt;No limit&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Price for GB/month&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;1.5- 2.5$&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;1$&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;&lt;strong&gt;That is a 1.5$ a GB/month difference&lt;/strong&gt;. A difference in something that will be a significant part of the overall cost of the service. Why do I have such a big issue with this?&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;I don’t see any technical reason for such a big difference.&lt;/li&gt;
  &lt;li&gt;It is pointing users into a straightforward cost-saving measure - have fewer backups. This is the reverse direction we should be pointing users.&lt;/li&gt;
  &lt;li&gt;I see this pricing as a way to look cheaper than the service is.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;cloud-offering-conclusion&quot;&gt;Cloud offering Conclusion&lt;/h2&gt;

&lt;p&gt;In a simple comparison, RavenDB is a bit more expensive. But when we take into account, a proper backup behaviour the total pricing will look differently.
As a side note, I will add that I am very happy with the move of database providers to provide managed instances in a selected cloud. It removes, or at least lowers, the need for the company to gain all operation expertise for the selected database. It makes deployments and company politics significantly simpler.&lt;/p&gt;

&lt;!-- Begin MailChimp Signup Form --&gt;

&lt;link href=&quot;//cdn-images.mailchimp.com/embedcode/horizontal-slim-10_7.css&quot; rel=&quot;stylesheet&quot; type=&quot;text/css&quot; /&gt;

&lt;style type=&quot;text/css&quot;&gt;
	#mc_embed_signup{
        clear:left; 
        font:14px Helvetica,Arial,sans-serif; 
        width:100%; 
        margin-top: 40px;
        margin-bottom: 40px;
        height:100px;
    }
    #mc_embed_signup .newsletter div{
        height: 100px;
    }
    #mc_embed_signup form{
        position: relative;
        top: -90px;
    }
	/* Add your own MailChimp form style overrides in your site stylesheet or in this style block.
	   We recommend moving this block and the preceding CSS link to the HEAD of your HTML file. */
&lt;/style&gt;

&lt;div id=&quot;mc_embed_signup&quot;&gt;
    &lt;div class=&quot;gradient newsletter&quot;&gt;
        &lt;div style=&quot;background:#000000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#1C0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#380000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#550000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#710000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#8D0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#AA0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#C60000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#E20000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF3800&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF5500&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF7100&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF8D00&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFAA00&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFC600&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFE200&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFFF00&quot;&gt;&lt;/div&gt;
    &lt;/div&gt;
    &lt;form action=&quot;https://IndexOutOfRange.us15.list-manage.com/subscribe/post?u=b1c1099bf7f49b95c64107c99&amp;amp;id=6a5eb68eb7&quot; method=&quot;post&quot; id=&quot;mc-embedded-subscribe-form&quot; name=&quot;mc-embedded-subscribe-form&quot; class=&quot;validate&quot; target=&quot;_blank&quot; novalidate=&quot;&quot;&gt;
        &lt;div id=&quot;mc_embed_signup_scroll&quot;&gt;
        &lt;label for=&quot;mce-EMAIL&quot; style=&quot;color: white;&quot;&gt;Get email notifications about new posts:&lt;/label&gt;
        &lt;input type=&quot;email&quot; value=&quot;&quot; name=&quot;EMAIL&quot; class=&quot;email&quot; id=&quot;mce-EMAIL&quot; placeholder=&quot;email address&quot; required=&quot;&quot; /&gt;
        &lt;!-- real people should not fill this in and expect good things - do not remove this or risk form bot signups--&gt;
        &lt;div style=&quot;position: absolute; left: -5000px;&quot; aria-hidden=&quot;true&quot;&gt;&lt;input type=&quot;text&quot; name=&quot;b_b1c1099bf7f49b95c64107c99_6a5eb68eb7&quot; tabindex=&quot;-1&quot; value=&quot;&quot; /&gt;&lt;/div&gt;
        &lt;div class=&quot;clear&quot;&gt;&lt;input type=&quot;submit&quot; value=&quot;Subscribe&quot; name=&quot;subscribe&quot; id=&quot;mc-embedded-subscribe&quot; class=&quot;button&quot; /&gt;&lt;/div&gt;
        &lt;/div&gt;
    &lt;/form&gt;
&lt;/div&gt;

&lt;!--End mc_embed_signup--&gt;

&lt;h1 id=&quot;clustering-model&quot;&gt;Clustering model&lt;/h1&gt;

&lt;h2 id=&quot;clustering-goals&quot;&gt;Clustering goals&lt;/h2&gt;

&lt;p&gt;What is clustering? In short, it is how the database behaves when running on multiple servers.
For a more in-depth explanation, &lt;a href=&quot;https://en.wikipedia.org/wiki/Computer_cluster&quot;&gt;read this here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Before we go into the clustering behaviour lets define the goals we want to accomplish with clustering:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Redundancy&lt;/strong&gt; - Being able to operate and not lose data when a node in a cluster fails.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Horizontal scaling&lt;/strong&gt; - Spread the load on multiple machines.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;mongodb-vs-ravendb-clustering&quot;&gt;MongoDB vs. RavenDB clustering&lt;/h2&gt;

&lt;p&gt;Clustering is where those two databases show the opposite end of the design spectrum.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;MongoDB&lt;/strong&gt; - uses &lt;a href=&quot;https://docs.mongodb.com/v3.4/core/master-slave/&quot;&gt;replica sets (from version 3.4 up)&lt;/a&gt; with &lt;a href=&quot;https://docs.mongodb.com/manual/core/sharded-cluster-components/&quot;&gt;database sharding as a method for horizontal scaling&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;RavenDB&lt;/strong&gt; - is a &lt;a href=&quot;https://ravendb.net/docs/article-page/4.2/csharp/server/clustering/overview&quot;&gt;multi-primary cluster&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Interesting things start when we go deeper.&lt;/p&gt;

&lt;h2 id=&quot;mongodb&quot;&gt;MongoDB&lt;/h2&gt;
&lt;h3 id=&quot;mongodb-replication&quot;&gt;MongoDB replication&lt;/h3&gt;

&lt;p&gt;MongoDB used to operate in a &lt;a href=&quot;https://docs.mongodb.com/v3.4/core/master-slave/&quot;&gt;Primary-secondary configuration until version 3.4&lt;/a&gt;. Now, primary-secondary replication was replaced with replica-sets. 
What is the difference between replica-sets and primary-secondary replication?&lt;/p&gt;

&lt;p&gt;Both modes allow for &lt;strong&gt;only one node&lt;/strong&gt; to accept all operations and, once they are committed &lt;strong&gt;data is replicated to the secondary nodes asynchronously&lt;/strong&gt;. Where the replica sets shine is what happens when the primary node fails. MongoDB replica sets will do an &lt;a href=&quot;https://docs.mongodb.com/manual/replication/#automatic-failover&quot;&gt;automatic failover&lt;/a&gt; with automated primary election from the shard nodes.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/data/2019-12-01-RavenDBvsMongoDB/replica-set-trigger-election.bakedsvg.svg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Image source: MongoDB documentation&lt;/p&gt;

&lt;h3 id=&quot;mongodb-horizontal-scaling&quot;&gt;MongoDB horizontal scaling&lt;/h3&gt;

&lt;p&gt;MongoDB scales horizontally by &lt;a href=&quot;https://docs.mongodb.com/manual/sharding/&quot;&gt;sharding on the database level&lt;/a&gt;.
Sharding is splitting the data into ** non-overlapping** sub data sets (called chunks in MongoDB) and hosting each chunk on a separate machine. For such an operation to work, we have to define a sharding key what will determine the server which will host the document.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/data/2019-12-01-RavenDBvsMongoDB/sharding-range-based.bakedsvg.svg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Sharding can be done in two places:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;by the client&lt;/strong&gt; - the client knows where to put each document.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;by the database&lt;/strong&gt;  - the database is responsible for splitting the data, and it should be transparent to the client.
MongoDB uses the latter approach.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;how-does-it-work-from-the-clients-perspective&quot;&gt;How does it work from the client’s perspective?&lt;/h4&gt;

&lt;p&gt;The client connects to an instance of &lt;a href=&quot;https://docs.mongodb.com/manual/reference/program/mongos/&quot;&gt;mongos&lt;/a&gt; that behaves like a MongoDB database. Mongos is responsible for fetching the shard structure form the &lt;a href=&quot;https://docs.mongodb.com/manual/core/sharded-cluster-config-servers/&quot;&gt;Config Server&lt;/a&gt;, splitting the execution of operations into appropriate servers and combining them at the end.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/data/2019-12-01-RavenDBvsMongoDB/sharded-cluster-scatter-gather-query.bakedsvg.svg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;This makes mongos an abstraction layer. Let’s look at the benefits and drawbacks of it.&lt;/p&gt;

&lt;p&gt;Benefits of database level sharding:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Application agnostic&lt;/strong&gt;  - the client doesn’t know that its queries are shared).&lt;/li&gt;
  &lt;li&gt;Simplifies application code.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Disadvantages of database level sharding:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;If we deploy mongos on the application machine, we will need a beefier application server. Deploying it on a database server that will be used by multiple clients creates a &lt;strong&gt;single point of failure and a performance bottleneck&lt;/strong&gt;.&lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Sharding key definition can’t be changed&lt;/strong&gt;. Migrating to a different sharding key specification (selecting different keys to define how data is shared) is, in most cases, &lt;a href=&quot;https://docs.mongodb.com/manual/core/sharding-shard-key/#shard-key-specification&quot;&gt;not supported&lt;/a&gt;.&lt;/p&gt;

    &lt;blockquote&gt;
      &lt;p&gt;I don’t blame MongoDB for not providing such an option because it is a very compute and network intensive operation that on more massive databases might not be even feasible.&lt;/p&gt;
    &lt;/blockquote&gt;
  &lt;/li&gt;
  &lt;li&gt;Last, but not least. I saw a few approaches to abstracting sharding on the database level, and they never worked. They always leaked. Mostly because of performance.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;ravendb-clustering&quot;&gt;RavenDB clustering&lt;/h2&gt;

&lt;h3 id=&quot;ravendb-replication&quot;&gt;RavenDB replication&lt;/h3&gt;

&lt;p&gt;RavenDB has a very different approach to clustering. RavenDB cluster is a group of self-organizing nodes that maintains consensus using an implementation of the &lt;a href=&quot;https://ravendb.net/docs/article-page/4.1/csharp/server/clustering/rachis/what-is-rachis&quot;&gt;RAFT algorithm&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;What is RAFT and how it works is beyond the scope of this article, but a few things to note:&lt;/p&gt;
  &lt;ul&gt;
    &lt;li&gt;it is the standard for reaching consensus in distributed systems.&lt;/li&gt;
    &lt;li&gt;it addresses the problem of a Single Point of Failure in distributed systems.&lt;/li&gt;
    &lt;li&gt;it has been proven to work.&lt;/li&gt;
  &lt;/ul&gt;

  &lt;p&gt;If You want to know more, an excellent place to start is &lt;a href=&quot;https://raft.github.io/&quot;&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This approach is more complicated, but allows for a few key features:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://ravendb.net/docs/article-page/4.2/csharp/server/clustering/distribution/distributed-database#dynamic-database-distribution&quot;&gt;&lt;strong&gt;Dynamic database distribution&lt;/strong&gt;&lt;/a&gt;. The cluster will rearrange which node is storing which database in case of a cluster node failure, or adding a new node to the cluster.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Variable consensus level.&lt;/strong&gt; By default, the data is assumed as saved when one node accepts it. Then it is replicated to other primary nodes. For special operations, the client can define that he wants to wait for replication to other nodes.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;ravendb-horizontal-scaling&quot;&gt;RavenDB horizontal scaling&lt;/h3&gt;

&lt;p&gt;&lt;a href=&quot;https://ravendb.net/docs/article-page/4.2/csharp/server/clustering/distribution/distributed-database#sharding&quot;&gt;RavenDB doesn’t support database level sharding&lt;/a&gt;. It is on their &lt;a href=&quot;https://issues.hibernatingrhinos.com/issue/RavenDB-8115&quot;&gt;roadmap&lt;/a&gt; and from the design notes, the approach looks very solid. Taking into account that they already have:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;dynamic database distribution&lt;/li&gt;
  &lt;li&gt;RAFT for consensus&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We might get auto partitioning &lt;a href=&quot;https://redis.io/topics/partitioning&quot;&gt;like in Reddis&lt;/a&gt;. How would it be different? We won’t have to define sharding keys, but let the database distribute the data according to load.&lt;/p&gt;

&lt;h2 id=&quot;clustering-conclusion&quot;&gt;Clustering conclusion&lt;/h2&gt;

&lt;p&gt;Before I wrap up this section, let me explain my beef with user-defined sharding (also known as content sharding):&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;data has to be split into &lt;strong&gt;non-overlapping&lt;/strong&gt; datasets which in some cases might &lt;strong&gt;not be possible or very hard&lt;/strong&gt;.&lt;/li&gt;
  &lt;li&gt;Selecting the right sharding key is very hard and requires an in-depth knowledge of the &lt;em&gt;business domain and &lt;strong&gt;future system usage patterns&lt;/strong&gt;&lt;/em&gt;. Because:&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Sharding keys can’t be changed easily&lt;/strong&gt; This applies to MongoDB, Azure CosmosDB and&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Sharding keys should distribute the data evenly across the cluster nodes&lt;/strong&gt;. Otherwise, we end up with a single node that requires vertical scaling (meaning bigger and more expensive machines - the exact thing we wanted to avoid)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Shards have to be monitored.&lt;/strong&gt; What once was a good sharding key can become a bad one over time.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Will RavenDB non-content based sharding be the end-all designs that will fix all of the above? I’m betting no. But it has the potential to solve most of them. Up to this time, I prefer to stay with sharding done by the client.&lt;/p&gt;

&lt;h1 id=&quot;multi-document-transactions&quot;&gt;Multi-document transactions&lt;/h1&gt;

&lt;h2 id=&quot;what-are-multi-document-transactions&quot;&gt;What are multi-document transactions?&lt;/h2&gt;

&lt;p&gt;First, let’s establish what I mean by multi-document transactions. Such a feature has to follow a few rules:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Expose the ability to execute a list of operations (insert, update, delete) on a set of entities.&lt;/li&gt;
  &lt;li&gt;The changes are applied only if &lt;strong&gt;all operations succeed&lt;/strong&gt;. If at least one fails, no changes are applied.&lt;/li&gt;
  &lt;li&gt;Until the transaction is committed, the changes aren’t visible to other operations.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So how RavenDB and MongoDB compare in this area?&lt;/p&gt;

&lt;h2 id=&quot;mongodb-vs-ravendb&quot;&gt;MongoDB vs. RavenDB&lt;/h2&gt;

&lt;p&gt;Both support multi-document transactions, but the road to this feature was different. In RavenDB it was a design decision from the start, with MongoDB it was added in version 3.4 with a proper implementation being available just in 4.2. 
Up to version 4.0, the transaction in MongoDB was limited to the total size of 16 MB. This limitation was removed in version 4.2.&lt;/p&gt;

&lt;!-- Begin MailChimp Signup Form --&gt;

&lt;link href=&quot;//cdn-images.mailchimp.com/embedcode/horizontal-slim-10_7.css&quot; rel=&quot;stylesheet&quot; type=&quot;text/css&quot; /&gt;

&lt;style type=&quot;text/css&quot;&gt;
	#mc_embed_signup{
        clear:left; 
        font:14px Helvetica,Arial,sans-serif; 
        width:100%; 
        margin-top: 40px;
        margin-bottom: 40px;
        height:100px;
    }
    #mc_embed_signup .newsletter div{
        height: 100px;
    }
    #mc_embed_signup form{
        position: relative;
        top: -90px;
    }
	/* Add your own MailChimp form style overrides in your site stylesheet or in this style block.
	   We recommend moving this block and the preceding CSS link to the HEAD of your HTML file. */
&lt;/style&gt;

&lt;div id=&quot;mc_embed_signup&quot;&gt;
    &lt;div class=&quot;gradient newsletter&quot;&gt;
        &lt;div style=&quot;background:#000000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#1C0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#380000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#550000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#710000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#8D0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#AA0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#C60000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#E20000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF3800&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF5500&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF7100&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF8D00&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFAA00&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFC600&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFE200&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFFF00&quot;&gt;&lt;/div&gt;
    &lt;/div&gt;
    &lt;form action=&quot;https://IndexOutOfRange.us15.list-manage.com/subscribe/post?u=b1c1099bf7f49b95c64107c99&amp;amp;id=6a5eb68eb7&quot; method=&quot;post&quot; id=&quot;mc-embedded-subscribe-form&quot; name=&quot;mc-embedded-subscribe-form&quot; class=&quot;validate&quot; target=&quot;_blank&quot; novalidate=&quot;&quot;&gt;
        &lt;div id=&quot;mc_embed_signup_scroll&quot;&gt;
        &lt;label for=&quot;mce-EMAIL&quot; style=&quot;color: white;&quot;&gt;Get email notifications about new posts:&lt;/label&gt;
        &lt;input type=&quot;email&quot; value=&quot;&quot; name=&quot;EMAIL&quot; class=&quot;email&quot; id=&quot;mce-EMAIL&quot; placeholder=&quot;email address&quot; required=&quot;&quot; /&gt;
        &lt;!-- real people should not fill this in and expect good things - do not remove this or risk form bot signups--&gt;
        &lt;div style=&quot;position: absolute; left: -5000px;&quot; aria-hidden=&quot;true&quot;&gt;&lt;input type=&quot;text&quot; name=&quot;b_b1c1099bf7f49b95c64107c99_6a5eb68eb7&quot; tabindex=&quot;-1&quot; value=&quot;&quot; /&gt;&lt;/div&gt;
        &lt;div class=&quot;clear&quot;&gt;&lt;input type=&quot;submit&quot; value=&quot;Subscribe&quot; name=&quot;subscribe&quot; id=&quot;mc-embedded-subscribe&quot; class=&quot;button&quot; /&gt;&lt;/div&gt;
        &lt;/div&gt;
    &lt;/form&gt;
&lt;/div&gt;

&lt;!--End mc_embed_signup--&gt;

&lt;h1 id=&quot;query-language&quot;&gt;Query Language&lt;/h1&gt;

&lt;p&gt;From all the differences and features discussed in this post, this one will have the most significant day to day implications.&lt;/p&gt;

&lt;h2 id=&quot;mongodb-querying-language&quot;&gt;MongoDB querying language&lt;/h2&gt;

&lt;p&gt;MongoDB has a very JSON like approach to building querries. The simplest find querry looks like this:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;inventory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;find&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;na&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&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;/div&gt;

&lt;p&gt;Corresponding to SQL query of this:&lt;/p&gt;

&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;Select&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;inventory&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;where&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;&quot;tests&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Looks OK. But where it starts to fall apart is when we want to express things like operators:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;inventory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;find&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;na&quot;&gt;$or&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;na&quot;&gt;status&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&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;na&quot;&gt;qty&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;na&quot;&gt;$lt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;30&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;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;/div&gt;

&lt;p&gt;This corresponds to this SQL:&lt;/p&gt;

&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;inventory&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;status&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;&quot;A&quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;OR&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;qty&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;30&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;What is nice is the fact that MongoDB managed to keep the language principles simple when dealing with more complex for complex properties in the document. For example this:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;inventory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;find&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;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;instock&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&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;na&quot;&gt;qty&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;warehouse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&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;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Will find documents with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;instock&lt;/code&gt; object equal to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;{ qty: 5, warehouse: &quot;A&quot; }&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Going back to MongoDB for this article made me remember the most common annoyance with writing MongoDB queries - missing or misplaced braces. 
Now let’s see what RavenDb has to offer.&lt;/p&gt;

&lt;h3 id=&quot;ravendb-query-language&quot;&gt;RavenDB query language&lt;/h3&gt;

&lt;p&gt;When talking about querying RavenDB, we have to separate two cases - writing in C# and all the other languages. Why? Because RavenDB client leverages C# LINQ expressions (a crossover between SQL and pipes from functional languages) and allows to express queries right in the code.&lt;/p&gt;

&lt;p&gt;But not all is lost for not - C# devs. There is RQL which is a mix of SQL and JavaScript looking like this:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Inventory&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;where&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;err&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;from&lt;/code&gt; at the start looks strange, but I can live with this syntax.
Now for the second query:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Inventory&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;where&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;status&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;sc&quot;&gt;'A'&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;qty&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;30&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;For me, it is much cleaner than the one in MongoDB. Time for querying complex properties:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Inventory&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;where&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;instock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;qty&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;5&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;instock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;warehouse&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;sc&quot;&gt;'A'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;direct-comparison&quot;&gt;Direct comparison&lt;/h2&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;MongoDB&lt;/th&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;RavenDB&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;db.inventory.find( { Name: &quot;test&quot; } )&lt;/code&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;from Inventory where Name = 'test'&lt;/code&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;db.inventory.find( { $or: [ { status: &quot;A&quot; }, { qty: { $lt: 30 } } ] } )&lt;/code&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;from Inventory where status = 'A' or qty &amp;lt; 30&lt;/code&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;db.inventory.find( { &quot;instock&quot;: { qty: 5, warehouse: &quot;A&quot; } } )&lt;/code&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;from Inventory where instock.qty = 5 and instock.warehouse = 'A'&lt;/code&gt;&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;h2 id=&quot;query-language-conclusion&quot;&gt;Query language conclusion&lt;/h2&gt;

&lt;p&gt;I know this is a matter of taste, but SQL is the most popular language for querying data. Having something similar to it makes the developer more productive faster.
Some will say that custom language in MongoDB allows for unique functionalities and that SQL is not well suited for document databases. I agree with this, but only partially. Multiple document databases expose SQL like querying language, and some migrated from custom to syntax to one more similar to SQL without losing unique functionalities.&lt;/p&gt;

&lt;h1 id=&quot;indexing&quot;&gt;Indexing&lt;/h1&gt;

&lt;h2 id=&quot;why-is-indexing-vital-in-document-databases&quot;&gt;Why is indexing vital in document databases?&lt;/h2&gt;

&lt;p&gt;We all know that database indexing is essential. For decades they were the most effective ways to optimize relational databases. But there is one very distinctive difference between relational and document databases (MongoDB and RavenDB in our case). The lack of a schema. Why does this matter?&lt;/p&gt;

&lt;p&gt;When we query over a &lt;strong&gt;non-indexed&lt;/strong&gt; column in a &lt;strong&gt;relational database&lt;/strong&gt;, it doesn’t have to read the whole file representing the table. It knows the table structure so it can calculate the file offsets and read only the necessary file fragments where this property is stored. Not ideal but works quite good.&lt;/p&gt;

&lt;p&gt;When we query over a ** non-indexed** property in a &lt;strong&gt;schema-less document database&lt;/strong&gt; the database doesn’t know the structure. It means that it has to deserialize each document and check if the requested property exists and what is its value. This means a higher disc, CPU and RAM usage.&lt;/p&gt;

&lt;h2 id=&quot;ravendb-vs-mongodb-indexes&quot;&gt;RavenDB vs. MongoDB indexes&lt;/h2&gt;

&lt;h3 id=&quot;mongodb-indexes&quot;&gt;MongoDB indexes&lt;/h3&gt;

&lt;p&gt;MongoDB has a very standard set of indexes:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://docs.mongodb.com/manual/core/index-single/&quot;&gt;Single field&lt;/a&gt; - for indexing one field&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://docs.mongodb.com/manual/core/index-compound/&quot;&gt;Compound index&lt;/a&gt; - for indexing multiple properties&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://docs.mongodb.com/manual/core/index-multikey/&quot;&gt;Multikey index&lt;/a&gt; - for indexing array items&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://docs.mongodb.com/manual/core/geospatial-indexes/&quot;&gt;Geospatial Index&lt;/a&gt; - for GIS operations&lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://docs.mongodb.com/manual/core/index-text/&quot;&gt;Text index&lt;/a&gt; - for text searches. It uses Lucene, so you get full-text search like in Elastic Search or Solr.&lt;/p&gt;

    &lt;blockquote&gt;
      &lt;p&gt;MongoDB has a limitation that one collection can have only one text index.&lt;/p&gt;
    &lt;/blockquote&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As an addition, indexes can have additional properties:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://docs.mongodb.com/manual/core/index-unique/&quot;&gt;Unique Indexes&lt;/a&gt; - for guaranteeing uniqueness of the features&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://docs.mongodb.com/manual/core/index-partial/&quot;&gt;Partial Indexes&lt;/a&gt; - they give the ability to filter the documents that will be indexed.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://docs.mongodb.com/manual/core/index-sparse/&quot;&gt;Sparse Indexes&lt;/a&gt; - they will only index documents that have the selected property after version 3.2 replaced by Partial Indexes indexes.&lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://docs.mongodb.com/manual/core/index-ttl/&quot;&gt;TTL Indexes&lt;/a&gt; - allows defining an automatic document removal period.&lt;/p&gt;

    &lt;blockquote&gt;
      &lt;p&gt;A useful option, but why is it on an index?&lt;/p&gt;
    &lt;/blockquote&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It is a very standard and robust set of indexes. Nothing groundbreaking, but OK.&lt;/p&gt;

&lt;h3 id=&quot;ravendb-indexes&quot;&gt;RavenDB indexes&lt;/h3&gt;

&lt;p&gt;RavenDB has a fundamentally different design approach to indexes. They are represented and declared as a user-defined function. Such a function is passed to RavenDB, and it takes care of the indexing and maintaining the index. 
This design decision leads to exciting possibilities like:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://ravendb.net/docs/article-page/4.2/csharp/indexes/map-indexes#combining-multiple-fields-together&quot;&gt;Combining fields in the index (FirstName + ‘ ‘ + LastName )&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://ravendb.net/docs/article-page/4.2/csharp/indexes/map-reduce-indexes&quot;&gt;Executing calculations&lt;/a&gt; (if it can be expressed as a function it can be used in an index)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://ravendb.net/docs/article-page/4.2/csharp/indexes/map-reduce-indexes#reduce-results-as-artificial-documents&quot;&gt;Aggregating documents before indexing&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://ravendb.net/docs/article-page/4.2/csharp/indexes/fanout-indexes&quot;&gt;Having multiple entries in an index for a document&lt;/a&gt; - this is very useful when we want to flatten the object structure for indexing.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://ravendb.net/docs/article-page/4.2/csharp/indexes/indexing-related-documents#example-ii&quot;&gt;Perform queries in the indexing function&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://ravendb.net/docs/article-page/4.2/csharp/indexes/indexing-hierarchical-data&quot;&gt;Indexing hierarchical data&lt;/a&gt;. I like this feature because executing hierarchical queries without support from the database is tough. In most cases requires special data modelling.&lt;/p&gt;

    &lt;blockquote&gt;
      &lt;p&gt;I wrote more on modelling hierarchical data &lt;a href=&quot;/How-to-model-hierarchical-data-in-noSQL-datababases/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
    &lt;/blockquote&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I am very impressed by the power that RavenDB indexes offer. They are pushing the user into two behaviours:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;For complex queries, separate the write model from the read model - CQRS. Something that we all know we should do, but don’t always do.&lt;/li&gt;
  &lt;li&gt;Always try to query over an index.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;auto-indexes&quot;&gt;Auto indexes&lt;/h4&gt;

&lt;p&gt;The push to always try to query over an index is supported by the last feature that I will discuss - &lt;a href=&quot;https://ravendb.net/docs/article-page/4.2/csharp/indexes/creating-and-deploying#auto-indexes&quot;&gt;auto-indexing&lt;/a&gt;. 
RavenDB can monitor the queries and automatically create indexes. It could be a very dangerous option because indexes generate an additional load on the server. But RavenDB also can delete unused indexes. 
Why do I like this feature? Adding each new component to the system means one additional element to worry about, monitor and maintain. Auto indexing won’t zero this overhead but anything that will decrease it is a welcomed addition.&lt;/p&gt;

&lt;h2 id=&quot;indexing-comparison&quot;&gt;Indexing comparison&lt;/h2&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;Option&lt;/th&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;MongoDB&lt;/th&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;RavenDB&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Primary indexes&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;a href=&quot;https://docs.mongodb.com/manual/indexes/#default-id-index&quot;&gt;Yes&lt;/a&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Yes&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Secondary indexes&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Yes&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Yes&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Auto indexes&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;No*2&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;a href=&quot;https://docs.mongodb.com/manual/indexes/#default-id-index&quot;&gt;Yes&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Multiple fields in one index&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;a href=&quot;https://docs.mongodb.com/manual/indexes/#default-id-index&quot;&gt;Yes (Compound Index)&lt;/a&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;a href=&quot;https://ravendb.net/docs/article-page/4.1/csharp/indexes/map-indexes&quot;&gt;Yes (Map indexes)&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Spatial indexes&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;a href=&quot;https://docs.mongodb.com/manual/core/geospatial-indexes/&quot;&gt;Yes (GeoSpatial Index)&lt;/a&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;a href=&quot;https://ravendb.net/docs/article-page/4.2/csharp/indexes/indexing-spatial-data&quot;&gt;Yes (Spatial Data)&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Full-text indexes&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;a href=&quot;https://docs.mongodb.com/manual/core/index-text/&quot;&gt;Yes (Text Index)&lt;/a&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;a href=&quot;https://ravendb.net/docs/article-page/4.2/csharp/indexes/using-analyzers#full-text-search&quot;&gt;Yes (Full-Text Search)&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Multi-collection indexes&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;a href=&quot;https://docs.mongodb.com/manual/applications/indexes/&quot;&gt;No&lt;/a&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;a href=&quot;https://ravendb.net/docs/article-page/4.2/csharp/indexes/multi-map-indexes&quot;&gt;Yes&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Hierarchical indexes&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;No&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;a href=&quot;https://ravendb.net/docs/article-page/4.2/csharp/indexes/indexing-hierarchical-data&quot;&gt;Yes&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Perform calculations or operations on indexes&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;No&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;a href=&quot;https://ravendb.net/docs/article-page/4.2/csharp/indexes/map-reduce-indexes&quot;&gt;Yes(Map-Reduce Indexes)&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Convert data during indexing&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;No&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;a href=&quot;https://ravendb.net/docs/article-page/4.2/csharp/indexes/map-indexes#combining-multiple-fields-together&quot;&gt;Yes&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Aggregate data in indexes&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;No&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;a href=&quot;https://ravendb.net/docs/article-page/4.2/csharp/indexes/map-reduce-indexes#reduce-results-as-artificial-documents&quot;&gt;Yes&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;&lt;strong&gt;Legend:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;*2&lt;/strong&gt; - &lt;a href=&quot;https://www.mongodb.com/blog/post/improving-mongodb-performance-with-automatically-generated-index-suggestions&quot;&gt;it could be done with Mongo Atlas&lt;/a&gt; but isn’t available in the free version and doesn’t work out of the box&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;summary&quot;&gt;Summary&lt;/h1&gt;

&lt;p&gt;&lt;a name=&quot;MongoDB&quot;&gt;&lt;/a&gt;
&lt;img src=&quot;/data/2019-12-01-RavenDBvsMongoDB/mongodb.png&quot; alt=&quot;MongoDB&quot; class=&quot;logo&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;mongodb-1&quot;&gt;MongoDB&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The good:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Free version without a database or used CPU/memory limits.&lt;/li&gt;
  &lt;li&gt;Solid documentation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The bad:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The lack of SQL like syntax for query operations makes for a steep learning curve.&lt;/li&gt;
  &lt;li&gt;Robo3T is better than it used to be, but still lacking.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The ugly:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;What is with the MongoDB Atlas backup pricing?&lt;/li&gt;
  &lt;li&gt;That Windows Docker image could be smaller.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a name=&quot;RavenDB&quot;&gt;&lt;/a&gt;
&lt;img src=&quot;/data/2019-12-01-RavenDBvsMongoDB/ravendb.png&quot; alt=&quot;RavenDB&quot; class=&quot;logo&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;ravendb&quot;&gt;RavenDB&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The good:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Multiple indexing options.&lt;/li&gt;
  &lt;li&gt;SQL-like RQL (&lt;strong&gt;R&lt;/strong&gt;aven &lt;strong&gt;Q&lt;/strong&gt;uery &lt;strong&gt;L&lt;/strong&gt;anguage) provides a smooth learning curve.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Raven Studio&lt;/strong&gt; for querying and managing the database is just a substantial addition to the product. Way better than Robot3T&lt;/li&gt;
  &lt;li&gt;A clear design goal to push the user towards proper behaviour&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The bad:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The limits in the free version could be higher. For me, they won’t be an issue, but I can imagine them deter some people. Maybe a different licencing model?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The ugly:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;s&gt;The documentation is lacking and is very uneven how deep is each section.&lt;/s&gt;
    &lt;p&gt;&lt;a href=&quot;https://ravendb.net/learn/inside-ravendb-book/reader/4.0/1-welcome-to-ravendb&quot;&gt;There is an excellent book on the website that goes in-depth and beyond&lt;/a&gt;. Also not a fan of the dark theme, but I know I’m in the minority.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;so-what-will-it-be&quot;&gt;So, what will it be?&lt;/h2&gt;

&lt;p&gt;This comparison is far from exhaustive, but I have some conclusions. I will probably make a performance comparison of those two. For now, RavenDB feels like a solid, well thought out product with even more potential (e.g., clustering) for delivering new features that will build on the previous design decisions.&lt;/p&gt;

&lt;style&gt;
div.entry-content .logo{
 height:150px;
}
&lt;/style&gt;

</description>
        <pubDate>Sun, 01 Dec 2019 00:00:00 +0100</pubDate>
        <link>https://IndexOutOfRange.com//RavenDBvsMongoDB/</link>
        <guid isPermaLink="true">https://IndexOutOfRange.com//RavenDBvsMongoDB/</guid>
      </item>
    
      <item>
        <title>Tips, tricks, and good practices for Data-Driven Testing. Part 2.</title>
        <description>&lt;img src='https://indexoutofrange.com/data/2019-09-09-data-driven-tests-tips-and-tricks-part2/logo.jpg' /&gt;&lt;p&gt;This post is a continuation of a previous &lt;a href=&quot;/data-driven-tests-tips-and-tricks-part1/&quot;&gt;tips, tricks, and good practices for Data-Driven Testing&lt;/a&gt; entry. This one with more code.&lt;/p&gt;

&lt;!--MORE--&gt;

&lt;h1 id=&quot;before-we-begin&quot;&gt;Before we begin&lt;/h1&gt;

&lt;p&gt;I will be converting this series into an ebook with additional source code and examples. If you want to get it, please subscribe:&lt;/p&gt;

&lt;!-- Begin MailChimp Signup Form --&gt;

&lt;link href=&quot;//cdn-images.mailchimp.com/embedcode/horizontal-slim-10_7.css&quot; rel=&quot;stylesheet&quot; type=&quot;text/css&quot; /&gt;

&lt;style type=&quot;text/css&quot;&gt;
	#mc_embed_signup{
        clear:left; 
        font:14px Helvetica,Arial,sans-serif; 
        width:100%; 
        margin-top: 40px;
        margin-bottom: 40px;
        height:100px;
    }
    #mc_embed_signup .newsletter div{
        height: 100px;
    }
    #mc_embed_signup form{
        position: relative;
        top: -90px;
    }
	/* Add your own MailChimp form style overrides in your site stylesheet or in this style block.
	   We recommend moving this block and the preceding CSS link to the HEAD of your HTML file. */
&lt;/style&gt;

&lt;div id=&quot;mc_embed_signup&quot;&gt;
    &lt;div class=&quot;gradient newsletter&quot;&gt;
        &lt;div style=&quot;background:#000000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#1C0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#380000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#550000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#710000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#8D0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#AA0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#C60000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#E20000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF3800&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF5500&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF7100&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF8D00&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFAA00&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFC600&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFE200&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFFF00&quot;&gt;&lt;/div&gt;
    &lt;/div&gt;
    &lt;form action=&quot;https://IndexOutOfRange.us15.list-manage.com/subscribe/post?u=b1c1099bf7f49b95c64107c99&amp;amp;id=6a5eb68eb7&quot; method=&quot;post&quot; id=&quot;mc-embedded-subscribe-form&quot; name=&quot;mc-embedded-subscribe-form&quot; class=&quot;validate&quot; target=&quot;_blank&quot; novalidate=&quot;&quot;&gt;
        &lt;div id=&quot;mc_embed_signup_scroll&quot;&gt;
        &lt;label for=&quot;mce-EMAIL&quot; style=&quot;color: white;&quot;&gt;Get email notifications about new posts:&lt;/label&gt;
        &lt;input type=&quot;email&quot; value=&quot;&quot; name=&quot;EMAIL&quot; class=&quot;email&quot; id=&quot;mce-EMAIL&quot; placeholder=&quot;email address&quot; required=&quot;&quot; /&gt;
        &lt;!-- real people should not fill this in and expect good things - do not remove this or risk form bot signups--&gt;
        &lt;div style=&quot;position: absolute; left: -5000px;&quot; aria-hidden=&quot;true&quot;&gt;&lt;input type=&quot;text&quot; name=&quot;b_b1c1099bf7f49b95c64107c99_6a5eb68eb7&quot; tabindex=&quot;-1&quot; value=&quot;&quot; /&gt;&lt;/div&gt;
        &lt;div class=&quot;clear&quot;&gt;&lt;input type=&quot;submit&quot; value=&quot;Subscribe&quot; name=&quot;subscribe&quot; id=&quot;mc-embedded-subscribe&quot; class=&quot;button&quot; /&gt;&lt;/div&gt;
        &lt;/div&gt;
    &lt;/form&gt;
&lt;/div&gt;

&lt;!--End mc_embed_signup--&gt;

&lt;h1 id=&quot;1-reading-data-files&quot;&gt;1. Reading data files&lt;/h1&gt;

&lt;h2 id=&quot;11-use-setname&quot;&gt;1.1 Use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SetName&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;We know that the objects returned by the function that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TestCaseDataAttribute&lt;/code&gt; points to will generate tests. The question is, how will they be called? By default, the name is generated from the method name and the arguments provided. It won’t be pretty. But we already &lt;a href=&quot;/data-driven-tests-tips-and-tricks-part1/&quot;&gt;have descriptive names for the test case folders&lt;/a&gt;. Why not use them? This is where the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SetName&lt;/code&gt; method on the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TestCaseData&lt;/code&gt; class comes in. 
We can change the initial file reading code to something better:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&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;n&quot;&gt;TestCaseData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;GetData&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;retArray&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Directory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetDirectories&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;MyTestDataFolder&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;*&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SearchOption&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AllDirectories&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;nf&quot;&gt;OrderBy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&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;nf&quot;&gt;Select&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&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;ret&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;nf&quot;&gt;TestCaseData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;JsonConvert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;DeserializeObject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;testdata.json&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ExpectedResult&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;JsonConvert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;DeserializeObject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;expectedResult.json&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;SetName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Replace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;_&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot; &quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;//to make it even more human readable I remove the underscores and replace them with spaces.&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ret&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;nf&quot;&gt;ToArray&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;retArray&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;/div&gt;

&lt;p&gt;This isn’t a huge change, but it saves a lot of time in resizing the test results window to check which file failed.&lt;/p&gt;

&lt;h2 id=&quot;12-wrap-file-parsing-in-a-trycatch&quot;&gt;1.2 Wrap file parsing in a try/catch&lt;/h2&gt;

&lt;p&gt;Your files will have errors, and parsing them will fail. It might not seem like a problem, but it is a bit of a pain. Why? Exceptions thrown in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TestCaseData&lt;/code&gt; generating method don’t show in the test results. What happens is that the tests disappear and only the primary method (which is always the parent of all data generated tests) is marked as failed, or inconclusive. Debugging such problems is also not ideal because if &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Break on all exceptions&lt;/code&gt; isn’t enabled, the exception will get caught by the test runner. Exiting our debug session. 
My solution to this is to wrap the folder reader in a try/catch block and add the crashed file name there. After the change, our code will look like below:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&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;n&quot;&gt;TestCaseData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;GetData&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;retArray&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Directory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetDirectories&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;MyTestDataFolder&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;*&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SearchOption&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AllDirectories&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;nf&quot;&gt;OrderBy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&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;nf&quot;&gt;Select&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&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;k&quot;&gt;try&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;ret&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;nf&quot;&gt;TestCaseData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;JsonConvert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;DeserializeObject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;testdata.json&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
                    &lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ExpectedResult&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;JsonConvert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;DeserializeObject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;expectedResult.json&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
                    &lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;SetName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Replace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;_&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot; &quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;//to make it even more human readable I remove the underscores and replace them with spaces.&lt;/span&gt;
                    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ret&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;catch&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Exception&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;p&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;k&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Exception&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;$&quot;Error in processing test data for folder: '&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&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;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;nf&quot;&gt;ToArray&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;retArray&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;/div&gt;

&lt;p&gt;This again isn’t a huge change, but one that when added at the start will save a few hours in pointless debugging.&lt;/p&gt;

&lt;h2 id=&quot;13-have-a-file-reader-class&quot;&gt;1.3 Have a file reader class&lt;/h2&gt;

&lt;p&gt;This tip is one that will save you from reimplementing the reading logic. Extract the logic of reading the dataset files into a separate reader class (I name it &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DATA_SET_NAMEReader&lt;/code&gt;) and place in the same folder as the dataset folder. It will look like this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/data/2019-09-09-data-driven-tests-tips-and-tricks-part2/datasetreaders.png&quot; alt=&quot;dataset readers&quot; /&gt;&lt;/p&gt;

&lt;p&gt;This simplifies the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;where is that reader&lt;/code&gt; question, lowering the effort, and by that making the reuse more probable.&lt;/p&gt;

&lt;h1 id=&quot;2-comparing&quot;&gt;2 Comparing&lt;/h1&gt;

&lt;h2 id=&quot;21-dont-use-expectedresult-for-complex-objects&quot;&gt;2.1 Don’t use ExpectedResult for complex objects.&lt;/h2&gt;

&lt;p&gt;If you read the &lt;a href=&quot;/refactoring-to-data-driven-tests/&quot;&gt;previous entry&lt;/a&gt;, you know that I like using this property. But, as always in IT. It depends. It is handy for simple objects, but for comparing complex ones, I prefer to write my own Asserts.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;The other option in NUnit is to use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Returns&lt;/code&gt; method on the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TestCaseData&lt;/code&gt; class. It has the benefits that it returns a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TestCaseData&lt;/code&gt; class so that we can have tidy fluent calls.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&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;n&quot;&gt;TestCaseData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;GetData&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;retArray&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Directory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetDirectories&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;MyTestDataFolder&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;*&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SearchOption&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AllDirectories&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;nf&quot;&gt;OrderBy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&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;nf&quot;&gt;Select&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&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;k&quot;&gt;try&lt;/span&gt;
                &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;c1&quot;&gt;//a bit more compacted and fluent.&lt;/span&gt;
                    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;TestCaseData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;JsonConvert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;DeserializeObject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;testdata.json&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;nf&quot;&gt;Returns&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;JsonConvert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;DeserializeObject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;expectedResult.json&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;nf&quot;&gt;SetName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Replace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;_&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot; &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;p&quot;&gt;}&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Exception&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;p&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;k&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Exception&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;$&quot;Error in processing test data for folder: '&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&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;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;nf&quot;&gt;ToArray&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;retArray&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;/div&gt;

&lt;h2 id=&quot;22-use-a-diff-tool-for-comparing&quot;&gt;2.2 Use a diff tool for comparing&lt;/h2&gt;

&lt;p&gt;Asserts are great. But when running a large number of tests, there are better ways to compare what we expected with what we got - Diff comparison tools. 
First, how to save the received results as files and what practices I use:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&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;MyTestSiute&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_pathForReceived&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;@&quot;C:\temp\MyDataDrivenTests_ReceivedResults&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_saveReceivedResultsToDrive&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;//A single flag that determins if we write the restults to the disk&lt;/span&gt;

        &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NUnit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Framework&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OneTimeSetUp&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;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;TestSuiteSetup&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;// A common source of mistakes is comparing old files. This is why I always delete the whole folder&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;_saveReceivedResultsToDrive&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;amp;&amp;amp;&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;IO&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Directory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Exists&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_pathForReceived&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;Directory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Delete&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_pathForReceived&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;Directory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;CreateDirectory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_pathForReceived&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// And recreate it.&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;cm&quot;&gt;/*
        Get data method and other helper functions
        */&lt;/span&gt;

        &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;TestCaseSource&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;nameof&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GetData&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;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;MyDataDrivenTests&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MyTestData&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&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;cm&quot;&gt;/*
            some preparation code
            */&lt;/span&gt;
            &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;received&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;testObject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;TestMethod&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Data&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;_saveReceivedResultsToDrive&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;receivedFilename&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Combine&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_pathForReceived&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TestCaseFolderName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;expected.json&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// We want to have the same folder structure and names in the results and in the received folder&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;WriteAllText&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;receivedFilename&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;JsonConvert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;SerializeObject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;received&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Formatting&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Indented&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// Remember about the formating!&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;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Once this is in place, we can use &lt;a href=&quot;https://www.devart.com/codecompare/&quot;&gt;Code Compare&lt;/a&gt; and its option to compare folders to get this result (blue files are those that differ):&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/data/2019-09-09-data-driven-tests-tips-and-tricks-part2/codecompare.png&quot; alt=&quot;code compare&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Easy and readable.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Code Compare by default launches in file comparison mode. Switching to directory comparison isn’t that visible, so to save you some time here it is:
&lt;img src=&quot;/data/2019-09-09-data-driven-tests-tips-and-tricks-part2/codecompare_comparedirectories.png&quot; alt=&quot;code compare&quot; /&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1 id=&quot;3-advanced-testsing-scenarios&quot;&gt;3. Advanced testsing scenarios&lt;/h1&gt;

&lt;h2 id=&quot;31-one-data-set-multiple-results&quot;&gt;3.1 One data set, multiple results&lt;/h2&gt;

&lt;p&gt;In the first &lt;a href=&quot;/refactoring-to-data-driven-tests/&quot;&gt;post of this series&lt;/a&gt; I wrote about testing a gearbox controller. We already had a test case source, so why move to files?
When we move the test data to files, we open new options on reusability. 
What will happen when we want to test a second gearbox controller? We could reuse the same datasets. 
What to do with the expected result files?
Save them in the same folder structure, but use a convention for recognizing for which scenario they are for:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/data/2019-09-09-data-driven-tests-tips-and-tricks-part2/differentresultfiles.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;32-multi-step-testing&quot;&gt;3.2 Multi step testing&lt;/h2&gt;

&lt;p&gt;Data-driven tests are great not only to verify a single function. Their biggest strength is in verifying the whole process. 
I wrote previously about how I use data-driven tests extensively in cookit for verifying recipe text parsing. This process is split into multiple data-driven tests:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Determine if HTML is a recipe page.&lt;/li&gt;
  &lt;li&gt;Extract recipe text, ingredient list, image, etc.&lt;/li&gt;
  &lt;li&gt;Recognize ingredients.&lt;/li&gt;
  &lt;li&gt;Build a list of ingredients, with weights, need for the recipe.&lt;/li&gt;
  &lt;li&gt;Extract cooking time, tags, etc.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;All of this can be done in one run. But splitting them makes it easier to understand what precisely broke.
Data driven tests are especially easy to break down into more detaild tests because all we have to do is to save some intermediary result to the drive, and use it to feed the next step. 
No need to create additional test data. We already have it.&lt;/p&gt;

&lt;h1 id=&quot;4-general&quot;&gt;4 General&lt;/h1&gt;

&lt;h2 id=&quot;41-copy-localon-all-files-in-visual-studiomsbuild&quot;&gt;4.1 Copy localon all files in Visual Studio/MSBuild&lt;/h2&gt;

&lt;p&gt;Before I explain it more let me say that I have mixed feelings with this one. I will explain why, after explaining the problem and the solution.&lt;/p&gt;

&lt;h3 id=&quot;the-problem&quot;&gt;The problem&lt;/h3&gt;

&lt;p&gt;By default, MSBuild copies only the dll files into the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bin&lt;/code&gt; folder. That is a good thing since we don’t want to ship source code with our dll files. But with data-driven tests, this is an annoyance because then our data files aren’t on the same level as the test dlls. This is a problem for two reasons:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Tests are executed with the root folder equal to the test dll root folder. So we will need to traverse to the data folders with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;..\..\&lt;/code&gt;. Not too elegant and prone to errors.&lt;/li&gt;
  &lt;li&gt;To speed up the CI pipeline, I often split building and running tests. This way, I can build once and use the build artifacts to run the tests in parallel on multiple agents. Getting the verification faster. The problem is that most build agents only copy the content of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bin&lt;/code&gt; directory into the build artifacts.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both of the above can be changed, but are annoying at first. A much smoother solution would be to copy the data directory into the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bin&lt;/code&gt; folder path.&lt;/p&gt;

&lt;h3 id=&quot;the-solution-&quot;&gt;The Solution (?)&lt;/h3&gt;

&lt;p&gt;To copy our data files into the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bin&lt;/code&gt; folder, we can change the property of each file to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Copy if never&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/data/2019-09-09-data-driven-tests-tips-and-tricks-part2/copylocal.png&quot; alt=&quot;code compare&quot; /&gt;&lt;/p&gt;

&lt;p&gt;But this approach is wrong because:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;we have to set it on each file&lt;/li&gt;
  &lt;li&gt;when we add a new test data, it won’t be picked up if we don’t set the copy local.&lt;/li&gt;
  &lt;li&gt;pointing to each file will create a big &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.csproj&lt;/code&gt; file, so merging and conflicts will be harder.&lt;/li&gt;
  &lt;li&gt;there is a much better solution.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We can set the in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;*.csproj&lt;/code&gt; to copy the whole folder with a simple change:&lt;/p&gt;

&lt;div class=&quot;language-xml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;nt&quot;&gt;&amp;lt;ItemGroup&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;None&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Update=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Data\**&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;CopyToOutputDirectory&amp;gt;&lt;/span&gt;PreserveNewest&lt;span class=&quot;nt&quot;&gt;&amp;lt;/CopyToOutputDirectory&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/None&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/ItemGroup&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This will copy the whole &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Data&lt;/code&gt; folder into the output only if there is a newer version of the file. Awesome!? Not exactly. This solution has one major flaw.&lt;/p&gt;

&lt;h3 id=&quot;why-i-have-doubts-about-this-solution&quot;&gt;Why I have doubts about this solution?&lt;/h3&gt;

&lt;p&gt;The biggest problem with this solution is that it will slow down the build (we are adding file copy for each build). 
Will it be a significant slowdown? 
For a small number of files and a computer using SSD drives, it probably won’t be noticable.
For a large number of files or a machine running a mechanical drive, it can be a disadvantage to consider.&lt;/p&gt;

&lt;h1 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h1&gt;

&lt;p&gt;Are those groundbreaking tips? No. But adopting each one of them will make your life easier with data-driven tests.&lt;/p&gt;
</description>
        <pubDate>Mon, 09 Sep 2019 00:00:00 +0200</pubDate>
        <link>https://IndexOutOfRange.com//data-driven-tests-tips-and-tricks-part2/</link>
        <guid isPermaLink="true">https://IndexOutOfRange.com//data-driven-tests-tips-and-tricks-part2/</guid>
      </item>
    
      <item>
        <title>Tips, tricks, and good practices for Data-Driven Testing. Part 1.</title>
        <description>&lt;img src='https://indexoutofrange.com/data/2019-09-03-data-driven-tests-tips-and-tricks-part1/logo.jpg' /&gt;&lt;p&gt;As promised &lt;a href=&quot;/refactoring-to-data-driven-tests/&quot;&gt;here&lt;/a&gt; and &lt;a href=&quot;/where-to-get-data-for-data-driven-tests/&quot;&gt;here&lt;/a&gt;, this will be tips, tricks, and good practices for data-driven tests.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;If You want to know more about data-driven testing see my &lt;a href=&quot;/refactoring-to-data-driven-tests/&quot;&gt;previous&lt;/a&gt; &lt;a href=&quot;/where-to-get-data-for-data-driven-tests/&quot;&gt;posts&lt;/a&gt; on this topic.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Here we go.&lt;/p&gt;

&lt;!--MORE--&gt;

&lt;h1 id=&quot;before-we-begin&quot;&gt;Before we begin&lt;/h1&gt;

&lt;p&gt;I will be converting this series into an ebook, or something like that, with additional source code and examples. If You want to get it please subscribe:&lt;/p&gt;

&lt;!-- Begin MailChimp Signup Form --&gt;

&lt;link href=&quot;//cdn-images.mailchimp.com/embedcode/horizontal-slim-10_7.css&quot; rel=&quot;stylesheet&quot; type=&quot;text/css&quot; /&gt;

&lt;style type=&quot;text/css&quot;&gt;
	#mc_embed_signup{
        clear:left; 
        font:14px Helvetica,Arial,sans-serif; 
        width:100%; 
        margin-top: 40px;
        margin-bottom: 40px;
        height:100px;
    }
    #mc_embed_signup .newsletter div{
        height: 100px;
    }
    #mc_embed_signup form{
        position: relative;
        top: -90px;
    }
	/* Add your own MailChimp form style overrides in your site stylesheet or in this style block.
	   We recommend moving this block and the preceding CSS link to the HEAD of your HTML file. */
&lt;/style&gt;

&lt;div id=&quot;mc_embed_signup&quot;&gt;
    &lt;div class=&quot;gradient newsletter&quot;&gt;
        &lt;div style=&quot;background:#000000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#1C0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#380000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#550000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#710000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#8D0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#AA0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#C60000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#E20000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF3800&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF5500&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF7100&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF8D00&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFAA00&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFC600&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFE200&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFFF00&quot;&gt;&lt;/div&gt;
    &lt;/div&gt;
    &lt;form action=&quot;https://IndexOutOfRange.us15.list-manage.com/subscribe/post?u=b1c1099bf7f49b95c64107c99&amp;amp;id=6a5eb68eb7&quot; method=&quot;post&quot; id=&quot;mc-embedded-subscribe-form&quot; name=&quot;mc-embedded-subscribe-form&quot; class=&quot;validate&quot; target=&quot;_blank&quot; novalidate=&quot;&quot;&gt;
        &lt;div id=&quot;mc_embed_signup_scroll&quot;&gt;
        &lt;label for=&quot;mce-EMAIL&quot; style=&quot;color: white;&quot;&gt;Get email notifications about new posts:&lt;/label&gt;
        &lt;input type=&quot;email&quot; value=&quot;&quot; name=&quot;EMAIL&quot; class=&quot;email&quot; id=&quot;mce-EMAIL&quot; placeholder=&quot;email address&quot; required=&quot;&quot; /&gt;
        &lt;!-- real people should not fill this in and expect good things - do not remove this or risk form bot signups--&gt;
        &lt;div style=&quot;position: absolute; left: -5000px;&quot; aria-hidden=&quot;true&quot;&gt;&lt;input type=&quot;text&quot; name=&quot;b_b1c1099bf7f49b95c64107c99_6a5eb68eb7&quot; tabindex=&quot;-1&quot; value=&quot;&quot; /&gt;&lt;/div&gt;
        &lt;div class=&quot;clear&quot;&gt;&lt;input type=&quot;submit&quot; value=&quot;Subscribe&quot; name=&quot;subscribe&quot; id=&quot;mc-embedded-subscribe&quot; class=&quot;button&quot; /&gt;&lt;/div&gt;
        &lt;/div&gt;
    &lt;/form&gt;
&lt;/div&gt;

&lt;!--End mc_embed_signup--&gt;

&lt;h1 id=&quot;keep-data-in-files&quot;&gt;Keep data in files.&lt;/h1&gt;

&lt;p&gt;I showed this in the &lt;a href=&quot;/where-to-get-data-for-data-driven-tests/&quot;&gt;previous post&lt;/a&gt;, but it is the most important tip. Save test case data as files and use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TestCaseDataAttribute&lt;/code&gt; to declare the function that will read it and pass as test cases. Something like this:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&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;n&quot;&gt;TestCaseData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;GetData&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;retArray&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Directory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetDirectories&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;MyTestDataFolder&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;*&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SearchOption&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AllDirectories&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;nf&quot;&gt;OrderBy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&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;nf&quot;&gt;Select&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&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;ret&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;nf&quot;&gt;TestCaseData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;JsonConvert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;DeserializeObject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;testdata.json&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ExpectedResult&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;JsonConvert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;DeserializeObject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;expectedResult.json&quot;&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;ret&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;nf&quot;&gt;ToArray&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;retArray&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;/div&gt;
&lt;p&gt;Now to te next most important area: folder structure.&lt;/p&gt;

&lt;h1 id=&quot;tips-on-folder-structure-in-data-driven-tests&quot;&gt;Tips on folder structure in Data-Driven Tests:&lt;/h1&gt;

&lt;p&gt;Since our test data is stored in files and folders, organizing them is important. Below is a sample structure I use to store test data files:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/data/2019-09-03-data-driven-tests-tips-and-tricks-part1/folderstructure.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Doesn’t look sophisticated, and isn’t once it is ready. But there are some tips there:&lt;/p&gt;

&lt;h2 id=&quot;1-have-one-data-folder-in-the-test-project&quot;&gt;1. Have one &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Data&lt;/code&gt; folder in the test project.&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;/data/2019-09-03-data-driven-tests-tips-and-tricks-part1/folderstructure-firstlevel.png&quot; alt=&quot;first level folders in data-driven tests in data-driven tests&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Having one central &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Data&lt;/code&gt; folder sounds like an anti-pattern. Let me explain why it isn’t in data-driven tests:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;They are easier to locate.&lt;/strong&gt; To read the test files, we need to know the relative path to them. One that starts at the project root. This means that if we place the test data files deep in the folder structure of the test project, we will need to duplicate that path in the test data path. Making the test more fragile for simple name changes.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Data reuse.&lt;/strong&gt; Reusing test objects in multiple tests is, in most cases, an anti-pattern. It leads to many people modifying a single object, or a class creating a no man’s land.  A part of the test project that isn’t owned by any particular test or a person. 
In data-driven test data is taken from real-life usage of the system. It isn’t made up, but something that happened. There is no point in modifying it (except for upgrading the object structure). We mostly create a new verification data set.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;2-second-level-folders---the-name-of-the-dataset&quot;&gt;2. Second level folders - the name of the dataset&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;/data/2019-09-03-data-driven-tests-tips-and-tricks-part1/folderstructure-secondlevel.png&quot; alt=&quot;second level folders in data-driven tests&quot; /&gt;&lt;/p&gt;

&lt;p&gt;This is the folder over which we iterate in the data reading method. The most apparent naming convention is to name it after the test. Sounds reasonable, but leads to one of the anti-patterns in data-driven testing: many test folders, each with a few tests and every test folder with a different file format. How to do it better? I propose naming the test after the dataset that it is.&lt;/p&gt;

&lt;div class=&quot;center&quot;&gt;
    &lt;div class=&quot;button&quot;&gt;Name it not what it is used for, but what it is. &lt;/div&gt;
&lt;/div&gt;

&lt;blockquote&gt;
  &lt;p&gt;For example:
In cookit.pl, I am parsing HTML websites and extracting recipe text and ingredients. The main logic is in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Parse&lt;/code&gt; method in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RecipeParser&lt;/code&gt; class. I initially named the folder &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RecipeParser_ParseWebsites&lt;/code&gt;. When I renamed it to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HtmlRecipePages&lt;/code&gt; it opened the possibility to use the HTML websites for testing:&lt;/p&gt;

  &lt;ul&gt;
    &lt;li&gt;HTML validation&lt;/li&gt;
    &lt;li&gt;encoding detection&lt;/li&gt;
    &lt;li&gt;recipe text detection&lt;/li&gt;
    &lt;li&gt;ingredient detection&lt;/li&gt;
    &lt;li&gt;etc.&lt;/li&gt;
  &lt;/ul&gt;

  &lt;p&gt;Names matter. Use good ones.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;3-third-level-folders-represent-the-data-cases&quot;&gt;3. Third level folders represent the data cases&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;/data/2019-09-03-data-driven-tests-tips-and-tricks-part1/folderstructure-thirdlevel.png&quot; alt=&quot;third level folders in data-driven tests&quot; /&gt;&lt;/p&gt;

&lt;p&gt;This level is the easiest to explain. Each bug, test case has its folder. It should also have a name representing the problem that it tests.&lt;/p&gt;

&lt;h2 id=&quot;4-dont-be-afraid-to-add-additional-grouping-folders&quot;&gt;4. Don’t be afraid to add additional grouping folders&lt;/h2&gt;

&lt;p&gt;I don’t like to have many folders in the solution tree, so I group them. If this is also your preference, remember that the grouping key should be simple and easy to understand. 
Some that I used:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;a website domain name&lt;/li&gt;
  &lt;li&gt;name of the client that encountered the error&lt;/li&gt;
  &lt;li&gt;application version&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Anything will do as long as it is &lt;strong&gt;simple to explain and intuitive&lt;/strong&gt;.&lt;/p&gt;

&lt;h1 id=&quot;file-tips&quot;&gt;File tips&lt;/h1&gt;

&lt;h2 id=&quot;1-use-proper-file-types&quot;&gt;1. Use proper file types.&lt;/h2&gt;

&lt;p&gt;JSON is the go-to format because of readability, and ease of import/export. Some rules make working with them easier:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Consistent formatting.&lt;/strong&gt; As we said, most of our data files will come from system usage. Those files should not be saved with formatting (it is a nontrivial overhead). 
The formatting should be applied when such file is used in tests. Define a convention, or better yet a tool that will do the formatting. It is good to have them for data files for the same reason why we have them for code files - &lt;em&gt;people will argue over them&lt;/em&gt;. I, personally, use the VS Code for formatting.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Consistent encoding.&lt;/strong&gt; A very similar problem as the one above. It is obvious to use the same encoding for one dataset, but we need to have the same for ALL data files.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Not only JSON.&lt;/strong&gt; Some data types are just perfect for tabular files formats like CSV, TSV, etc. For reading them, I recommend &lt;a href=&quot;https://joshclose.github.io/CsvHelper/&quot;&gt;CsvHelper&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Remove not important fields.&lt;/strong&gt; We don’t always have a perfectly logged object. When using a data file from production,  analyze the properties, and remove the unnecessary ones. Remember, tests should be optimized for readability. This also applies to test data.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Anonymize the data.&lt;/strong&gt; Don’t commit to the repo data files that contain sensitive or personal data. Once you identify the problem anonymize the data file.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;json-tips&quot;&gt;JSON tips&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;1 object in one file.&lt;/strong&gt; Some tests will take in a collection of elements. Then it is tempting to have one JSON file with an array of objects. Don’t do it. JSON files aren’t easy to merge. Having big files is just asking for trouble. How to deal with this? I introduce a fourth level folder and save each object as a separate file:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;/data/2019-09-03-data-driven-tests-tips-and-tricks-part1/folderstructure_complex.png&quot; alt=&quot;fourth level folders in data-driven tests&quot; /&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Consistent formatting.&lt;/strong&gt; I know I am repeating myself, but this is important. Have consistent formatting&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;csvtsv-tips&quot;&gt;CSV/TSV tips&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Don’t use a comma as the separator.&lt;/strong&gt; Commas are used in numbers, texts and aren’t too visible when opening the file. What to use, then? I use a tab.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Set the culture explicitly for reading the file&lt;/strong&gt;. Culture on your machine may be different than the one on the build agent machine, or other developers. Set the culture explicitly and save yourself a lot of debugging. A sample using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CsvHelper&lt;/code&gt; NuGet package:&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;csvReader&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;nf&quot;&gt;CsvReader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reader&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;Configuration&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;CultureInfo&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CultureInfo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;CreateSpecificCulture&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;en-US&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;p&quot;&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;2-how-to-handle-large-files-in-data-driven-tests&quot;&gt;2. How to handle large files in data-driven tests&lt;/h2&gt;

&lt;p&gt;Large files or a large number of files can be a problem because they will significantly increase the repo size making Git slower. Here we have two equally good solutions:&lt;/p&gt;

&lt;h3 id=&quot;21-use-git-lfs-git-large-file-storage&quot;&gt;2.1. Use Git LFS (Git &lt;strong&gt;L&lt;/strong&gt;arge &lt;strong&gt;F&lt;/strong&gt;ile &lt;strong&gt;S&lt;/strong&gt;torage)&lt;/h3&gt;

&lt;p&gt;Git LFS was designed to store nontext or large files. Files stored using &lt;a href=&quot;https://git-lfs.github.com/&quot;&gt;Git LFS&lt;/a&gt; are visible ass regular files in the repository, but changes to them aren’t tracked using the standard git diff mechanism. When cloning the repository with Git LFS, we will only get the latest version of the file, saving us a lot of disk space. Sound awesome. And for most cases it is. But it has some drawbacks:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Requires support on the git server.&lt;/strong&gt; Git server has to support Git LFS. Most online providers do, but some older on-premise solutions might not.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Requires an extension on every developer machine.&lt;/strong&gt; Each developer has to install Git LFS. Without the extension, we will see text pointers to Git LFS files.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;22-use-git-submodules&quot;&gt;2.2. Use Git submodules&lt;/h3&gt;

&lt;p&gt;Git LFS is fantastic, but for text files, we might still prefer the usual git way. What then? The answer is to use Git, but put the files in a separate repository that will only contain data files. Then add that repository to the code repository using a submodule:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-cmd&quot;&gt;git submodule add GIT_REPOSITORY_URL
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This call will clone the data repository to a folder inside our standard repository.&lt;/p&gt;

&lt;p&gt;When cloning the code repository, we only need to add one flag to the clone call (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--recurse-submodules&lt;/code&gt;):&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-cmd&quot;&gt;git clone --recurse-submodules
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This approach has some significant benefits:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Easy to share&lt;/strong&gt;. Because it is a separate repository, it can be used as a normal repository or used as a submodule in other repositories.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Separate versioning.&lt;/strong&gt; The code repository links to the specific commit in the data repository. Versioning them separately can be handy when we are getting test case data from an external source and may not be in control of the structure.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;this-is-not-the-end&quot;&gt;This is not the end.&lt;/h1&gt;

&lt;p&gt;Jekyll doesn’t like long posts (I learned it the hard way with &lt;a href=&quot;/Choosing-centralized-logging-and-monitoring-system/&quot;&gt;this one&lt;/a&gt;), and I also feel this is a good moment to break this post. To be continued …&lt;/p&gt;
</description>
        <pubDate>Tue, 03 Sep 2019 00:00:00 +0200</pubDate>
        <link>https://IndexOutOfRange.com//data-driven-tests-tips-and-tricks-part1/</link>
        <guid isPermaLink="true">https://IndexOutOfRange.com//data-driven-tests-tips-and-tricks-part1/</guid>
      </item>
    
      <item>
        <title>How to get data for Data-Driven Tests?</title>
        <description>&lt;img src='https://indexoutofrange.com/data/2019-08-27-where-to-get-data-for-data-driven-tests/logo.jpg' /&gt;&lt;p&gt;The &lt;a href=&quot;/refactoring-to-data-driven-tests/&quot;&gt;previous post&lt;/a&gt; was meant to be an encouragement and a warmup to data-driven testing. This post describes why I love this way of testing.
Understanding a simple fact about testing moved me from “Oh, I should write tests” to &lt;a href=&quot;https://www.youtube.com/watch?v=hFDcoX7s6rE&amp;amp;feature=youtu.be&amp;amp;t=6&quot;&gt;“I want it all! And I want it now!”&lt;/a&gt; and Data-Driven Testing.
And the simple truth is:
&lt;!--MORE--&gt;&lt;/p&gt;

&lt;h1 id=&quot;before-we-begin&quot;&gt;Before we begin&lt;/h1&gt;

&lt;p&gt;I will be converting this series into an ebook, or something like that, with additional source code and examples. If You want to get it please subscribe:&lt;/p&gt;

&lt;!-- Begin MailChimp Signup Form --&gt;

&lt;link href=&quot;//cdn-images.mailchimp.com/embedcode/horizontal-slim-10_7.css&quot; rel=&quot;stylesheet&quot; type=&quot;text/css&quot; /&gt;

&lt;style type=&quot;text/css&quot;&gt;
	#mc_embed_signup{
        clear:left; 
        font:14px Helvetica,Arial,sans-serif; 
        width:100%; 
        margin-top: 40px;
        margin-bottom: 40px;
        height:100px;
    }
    #mc_embed_signup .newsletter div{
        height: 100px;
    }
    #mc_embed_signup form{
        position: relative;
        top: -90px;
    }
	/* Add your own MailChimp form style overrides in your site stylesheet or in this style block.
	   We recommend moving this block and the preceding CSS link to the HEAD of your HTML file. */
&lt;/style&gt;

&lt;div id=&quot;mc_embed_signup&quot;&gt;
    &lt;div class=&quot;gradient newsletter&quot;&gt;
        &lt;div style=&quot;background:#000000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#1C0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#380000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#550000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#710000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#8D0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#AA0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#C60000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#E20000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF3800&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF5500&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF7100&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF8D00&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFAA00&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFC600&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFE200&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFFF00&quot;&gt;&lt;/div&gt;
    &lt;/div&gt;
    &lt;form action=&quot;https://IndexOutOfRange.us15.list-manage.com/subscribe/post?u=b1c1099bf7f49b95c64107c99&amp;amp;id=6a5eb68eb7&quot; method=&quot;post&quot; id=&quot;mc-embedded-subscribe-form&quot; name=&quot;mc-embedded-subscribe-form&quot; class=&quot;validate&quot; target=&quot;_blank&quot; novalidate=&quot;&quot;&gt;
        &lt;div id=&quot;mc_embed_signup_scroll&quot;&gt;
        &lt;label for=&quot;mce-EMAIL&quot; style=&quot;color: white;&quot;&gt;Get email notifications about new posts:&lt;/label&gt;
        &lt;input type=&quot;email&quot; value=&quot;&quot; name=&quot;EMAIL&quot; class=&quot;email&quot; id=&quot;mce-EMAIL&quot; placeholder=&quot;email address&quot; required=&quot;&quot; /&gt;
        &lt;!-- real people should not fill this in and expect good things - do not remove this or risk form bot signups--&gt;
        &lt;div style=&quot;position: absolute; left: -5000px;&quot; aria-hidden=&quot;true&quot;&gt;&lt;input type=&quot;text&quot; name=&quot;b_b1c1099bf7f49b95c64107c99_6a5eb68eb7&quot; tabindex=&quot;-1&quot; value=&quot;&quot; /&gt;&lt;/div&gt;
        &lt;div class=&quot;clear&quot;&gt;&lt;input type=&quot;submit&quot; value=&quot;Subscribe&quot; name=&quot;subscribe&quot; id=&quot;mc-embedded-subscribe&quot; class=&quot;button&quot; /&gt;&lt;/div&gt;
        &lt;/div&gt;
    &lt;/form&gt;
&lt;/div&gt;

&lt;!--End mc_embed_signup--&gt;

&lt;h1 id=&quot;data-is-the-king&quot;&gt;Data is the king&lt;/h1&gt;

&lt;p&gt;Anyone who is a bit interested in machine learning heard statements like &lt;em&gt;data is the king&lt;/em&gt;, &lt;em&gt;data is the new oil&lt;/em&gt;, etc. The same applies to tests. Having tests provides very little value. Having tests with &lt;strong&gt;the right test data provides huge value&lt;/strong&gt;. Let me explain. &lt;a href=&quot;/refactoring-to-data-driven-tests/&quot;&gt;Previously&lt;/a&gt; I wrote that I don’t like writing tests. Writing tests is one of two:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;It is a verification of the quality of the code you produced.&lt;/li&gt;
  &lt;li&gt;Or can be the verification of the skill in hacking using mocks, stubs, and fakes you poses.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Pick one.
I will concentrate on the first option. In it, writing tests is fun and engaging. It requires a lot of rethinking of previous assumptions, has a very short feedback loop, and gives a feeling of satisfaction. Fun and awesome.&lt;/p&gt;

&lt;p&gt;The part that drains my mental energy the most is producing test cases and test data. This part is:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;boring.&lt;/li&gt;
  &lt;li&gt;doesn’t require significant thought.&lt;/li&gt;
  &lt;li&gt;in most cases is copying previous data and changing one variable.&lt;/li&gt;
  &lt;li&gt;repetitive&lt;/li&gt;
  &lt;li&gt;doesn’t give any feeling satisfaction&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All the above reasons made me try most auto testing approaches in the .net ecosystem with the biggest hopes for &lt;a href=&quot;https://www.microsoft.com/en-us/research/publication/pex-white-box-test-generation-for-net/&quot;&gt;Pex&lt;/a&gt;
But, like most Microsoft products, it died. And for a good reason. It approached producing testing data from the wrong angle. It analyzed the code and found edge cases. Sounds reasonable - this is how we write tests and why we write tests. To test the edge cases. 
But is it how we should write tests? No! Writing tests this way is just duplicating the conditions from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;if&lt;/code&gt;s, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;switch&lt;/code&gt;es,  etc. We end up with tightly coupled, made-up tests.&lt;/p&gt;

&lt;p&gt;I am not saying that such tests aren’t necessary. They are useful. But only initially, the first verification.
Once we verified that the code is working, or we want to test more complex logic, they become too expensive. Time invested in them produces a minimal gain. It makes no think of the data that will cover all paths.
But we need the data to test the code. How to get it?&lt;/p&gt;

&lt;h1 id=&quot;how-to-get-test-data&quot;&gt;How to get test data&lt;/h1&gt;

&lt;p&gt;Where to get better test data? That is simple - from the users. A user of our code is a developer, a tester, or a triggered job that will call it. In this case&lt;/p&gt;

&lt;div class=&quot;center&quot;&gt;
    &lt;div class=&quot;button&quot;&gt;User = someone who uses our code.&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;All we need to do is to log the call data. This functionality can be already implemented or might require some tinkering in our app. Let’s examine a few usages.&lt;/p&gt;

&lt;h2 id=&quot;messages&quot;&gt;Messages&lt;/h2&gt;

&lt;p&gt;Some architectures are better than others for gathering data for data-driven tests. Message-based ones are near perfect. Most message systems have the notion of a dead letter queue - a queue that contains messages that failed to process (thrown an exception). The dead letter queue makes for a perfect input to our data-driven tests.
If we want to have a better correlation of the message and the exception or wish to have all the data in logs, we might do something like this:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&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;MyHandler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MyMessage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;{&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;cm&quot;&gt;/*
    initization code etc...
    */&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt;    &lt;/span&gt;
&lt;span class=&quot;err&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Task&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Handle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MyMessage&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;){&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;try&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;// message handling logic here&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;catch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Exception&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;err&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;messageJson&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;JsonConverter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;SerializeObject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;//the call failed, but we have access to the message that coused the error.&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_logger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;LogFailedMessages&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;messageJson&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&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;err&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;throw&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;c1&quot;&gt;//we need to throw to mark the message as failed so it is retries or put into dead letter queue.&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;err&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;/div&gt;

&lt;p&gt;The above is a very simplified implementation designed to show the idea, so please don’t use it on production. A better way to implement it is to hook this code in the code calling the handlers.&lt;/p&gt;

&lt;!-- Begin MailChimp Signup Form --&gt;

&lt;link href=&quot;//cdn-images.mailchimp.com/embedcode/horizontal-slim-10_7.css&quot; rel=&quot;stylesheet&quot; type=&quot;text/css&quot; /&gt;

&lt;style type=&quot;text/css&quot;&gt;
	#mc_embed_signup{
        clear:left; 
        font:14px Helvetica,Arial,sans-serif; 
        width:100%; 
        margin-top: 40px;
        margin-bottom: 40px;
        height:100px;
    }
    #mc_embed_signup .newsletter div{
        height: 100px;
    }
    #mc_embed_signup form{
        position: relative;
        top: -90px;
    }
	/* Add your own MailChimp form style overrides in your site stylesheet or in this style block.
	   We recommend moving this block and the preceding CSS link to the HEAD of your HTML file. */
&lt;/style&gt;

&lt;div id=&quot;mc_embed_signup&quot;&gt;
    &lt;div class=&quot;gradient newsletter&quot;&gt;
        &lt;div style=&quot;background:#000000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#1C0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#380000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#550000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#710000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#8D0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#AA0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#C60000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#E20000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF3800&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF5500&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF7100&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF8D00&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFAA00&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFC600&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFE200&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFFF00&quot;&gt;&lt;/div&gt;
    &lt;/div&gt;
    &lt;form action=&quot;https://IndexOutOfRange.us15.list-manage.com/subscribe/post?u=b1c1099bf7f49b95c64107c99&amp;amp;id=6a5eb68eb7&quot; method=&quot;post&quot; id=&quot;mc-embedded-subscribe-form&quot; name=&quot;mc-embedded-subscribe-form&quot; class=&quot;validate&quot; target=&quot;_blank&quot; novalidate=&quot;&quot;&gt;
        &lt;div id=&quot;mc_embed_signup_scroll&quot;&gt;
        &lt;label for=&quot;mce-EMAIL&quot; style=&quot;color: white;&quot;&gt;Get email notifications about new posts:&lt;/label&gt;
        &lt;input type=&quot;email&quot; value=&quot;&quot; name=&quot;EMAIL&quot; class=&quot;email&quot; id=&quot;mce-EMAIL&quot; placeholder=&quot;email address&quot; required=&quot;&quot; /&gt;
        &lt;!-- real people should not fill this in and expect good things - do not remove this or risk form bot signups--&gt;
        &lt;div style=&quot;position: absolute; left: -5000px;&quot; aria-hidden=&quot;true&quot;&gt;&lt;input type=&quot;text&quot; name=&quot;b_b1c1099bf7f49b95c64107c99_6a5eb68eb7&quot; tabindex=&quot;-1&quot; value=&quot;&quot; /&gt;&lt;/div&gt;
        &lt;div class=&quot;clear&quot;&gt;&lt;input type=&quot;submit&quot; value=&quot;Subscribe&quot; name=&quot;subscribe&quot; id=&quot;mc-embedded-subscribe&quot; class=&quot;button&quot; /&gt;&lt;/div&gt;
        &lt;/div&gt;
    &lt;/form&gt;
&lt;/div&gt;

&lt;!--End mc_embed_signup--&gt;

&lt;h2 id=&quot;asynchronous-processing&quot;&gt;Asynchronous processing&lt;/h2&gt;

&lt;p&gt;A simplified bit easier to implement approach is to use async processing. I don’t mean the use of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async&lt;/code&gt; keywords in controllers, but splitting the business process into asynchronous jobs that can be processed later.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Example: We register the user, but create a job that will send the confirmation email.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For this I use Hangfire.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;A shameless plug: I wrote a &lt;a href=&quot;/Don't-do-it-now!-Part-2.-Background-tasks,-job-queuing-and-scheduling-with-Hangfire/&quot;&gt;series of articles on Hangfire and how it works&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It makes it even simpler than messaging. Hangfire displays execution parameters with the thrown error in the Hangfire dashboard:&lt;/p&gt;

&lt;center&gt;
 &lt;img alt=&quot;Hangfire&quot; src=&quot;/data/2019-08-27-where-to-get-data-for-data-driven-tests/hangfire.png&quot; /&gt;
&lt;/center&gt;

&lt;h2 id=&quot;mvcwebapi&quot;&gt;MVC/WebApi&lt;/h2&gt;

&lt;p&gt;Http calls make it more tricky, but still possible. The same try/catch logic can be implemented in the controller methods directly, but a more general solution is to have a global filter. 
Something like this:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&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;MyErrorFilter&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IActionFilter&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;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;OnActionExecuted&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ActionExecutedContext&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&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;context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Exception&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;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ExceptionHandled&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;// get data from context.HttpContext.Request&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;/div&gt;

&lt;p&gt;The code above is not for production use. Especially since HTTP calls logging requires considering a few additional things:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;You have to filter our typical HTTP errors (404, 400, etc.)&lt;/li&gt;
  &lt;li&gt;If the website is public, you will get a ton of automated scans looking for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/phpadmin&lt;/code&gt; and some injection attempts. Those have to be filtered out.&lt;/li&gt;
  &lt;li&gt;HTTP requests, more often than the previous, contain sensitive data such as user and password, cookie values, etc. &lt;strong&gt;Don’t log those. Never.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Logging on this controller level has one significant disadvantage when compared to the previous options. Unit and data-driven testing for controllers is hard. 
How to do it better?&lt;/p&gt;

&lt;h3 id=&quot;log-on-business-methods-level&quot;&gt;Log on business methods level&lt;/h3&gt;

&lt;p&gt;The more pinpointed the logging, the better. Ideally, every vital method that has a data-driven test should be logging call data. Here, we might encounter the &lt;strong&gt;banana problem&lt;/strong&gt;.&lt;/p&gt;

&lt;center&gt;
 &lt;img alt=&quot;you wanted a banana but what you got was a gorilla holding the banana and the entire jungle&quot; src=&quot;/data/2019-08-27-where-to-get-data-for-data-driven-tests/gorilla.png&quot; /&gt;
&lt;/center&gt;

&lt;p&gt;Trying to serialize &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HTTPContext&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DBContext&lt;/code&gt; or anything with lazy loading might result in us trying to serialize the whole application world. 
Not passing such objects is a good codding practice. Simple and narrowed down classes are better anyway.&lt;/p&gt;

&lt;h1 id=&quot;things-to-consider-when-logging-input-parameters-for-data-driven-tests&quot;&gt;Things to consider when logging input parameters for data-driven tests:&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Sensitive data.&lt;/strong&gt; Logs are very often treated with not the same care as the database. Adding input data logging means that they should be. They will contain important data.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;GDPR.&lt;/strong&gt; Adding such logging, we are adding yet another place to monitor for user data.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Data size.&lt;/strong&gt; It is very easy to create tens of thousands of such logs. Filter them out and fix fast.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Not a silver bullet.&lt;/strong&gt; This approach requires architecture changes. Just dropping it into an application with global state won’t provide to much value.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Performance.&lt;/strong&gt; We are logging only in case of a failure. Why care about response timings so much? The user won’t be happy anyways. What if the user is not human and we are getting thousands of such errors a second? Logging is making our situation just worse. Be careful, notify Your Ops team.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Just logging is not enough.&lt;/strong&gt; Only logging won’t make your system better. Logging is so that it is easier to fix the bugs. Don’t forget about that.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;creating-data-driven-tests&quot;&gt;Creating data-driven tests&lt;/h1&gt;

&lt;p&gt;I have the data now what?&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Format it. Remember, &lt;a href=&quot;/refactoring-to-data-driven-tests/&quot;&gt;tests should be optimized for readability.&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Save it to a special directory&lt;/li&gt;
  &lt;li&gt;Read it and use it in a test.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Remember the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TestCaseSourceAttribute&lt;/code&gt; from the &lt;a href=&quot;2019-08-20-refactoring-to-data-driven-tests&quot;&gt;previous article&lt;/a&gt;? Just change it into something like this:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&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;n&quot;&gt;TestCaseData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;GetData&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;retArray&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Directory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetDirectories&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;MyTestDataFolder&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;*&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SearchOption&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AllDirectories&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;nf&quot;&gt;OrderBy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&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;nf&quot;&gt;Select&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&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;ret&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;nf&quot;&gt;TestCaseData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;JsonConverter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;DeserializeObject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;testdata.json&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ExpectedResult&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;JsonConverter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;DeserializeObject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;expectedResult.json&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;SetName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;FolderName&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;ret&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;nf&quot;&gt;ToArray&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;retArray&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;/div&gt;

&lt;p&gt;Some assumption:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Each test is in a separate folder.&lt;/li&gt;
  &lt;li&gt;The name of the folder describes the test case.&lt;/li&gt;
  &lt;li&gt;Each folder has a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;testdata.json&lt;/code&gt; file containing the test data object.&lt;/li&gt;
  &lt;li&gt;Each folder has an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;expectedResult.json&lt;/code&gt; file containing the expected result object.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;p&gt;I started with the intention to write a tips and tricks entry, but after a few conversations, I saw that a part about gathering data is missing. I promise tips, tricks and good practices are next! If you don’t want to miss it, subscribe to the &lt;a href=&quot;https://indexoutofrange.us15.list-manage.com/subscribe/post?u=b1c1099bf7f49b95c64107c99&amp;amp;id=6a5eb68eb7&quot;&gt;newsletter&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
</description>
        <pubDate>Tue, 27 Aug 2019 00:00:00 +0200</pubDate>
        <link>https://IndexOutOfRange.com//where-to-get-data-for-data-driven-tests/</link>
        <guid isPermaLink="true">https://IndexOutOfRange.com//where-to-get-data-for-data-driven-tests/</guid>
      </item>
    
      <item>
        <title>Refactoring to Data Driven Tests</title>
        <description>&lt;img src='https://indexoutofrange.com/data/2019-08-20-refactoring-to-data-driven-tests/logo.jpg' /&gt;&lt;p&gt;I am not a big fan of writing tests. I like having them, but I find writing them to be boring. That said, retesting manually is even more annoying, so I write tests. The thought that there has to be a better way, never passed. I tried a few approaches. After some experimentation, I think I have the answer - DDT (&lt;strong&gt;D&lt;/strong&gt;ata &lt;strong&gt;D&lt;/strong&gt;riven &lt;strong&gt;T&lt;/strong&gt;esting)&lt;/p&gt;

&lt;!--MORE--&gt;

&lt;h1 id=&quot;before-we-begin&quot;&gt;Before we begin&lt;/h1&gt;

&lt;p&gt;I will be converting this series into an ebook, or something like that, with additional source code and examples. If You want to get it please subscribe:&lt;/p&gt;

&lt;!-- Begin MailChimp Signup Form --&gt;

&lt;link href=&quot;//cdn-images.mailchimp.com/embedcode/horizontal-slim-10_7.css&quot; rel=&quot;stylesheet&quot; type=&quot;text/css&quot; /&gt;

&lt;style type=&quot;text/css&quot;&gt;
	#mc_embed_signup{
        clear:left; 
        font:14px Helvetica,Arial,sans-serif; 
        width:100%; 
        margin-top: 40px;
        margin-bottom: 40px;
        height:100px;
    }
    #mc_embed_signup .newsletter div{
        height: 100px;
    }
    #mc_embed_signup form{
        position: relative;
        top: -90px;
    }
	/* Add your own MailChimp form style overrides in your site stylesheet or in this style block.
	   We recommend moving this block and the preceding CSS link to the HEAD of your HTML file. */
&lt;/style&gt;

&lt;div id=&quot;mc_embed_signup&quot;&gt;
    &lt;div class=&quot;gradient newsletter&quot;&gt;
        &lt;div style=&quot;background:#000000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#1C0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#380000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#550000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#710000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#8D0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#AA0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#C60000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#E20000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF3800&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF5500&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF7100&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF8D00&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFAA00&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFC600&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFE200&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFFF00&quot;&gt;&lt;/div&gt;
    &lt;/div&gt;
    &lt;form action=&quot;https://IndexOutOfRange.us15.list-manage.com/subscribe/post?u=b1c1099bf7f49b95c64107c99&amp;amp;id=6a5eb68eb7&quot; method=&quot;post&quot; id=&quot;mc-embedded-subscribe-form&quot; name=&quot;mc-embedded-subscribe-form&quot; class=&quot;validate&quot; target=&quot;_blank&quot; novalidate=&quot;&quot;&gt;
        &lt;div id=&quot;mc_embed_signup_scroll&quot;&gt;
        &lt;label for=&quot;mce-EMAIL&quot; style=&quot;color: white;&quot;&gt;Get email notifications about new posts:&lt;/label&gt;
        &lt;input type=&quot;email&quot; value=&quot;&quot; name=&quot;EMAIL&quot; class=&quot;email&quot; id=&quot;mce-EMAIL&quot; placeholder=&quot;email address&quot; required=&quot;&quot; /&gt;
        &lt;!-- real people should not fill this in and expect good things - do not remove this or risk form bot signups--&gt;
        &lt;div style=&quot;position: absolute; left: -5000px;&quot; aria-hidden=&quot;true&quot;&gt;&lt;input type=&quot;text&quot; name=&quot;b_b1c1099bf7f49b95c64107c99_6a5eb68eb7&quot; tabindex=&quot;-1&quot; value=&quot;&quot; /&gt;&lt;/div&gt;
        &lt;div class=&quot;clear&quot;&gt;&lt;input type=&quot;submit&quot; value=&quot;Subscribe&quot; name=&quot;subscribe&quot; id=&quot;mc-embedded-subscribe&quot; class=&quot;button&quot; /&gt;&lt;/div&gt;
        &lt;/div&gt;
    &lt;/form&gt;
&lt;/div&gt;

&lt;!--End mc_embed_signup--&gt;

&lt;h1 id=&quot;establishing-the-baseline&quot;&gt;Establishing the baseline&lt;/h1&gt;

&lt;p&gt;Before we dig into what Data Driven Tests are, let’s look at some standard, non-DDT tests.&lt;/p&gt;

&lt;h3 id=&quot;what-we-will-be-testing&quot;&gt;What we will be testing?&lt;/h3&gt;

&lt;blockquote&gt;
  &lt;p&gt;There is a fragile line for code examples. Too simple and they lose any business applicability. Too complicated and the domain overwhelms the problem described. Let me know if this problem works.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We will be testing an automatic gearbox controller for a car. This “simple” box decides when to change gear. Our version will get the following inputs:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Gear&lt;/li&gt;
  &lt;li&gt;Acceleration applied (values in the range of 0 to 1 in our example)&lt;/li&gt;
  &lt;li&gt;RPM (&lt;strong&gt;R&lt;/strong&gt;otations &lt;strong&gt;P&lt;/strong&gt;er &lt;strong&gt;M&lt;/strong&gt;inute), so how fast the engine is turning.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The return value is only one - the gear the engine should use. It sounds simple. Let’s see some tests.&lt;/p&gt;

&lt;h2 id=&quot;the-starting-point-no-data-driven-tests&quot;&gt;The starting point. No Data Driven Tests&lt;/h2&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&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;GearCalculatorTests&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;Test&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;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ShouldReduceGear_whenAcceleratingRapidlyOnLowRPM&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;//Arrange&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;initialGear&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rapidAcceleration&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0.7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;currentRpm&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;2000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

            &lt;span class=&quot;c1&quot;&gt;//Act&lt;/span&gt;
            &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gear&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;nf&quot;&gt;GearCalculator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Calculate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rapidAcceleration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;currentRpm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;initialGear&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

            &lt;span class=&quot;c1&quot;&gt;//Assert&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;nf&quot;&gt;AreEqual&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;initialGear&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;n&quot;&gt;gear&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;The gear should decrease by one&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;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Test&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;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ShouldNotReduceGearWhenOnFirstGear_whenAcceleratingRapidlyOnLowRPM&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;//Arrange&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;initialGear&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;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rapidAcceleration&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0.7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;currentRpm&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;2000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

            &lt;span class=&quot;c1&quot;&gt;//Act&lt;/span&gt;
            &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gear&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;nf&quot;&gt;GearCalculator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Calculate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rapidAcceleration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;currentRpm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;initialGear&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

            &lt;span class=&quot;c1&quot;&gt;//Assert&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;nf&quot;&gt;AreEqual&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;initialGear&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gear&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;The gear should stay the same&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;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Test&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;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ShouldNotReduceGear_whenAcceleratingNotRapidlyOnLowRPM&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;//Arrange &lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;initialGear&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nonRapidAcceleration&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0.4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;currentRpm&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;2000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

            &lt;span class=&quot;c1&quot;&gt;//Act&lt;/span&gt;
            &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gear&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;nf&quot;&gt;GearCalculator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Calculate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;nonRapidAcceleration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;currentRpm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;initialGear&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

            &lt;span class=&quot;c1&quot;&gt;//Assert&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;nf&quot;&gt;AreEqual&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;initialGear&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gear&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;The gear should stay the same&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;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;refactoring-to-data-driven-tests&quot;&gt;Refactoring to Data Driven Tests&lt;/h1&gt;

&lt;h2 id=&quot;what-are-data-driven-tests&quot;&gt;What are Data Driven Tests?&lt;/h2&gt;

&lt;p&gt;Not what we have some baseline, let’s define what a &lt;strong&gt;D&lt;/strong&gt;ata &lt;strong&gt;D&lt;/strong&gt;riven &lt;strong&gt;T&lt;/strong&gt;est is.&lt;/p&gt;

&lt;div class=&quot;center&quot;&gt;
    &lt;div class=&quot;button&quot;&gt;
        A &lt;b&gt;D&lt;/b&gt;ata &lt;b&gt;D&lt;/b&gt;riven &lt;b&gt;T&lt;/b&gt;est is a test where the &lt;b&gt;data is separated from the logic&lt;/b&gt;. 
    &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;It might sound obvious. We don’t mix data with code. Don’t we? Look at the tests above and try to recall if your tests aren’t splashed with a big dose of setup objects. They probably are.&lt;/p&gt;

&lt;p&gt;Some people argue saying that this is normal. &lt;em&gt;Test need testing data.&lt;/em&gt;
I am not saying they don’t. I’m saying that we should not couple test logic and test data so strongly. A few arguments to back up that statement:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Tests should always be optimized for readability&lt;/strong&gt;. Tests have a lot of boilerplate. Mocks, stubs, test data classes, mocked methods, etc. All this code makes it hard to know what is the boilerplate and what is the needed data. Therefore it makes the tests less readable.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Test cases should always be optimized for readability&lt;/strong&gt;. Again about readability? Yes, but in a different take. Let’s take two tests testing the &lt;em&gt;same class&lt;/em&gt;, but a different path. Let’s say they are a medium size test with ~100 effective lines of code. What will be the difference between those two tests? I’m betting below ten lines of code. That is 10%. Even if the tests are readable, &lt;em&gt;the difference between them is not&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The problem with tests like above is that new ones will be made by copying an old test and changing some lines (making the 10% changes). Lowering readability further on.
Now let’s refactor the above tests to Data Driven Tests.&lt;/p&gt;

&lt;!-- Begin MailChimp Signup Form --&gt;

&lt;link href=&quot;//cdn-images.mailchimp.com/embedcode/horizontal-slim-10_7.css&quot; rel=&quot;stylesheet&quot; type=&quot;text/css&quot; /&gt;

&lt;style type=&quot;text/css&quot;&gt;
	#mc_embed_signup{
        clear:left; 
        font:14px Helvetica,Arial,sans-serif; 
        width:100%; 
        margin-top: 40px;
        margin-bottom: 40px;
        height:100px;
    }
    #mc_embed_signup .newsletter div{
        height: 100px;
    }
    #mc_embed_signup form{
        position: relative;
        top: -90px;
    }
	/* Add your own MailChimp form style overrides in your site stylesheet or in this style block.
	   We recommend moving this block and the preceding CSS link to the HEAD of your HTML file. */
&lt;/style&gt;

&lt;div id=&quot;mc_embed_signup&quot;&gt;
    &lt;div class=&quot;gradient newsletter&quot;&gt;
        &lt;div style=&quot;background:#000000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#1C0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#380000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#550000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#710000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#8D0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#AA0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#C60000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#E20000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF3800&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF5500&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF7100&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF8D00&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFAA00&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFC600&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFE200&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFFF00&quot;&gt;&lt;/div&gt;
    &lt;/div&gt;
    &lt;form action=&quot;https://IndexOutOfRange.us15.list-manage.com/subscribe/post?u=b1c1099bf7f49b95c64107c99&amp;amp;id=6a5eb68eb7&quot; method=&quot;post&quot; id=&quot;mc-embedded-subscribe-form&quot; name=&quot;mc-embedded-subscribe-form&quot; class=&quot;validate&quot; target=&quot;_blank&quot; novalidate=&quot;&quot;&gt;
        &lt;div id=&quot;mc_embed_signup_scroll&quot;&gt;
        &lt;label for=&quot;mce-EMAIL&quot; style=&quot;color: white;&quot;&gt;Get email notifications about new posts:&lt;/label&gt;
        &lt;input type=&quot;email&quot; value=&quot;&quot; name=&quot;EMAIL&quot; class=&quot;email&quot; id=&quot;mce-EMAIL&quot; placeholder=&quot;email address&quot; required=&quot;&quot; /&gt;
        &lt;!-- real people should not fill this in and expect good things - do not remove this or risk form bot signups--&gt;
        &lt;div style=&quot;position: absolute; left: -5000px;&quot; aria-hidden=&quot;true&quot;&gt;&lt;input type=&quot;text&quot; name=&quot;b_b1c1099bf7f49b95c64107c99_6a5eb68eb7&quot; tabindex=&quot;-1&quot; value=&quot;&quot; /&gt;&lt;/div&gt;
        &lt;div class=&quot;clear&quot;&gt;&lt;input type=&quot;submit&quot; value=&quot;Subscribe&quot; name=&quot;subscribe&quot; id=&quot;mc-embedded-subscribe&quot; class=&quot;button&quot; /&gt;&lt;/div&gt;
        &lt;/div&gt;
    &lt;/form&gt;
&lt;/div&gt;

&lt;!--End mc_embed_signup--&gt;

&lt;h2 id=&quot;version-01-refactoring&quot;&gt;Version 0.1 Refactoring&lt;/h2&gt;

&lt;p&gt;The first step is to extract the data from the test code. Let’s put in into a function:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;CalculateAndVerifyGear&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;acceleration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;currentRpm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gear&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;expectedGear&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;){&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;//Act&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;calculatedGear&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;nf&quot;&gt;GearCalculator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Calculate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;acceleration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;currentRpm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gear&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;//Assert&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;nf&quot;&gt;AreEqual&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;expectedGear&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;calculatedGear&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;/div&gt;

&lt;p&gt;Now, to use it:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&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;GearCalculatorTests&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;Test&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;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ShouldReduceGear_whenAcceleratingRapidlyOnLowRPM&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;//Arrange&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;initialGear&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rapidAcceleration&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0.7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;currentRpm&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;2000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

            &lt;span class=&quot;nf&quot;&gt;CalculateAndVerifyGear&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rapidAcceleration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;currentRpm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;initialGear&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;initialGear&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;span class=&quot;n&quot;&gt;Test&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;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ShouldNotReduceGearWhenOnFirstGear_whenAcceleratingRapidlyOnLowRPM&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;//Arrange &lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;initialGear&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;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rapidAcceleration&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0.7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;currentRpm&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;2000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

            &lt;span class=&quot;nf&quot;&gt;CalculateAndVerifyGear&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rapidAcceleration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;currentRpm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;initialGear&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;initialGear&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;n&quot;&gt;Test&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;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ShouldNotReduceGear_whenAcceleratingNotRapidlyOnLowRPM&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;//Arrange&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;initialGear&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nonRapidAcceleration&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0.4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;currentRpm&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;2000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

            &lt;span class=&quot;nf&quot;&gt;CalculateAndVerifyGear&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;nonRapidAcceleration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;currentRpm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;initialGear&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;initialGear&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;/div&gt;

&lt;center&gt;
&lt;b&gt;This is the starting point. We will refactor it further on&lt;/b&gt;
&lt;/center&gt;

&lt;p&gt;The refactor has a few problems:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;We lost the assert message (it could be added to our version, but most tests have more than one assert. Passing many assert messages will make the test unreadable)&lt;/li&gt;
  &lt;li&gt;New tests will still be made by copying an old one and changing a few dials. Changes will be more visible, but this still isn’t good enough.&lt;/li&gt;
  &lt;li&gt;Test data still isn’t a first-class citizen.&lt;/li&gt;
  &lt;li&gt;When looking at those tests, I get the feeling that there should be a better way.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;version-02---making-test-data-a-first-class-citizen&quot;&gt;Version 0.2 - Making test data a first-class citizen&lt;/h2&gt;

&lt;p&gt;There are a few ways the problems mentioned above can be addressed. We will go over them one by one.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;From here on we will use NUnit. If You prefer XUnit or any other testing framework, check the documentation. It probably supports Data Driven Testing.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The first way is to use a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TestCase&lt;/code&gt; attribute. It allows to pass parameters to tests. After refactoring the code will look like this:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&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;GearCalculatorTests&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;nf&quot;&gt;TestCase&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0.7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;2000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Description&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;When accelerating rapidly on low RPM should reduce gear &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;nf&quot;&gt;TestCase&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0.7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;2000&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;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Description&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;When accelerating rapidly on low RPM should not reduce gear when on first gear &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;nf&quot;&gt;TestCase&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0.4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;2000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Description&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;When accelerating NOT rapidly on low RPM should not reduce gear&quot;&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;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;CalculateAndVerifyGear&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;acceleration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;currentRpm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gear&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;expectedGear&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;//Act&lt;/span&gt;
            &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;calculatedGear&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;nf&quot;&gt;GearCalculator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Calculate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;acceleration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;currentRpm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gear&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

            &lt;span class=&quot;c1&quot;&gt;//Assert&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;nf&quot;&gt;AreEqual&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;expectedGear&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;calculatedGear&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;/div&gt;

&lt;p&gt;Yes, that is all. Initial 45 lines of tests now take 15 lines of code and are more readable. Now I see that I could remove the current RPM from the tests data because it never changes.&lt;/p&gt;

&lt;p&gt;This approach is better than what we started with, but has some drawbacks:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Attributes can only have parameters that are known on compile time.&lt;/li&gt;
  &lt;li&gt;We can’t pass complex objects to attributes.&lt;/li&gt;
  &lt;li&gt;There are no compile-time checks for the wrong number of parameters (Resharper will show a warning).&lt;/li&gt;
  &lt;li&gt;Values in attributes aren’t that readable.&lt;/li&gt;
  &lt;li&gt;Having four attributes is OK, but more of them will be messy.&lt;/li&gt;
  &lt;li&gt;It is hard to read what we are asserting.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s first address the last point.&lt;/p&gt;

&lt;h2 id=&quot;version-025---better-asserts&quot;&gt;Version 0.2.5 - Better asserts&lt;/h2&gt;

&lt;p&gt;To better express what we are asserting, we can use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ExpectedResult&lt;/code&gt; from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TestCaseAttribute&lt;/code&gt;. After refactoring it will look like this:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;TestCase&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0.7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;2000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ExpectedResult&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Description&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;When accelerating rapidly on low RPM should reduce gear &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;nf&quot;&gt;TestCase&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0.7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;2000&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;n&quot;&gt;ExpectedResult&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;n&quot;&gt;Description&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;When accelerating rapidly on low RPM should not reduce gear when on first gear &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;nf&quot;&gt;TestCase&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0.4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;2000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ExpectedResult&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Description&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;When accelerating NOT rapidly on low RPM should not reduce gear&quot;&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;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;CalculateAndVerifyGear&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;acceleration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;currentRpm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gear&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;//Act&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;GearCalculator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Calculate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;acceleration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;currentRpm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gear&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;/div&gt;

&lt;p&gt;How this works:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;now our test returns a value.&lt;/li&gt;
  &lt;li&gt;this value will be compared with the value of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ExpectedResult&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It is a bit better, but we still have to address drawbacks 1-4.&lt;/p&gt;

&lt;h2 id=&quot;version-03---testdatasourceattribute&quot;&gt;Version 0.3 - TestDataSourceAttribute&lt;/h2&gt;

&lt;p&gt;We can adress most of the drawbacks by using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TestDataSourceAttribute&lt;/code&gt;. This attribute allows defines a method that will generate test cases by creating a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TestCaseData&lt;/code&gt; objects. Let’s see it in action and explain later:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&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;GearCalculatorTests&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;n&quot;&gt;TestCaseData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TestDataSource&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;return&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;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;TestCaseData&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;nf&quot;&gt;GearBoxTestData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0.7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;2000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;5&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;ExpectedResult&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TestName&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;When accelerating rapidly on low RPM should reduce gear &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;nf&quot;&gt;TestCaseData&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;nf&quot;&gt;GearBoxTestData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0.7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;2000&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;ExpectedResult&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;n&quot;&gt;TestName&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;When accelerating rapidly on low RPM should not reduce gear when on first gear &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;nf&quot;&gt;TestCaseData&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;nf&quot;&gt;GearBoxTestData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0.4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;2000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;5&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;ExpectedResult&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TestName&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;When accelerating NOT rapidly on low RPM should not reduce gear&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;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;nf&quot;&gt;TestCaseSource&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;nameof&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TestDataSource&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;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;CalculateAndVerifyGear&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GearBoxTestData&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&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;//Act&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;GearCalculator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Calculate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Acceleration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Rpm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Gear&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;GearBoxTestData&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;GearBoxTestData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;acceleration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rpm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gear&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;Acceleration&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;acceleration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;Rpm&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rpm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;Gear&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gear&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;kt&quot;&gt;double&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Acceleration&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;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Rpm&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;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Gear&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;/div&gt;

&lt;p&gt;A few things to note:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;We could also pass parameters the same way as with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TestCase&lt;/code&gt;, but not using the power of dedicated class would be a waste of potential.&lt;/li&gt;
  &lt;li&gt;Notice that the method has to be &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;static&lt;/code&gt;. Why? Because this generates separate tests for each &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TestCaseData&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;How this works is that a test runner first calls the method defined in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TestCaseSourceAttribute&lt;/code&gt; and generates tests based on data returned. Each &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TestCaseData&lt;/code&gt; will be seen as a separate test:&lt;/p&gt;

&lt;center&gt;
 &lt;img alt=&quot;Resharper data driven tests&quot; src=&quot;/data/2019-08-20-refactoring-to-data-driven-tests/Resharper.png&quot; /&gt;
&lt;/center&gt;
&lt;p&gt;Depending on the runner, each test can be debugged separately. They behave just like any other tests.&lt;/p&gt;

&lt;h1 id=&quot;is-this-the-end&quot;&gt;Is this the end?&lt;/h1&gt;

&lt;p&gt;No. But this post is long enough as an introduction. Following tips and tricks.&lt;/p&gt;
</description>
        <pubDate>Tue, 20 Aug 2019 00:00:00 +0200</pubDate>
        <link>https://IndexOutOfRange.com//refactoring-to-data-driven-tests/</link>
        <guid isPermaLink="true">https://IndexOutOfRange.com//refactoring-to-data-driven-tests/</guid>
      </item>
    
      <item>
        <title>How to choose the partition key</title>
        <description>&lt;img src='https://indexoutofrange.com/data/2019-08-13-how-to-choose-a-partition-key/logo.jpg' /&gt;&lt;p&gt;NoSQL PaaS databases like AWS DynamoDB or Cosmos DB offer incredible capabilities in scale, speed, and availability. There is also a dark side to those databases. They will punish anyone greatly for mistakes. And no mistakes are punished more than choosing the wrong partition key. Below is an ORDERED list on how to approach selecting the partition key.&lt;/p&gt;

&lt;!--MORE--&gt;

&lt;h2 id=&quot;1-transaction-boundary&quot;&gt;1. Transaction boundary&lt;/h2&gt;

&lt;p&gt;I can’t stress this enough.&lt;/p&gt;

&lt;div class=&quot;center&quot;&gt;
    &lt;div class=&quot;button&quot;&gt;This is the most critical factor. If our transaction boundary is wrong, please don’t even think about using this partition key.
    &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Now to elaborate.&lt;/p&gt;

&lt;p&gt;In Cosmos DB and DynamoDB partition is the transaction boundary. An operation performed over records with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;N&lt;/code&gt; partition keys (and so in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;N&lt;/code&gt; partitions) is split into &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;N&lt;/code&gt; separate transactions. 
Each partition transaction can fail or succeed independently with no rollback of the primary transaction.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If some operations fail, the changes to other partitions won’t be rollbacked.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;There is no way around this limitation.&lt;/p&gt;

&lt;p&gt;Why is this requirement so essential? We have to take into account a few limitations:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Both databases have minimal capabilities for multi-operation transactions (Cosmos DB supports them only in &lt;a href=&quot;https://docs.microsoft.com/pl-pl/azure/cosmos-db/database-transactions-optimistic-concurrency#multi-item-transactions&quot;&gt;stored procedures, pre/post triggers, user-defined-functions (UDFs)&lt;/a&gt;).&lt;/li&gt;
  &lt;li&gt;We don’t have transaction isolation levels like in relational databases.&lt;/li&gt;
  &lt;li&gt;There is no option to lock a record for editing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The above limitations mean that we will encounter a lot more cases when data changed between our operations.
To not override data Cosmos DB and DynamoDB uses optimistic locking. It guarantees that the application will know that some changes weren’t applied, but won’t prevent data inconsistency.&lt;/p&gt;

&lt;p&gt;Therefore not platform failure, but changes executed between operations will be the main reason why we might want to revert changes.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;I wrote how to simulate transaction isolation on noSQL databases in the &lt;a href=&quot;/Modeling-version-and-temporary-state-in-noSQL-databases/&quot;&gt;previous post&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;2-size-limitation&quot;&gt;2. Size limitation&lt;/h2&gt;

&lt;p&gt;The obvious solution to the lack of transactionality over multiple partition keys is to store everything in one partition. 
Not so fast. Cosmos DB and DynamoDB have a &lt;strong&gt;hard limit on partition size - 10 GB&lt;/strong&gt;. (&lt;a href=&quot;https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/LSI.html#LSI.ItemCollections.SizeLimit&quot;&gt;DynamoDB&lt;/a&gt;, &lt;a href=&quot;https://docs.microsoft.com/en-us/azure/cosmos-db/partitioning-overview&quot;&gt;CosmosDB&lt;/a&gt;).
Making matters worse, this is not a limit only on data, but all the things around it like indexes. 
When the limit is reached, all operations increasing the partition size will fail.
As with the transaction boundary, this is a hard limit, and can’t be changed.&lt;/p&gt;

&lt;h2 id=&quot;3-partition-key-values-cant-be-updated&quot;&gt;3. Partition key values can’t be updated&lt;/h2&gt;

&lt;p&gt;When creating a table/collection, we have to define a path to the property which value will be used as the partition id.
Selecting a property as the partition adds some additional requirements on it. There are some type and size limitations, but most importantly, this property has to be present in every document in the collection/table.&lt;/p&gt;

&lt;p&gt;From the application logic, it is just like any other required property. With one exception:&lt;/p&gt;

&lt;div class=&quot;center&quot;&gt;
    &lt;div class=&quot;button&quot;&gt;&lt;b&gt;Values of properties designated as partition keys can't be changed.&lt;/b&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Why?&lt;/p&gt;

&lt;!-- Begin MailChimp Signup Form --&gt;

&lt;link href=&quot;//cdn-images.mailchimp.com/embedcode/horizontal-slim-10_7.css&quot; rel=&quot;stylesheet&quot; type=&quot;text/css&quot; /&gt;

&lt;style type=&quot;text/css&quot;&gt;
	#mc_embed_signup{
        clear:left; 
        font:14px Helvetica,Arial,sans-serif; 
        width:100%; 
        margin-top: 40px;
        margin-bottom: 40px;
        height:100px;
    }
    #mc_embed_signup .newsletter div{
        height: 100px;
    }
    #mc_embed_signup form{
        position: relative;
        top: -90px;
    }
	/* Add your own MailChimp form style overrides in your site stylesheet or in this style block.
	   We recommend moving this block and the preceding CSS link to the HEAD of your HTML file. */
&lt;/style&gt;

&lt;div id=&quot;mc_embed_signup&quot;&gt;
    &lt;div class=&quot;gradient newsletter&quot;&gt;
        &lt;div style=&quot;background:#000000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#1C0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#380000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#550000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#710000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#8D0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#AA0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#C60000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#E20000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF3800&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF5500&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF7100&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF8D00&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFAA00&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFC600&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFE200&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFFF00&quot;&gt;&lt;/div&gt;
    &lt;/div&gt;
    &lt;form action=&quot;https://IndexOutOfRange.us15.list-manage.com/subscribe/post?u=b1c1099bf7f49b95c64107c99&amp;amp;id=6a5eb68eb7&quot; method=&quot;post&quot; id=&quot;mc-embedded-subscribe-form&quot; name=&quot;mc-embedded-subscribe-form&quot; class=&quot;validate&quot; target=&quot;_blank&quot; novalidate=&quot;&quot;&gt;
        &lt;div id=&quot;mc_embed_signup_scroll&quot;&gt;
        &lt;label for=&quot;mce-EMAIL&quot; style=&quot;color: white;&quot;&gt;Get email notifications about new posts:&lt;/label&gt;
        &lt;input type=&quot;email&quot; value=&quot;&quot; name=&quot;EMAIL&quot; class=&quot;email&quot; id=&quot;mce-EMAIL&quot; placeholder=&quot;email address&quot; required=&quot;&quot; /&gt;
        &lt;!-- real people should not fill this in and expect good things - do not remove this or risk form bot signups--&gt;
        &lt;div style=&quot;position: absolute; left: -5000px;&quot; aria-hidden=&quot;true&quot;&gt;&lt;input type=&quot;text&quot; name=&quot;b_b1c1099bf7f49b95c64107c99_6a5eb68eb7&quot; tabindex=&quot;-1&quot; value=&quot;&quot; /&gt;&lt;/div&gt;
        &lt;div class=&quot;clear&quot;&gt;&lt;input type=&quot;submit&quot; value=&quot;Subscribe&quot; name=&quot;subscribe&quot; id=&quot;mc-embedded-subscribe&quot; class=&quot;button&quot; /&gt;&lt;/div&gt;
        &lt;/div&gt;
    &lt;/form&gt;
&lt;/div&gt;

&lt;!--End mc_embed_signup--&gt;

&lt;h3 id=&quot;why-partition-keys-values-cant-be-changed&quot;&gt;Why partition keys values can’t be changed?&lt;/h3&gt;

&lt;p&gt;Let’s think about it. We know that:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The partition is the boundary of the transaction.&lt;/li&gt;
  &lt;li&gt;All documents with the same partition key value are in one partition.&lt;/li&gt;
  &lt;li&gt;The partition contains documents with the same partition key value.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The change of a partition key property value would spawn across two partitions (old, and new). However, that won’t be transactional. 
For this reason, Cosmos DB throws an exception if we try to change the value of the partition key property.&lt;/p&gt;

&lt;h2 id=&quot;4-performance-limitation&quot;&gt;4. Performance limitation&lt;/h2&gt;

&lt;p&gt;One partition can’t be split across multiple servers (&lt;a href=&quot;https://stackoverflow.com/questions/40272600/is-there-a-dynamodb-max-partition-size-of-10gb-for-a-single-partition-key-value&quot;&gt;DynamoDB can split a single partition using a range key&lt;/a&gt;, but this is more or less equal to having a more detailed partition key value). This leads to an obvious limitation:&lt;/p&gt;

&lt;div class=&quot;center&quot;&gt;
    &lt;div class=&quot;button&quot;&gt;&lt;b&gt;Partitions have a limit on the number of operations a second they can perform.&lt;/b&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Since partitions have limited performance capabilities we might want to distribute queries over multiple partitions. In general, this is a good practice but has to be executed with one thing in mind.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;NoSQL databases have a named anti-pattern for partitions that are used more than others - &lt;strong&gt;hot partitions&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We have to be careful with load distribution because of:&lt;/p&gt;

&lt;h2 id=&quot;5-cost&quot;&gt;5. Cost&lt;/h2&gt;

&lt;p&gt;One of the first steps in query execution in Cosmos DB and DynamoDB is to send the query to proper partitions.
When we don’t provide a value for the partition key property in the query, the engine executes it on &lt;strong&gt;all partitions&lt;/strong&gt;. 
Even if the query executed on the partition doesn’t return any results, we will still pay for the used compute resources. Most of those queries should end on index scans. This little expense is multiplied by the number of partitions and might end up a significant one in the end.&lt;/p&gt;

&lt;p&gt;A good practice is to design queries so that they always execute on as few partitions as possible.&lt;/p&gt;

&lt;h1 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h1&gt;

&lt;p&gt;If anyone expected a straightforward answer on how to choose the partition key, sorry for letting you down. There is no simple answer. As always, it depends.
Choosing the partition key is always a trade-off:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Large transaction boundary &lt;b&gt;or&lt;/b&gt; the peace of mind of small partitions?&lt;/li&gt;
  &lt;li&gt;Risk of hot partitions &lt;b&gt;or&lt;/b&gt; more expensive queries?&lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Tue, 13 Aug 2019 00:00:00 +0200</pubDate>
        <link>https://IndexOutOfRange.com//how-to-choose-a-partition-key/</link>
        <guid isPermaLink="true">https://IndexOutOfRange.com//how-to-choose-a-partition-key/</guid>
      </item>
    
      <item>
        <title>Stop trying to mock the ILogger methods</title>
        <description>&lt;img src='https://indexoutofrange.com/data/2019-08-05-Stop-trying-to-mock-the-ILogger-methods/logo.jpg' /&gt;&lt;p&gt;I’ve seen multiple people struggling with trying to mock the ILogger calls. This post will hopefully save some people from wandering this path.
Here it goes:&lt;/p&gt;

&lt;div class=&quot;center&quot;&gt;
    &lt;div class=&quot;button&quot;&gt;Please stop trying to mock the ILogger methods from .net core.&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Here is why:&lt;/p&gt;

&lt;!--MORE--&gt;

&lt;h1 id=&quot;it-is-not-designed-to-be-mocked&quot;&gt;It is not designed to be mocked&lt;/h1&gt;

&lt;p&gt;Most ILogger methods that we use for logging are extension methods - static methods. While mocking them is possible using &lt;a href=&quot;https://github.com/urasandesu/Prig&quot;&gt;Prig&lt;/a&gt;, or &lt;a href=&quot;https://docs.microsoft.com/en-US/visualstudio/test/code-generation-compilation-and-naming-conventions-in-microsoft-fakes?view=vs-2019&quot;&gt;Microsoft Fakes&lt;/a&gt; it is not easy or pleasant.
Mocking a static method boils down to replacing the code &lt;strong&gt;at runtime&lt;/strong&gt; using the debugger API. It sounds hard because it is hard. Those testing frameworks have additional restrictions that may make them impossible to run on a CI server.&lt;/p&gt;

&lt;h1 id=&quot;why-test-calling-a-log-method&quot;&gt;Why test calling a log method?&lt;/h1&gt;

&lt;p&gt;A log is a technical detail. It should be used for diagnosing problems and not much else.
The most common reason I see why people want to mock the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ILogger&lt;/code&gt; interface is because they are using a logger to write audit data to an audit file using a logger.&lt;/p&gt;

&lt;p&gt;It might sound like a good idea, but it is wrong for a few reasons:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Audit data should not be stored in a file&lt;/strong&gt;. It can be exported to a file, but a file should not be its main storage.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Loggers are optimized for throughput, not consistency&lt;/strong&gt;. They might lose data.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Writing to a &lt;a href=&quot;/What-is-the-simplest-database/&quot;&gt;file is not (it can be, but don’t do it) transactional&lt;/a&gt;&lt;/strong&gt;. If we write to a log and then rollback the transaction, the entry will stay in the file.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Most loggers use a buffer or a delayed/async write&lt;/strong&gt;. Writing to a file is a slow IO operation. Loggers delay it not to slow down the process and write asynchronously in batches.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Calling the logging method does not imply that the entry will be written to a file&lt;/strong&gt;. Loggers offer multiple ways to filter what will be written to which file. From log levels to disabling some loggers. Additionally, logging configurations are, in most cases, customized for each environment. Making the test meaningless.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;you-are-testing-the-wrong-thing&quot;&gt;You are testing the wrong thing&lt;/h1&gt;

&lt;p&gt;Even if we could test the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ILogger&lt;/code&gt; call, we still shouldn’t do it. Let me show an example. Let’s imagine we are logging access to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RegisterUser&lt;/code&gt;. Something like this:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&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;UserService&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ILogger&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_logger&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;UserService&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ILogger&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;logger&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;_logger&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;logger&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;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;RegisterUser&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;RegisterData&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&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;_logger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;LogInformation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;$&quot;User:&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;UserName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; logged in.&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;// do some cerification logic&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;/div&gt;

&lt;p&gt;It might look reasonable to try to mock the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LogInformation&lt;/code&gt; of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ILogger&lt;/code&gt; to verify if the business process logs registration attempts.&lt;/p&gt;

&lt;p&gt;When testing if a business process logs some information, we should be testing the &lt;strong&gt;business intent&lt;/strong&gt;. 
By testing the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ILogger&lt;/code&gt; call, we are testing the &lt;strong&gt;implementation&lt;/strong&gt;. Those two are mixed in the code above, causing our problems.&lt;/p&gt;

&lt;!-- Begin MailChimp Signup Form --&gt;

&lt;link href=&quot;//cdn-images.mailchimp.com/embedcode/horizontal-slim-10_7.css&quot; rel=&quot;stylesheet&quot; type=&quot;text/css&quot; /&gt;

&lt;style type=&quot;text/css&quot;&gt;
	#mc_embed_signup{
        clear:left; 
        font:14px Helvetica,Arial,sans-serif; 
        width:100%; 
        margin-top: 40px;
        margin-bottom: 40px;
        height:100px;
    }
    #mc_embed_signup .newsletter div{
        height: 100px;
    }
    #mc_embed_signup form{
        position: relative;
        top: -90px;
    }
	/* Add your own MailChimp form style overrides in your site stylesheet or in this style block.
	   We recommend moving this block and the preceding CSS link to the HEAD of your HTML file. */
&lt;/style&gt;

&lt;div id=&quot;mc_embed_signup&quot;&gt;
    &lt;div class=&quot;gradient newsletter&quot;&gt;
        &lt;div style=&quot;background:#000000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#1C0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#380000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#550000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#710000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#8D0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#AA0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#C60000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#E20000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF3800&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF5500&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF7100&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF8D00&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFAA00&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFC600&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFE200&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFFF00&quot;&gt;&lt;/div&gt;
    &lt;/div&gt;
    &lt;form action=&quot;https://IndexOutOfRange.us15.list-manage.com/subscribe/post?u=b1c1099bf7f49b95c64107c99&amp;amp;id=6a5eb68eb7&quot; method=&quot;post&quot; id=&quot;mc-embedded-subscribe-form&quot; name=&quot;mc-embedded-subscribe-form&quot; class=&quot;validate&quot; target=&quot;_blank&quot; novalidate=&quot;&quot;&gt;
        &lt;div id=&quot;mc_embed_signup_scroll&quot;&gt;
        &lt;label for=&quot;mce-EMAIL&quot; style=&quot;color: white;&quot;&gt;Get email notifications about new posts:&lt;/label&gt;
        &lt;input type=&quot;email&quot; value=&quot;&quot; name=&quot;EMAIL&quot; class=&quot;email&quot; id=&quot;mce-EMAIL&quot; placeholder=&quot;email address&quot; required=&quot;&quot; /&gt;
        &lt;!-- real people should not fill this in and expect good things - do not remove this or risk form bot signups--&gt;
        &lt;div style=&quot;position: absolute; left: -5000px;&quot; aria-hidden=&quot;true&quot;&gt;&lt;input type=&quot;text&quot; name=&quot;b_b1c1099bf7f49b95c64107c99_6a5eb68eb7&quot; tabindex=&quot;-1&quot; value=&quot;&quot; /&gt;&lt;/div&gt;
        &lt;div class=&quot;clear&quot;&gt;&lt;input type=&quot;submit&quot; value=&quot;Subscribe&quot; name=&quot;subscribe&quot; id=&quot;mc-embedded-subscribe&quot; class=&quot;button&quot; /&gt;&lt;/div&gt;
        &lt;/div&gt;
    &lt;/form&gt;
&lt;/div&gt;

&lt;!--End mc_embed_signup--&gt;

&lt;h1 id=&quot;refactor&quot;&gt;Refactor&lt;/h1&gt;

&lt;p&gt;If we split the implementation from the intent, our work will be much more straightforward:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&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;UserService&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ILogger&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_logger&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;UserService&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ILogger&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;logger&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;_logger&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;logger&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;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;RegisterUser&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;RegisterData&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&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;nf&quot;&gt;LogRegisterAttempt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;userName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;// do some cerification logic&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        
        &lt;span class=&quot;k&quot;&gt;internal&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;virtual&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;LogRegisterAttempt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;userName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;){&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;_logger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;LogInformation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;$&quot;User:&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;userName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; tried to register.&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;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now for a simple test (used Moq, but any mocking framework will do):&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&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;UserServiceTests&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;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;RegisterUser_ShouldLogLogginAttempt&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;// Arrange&lt;/span&gt;
            &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;registerData&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;nf&quot;&gt;RegisterData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(){&lt;/span&gt;
                &lt;span class=&quot;cm&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;userService&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;Mock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;UserService&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;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;userService&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CallBase&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;userService&lt;/span&gt;
                &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Setup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;LogRegisterAttempt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;It&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IsAny&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;RegisterData&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;c1&quot;&gt;// Act &lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;userService&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;RegisterUser&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;registerData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

            &lt;span class=&quot;c1&quot;&gt;// Assert&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;userService&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Verify&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;LogRegisterAttempt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;registerData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Times&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Exactly&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;/div&gt;

&lt;p&gt;A few things to note here:&lt;/p&gt;

&lt;p&gt;Those who read the code carefully will notice that I am mocking the system under test (my &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;UserService&lt;/code&gt;). Let me explain:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Yes, it will work (the method has to be virtual).&lt;/li&gt;
  &lt;li&gt;Yes, you can do such things.&lt;/li&gt;
  &lt;li&gt;Yes, it is perfectly OK.&lt;/li&gt;
  &lt;li&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RegisterUser&lt;/code&gt; will be called thanks to setting &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CallBase = true&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;making-it-even-better&quot;&gt;Making it even better&lt;/h2&gt;

&lt;p&gt;An even better idea is to refactor the audit logging function into a class. Since it is fulfilling a business need, so it should encapsulate how it is doing it.&lt;/p&gt;

&lt;h2 id=&quot;we-arent-testing-the-same-thing&quot;&gt;We aren’t testing the same thing!&lt;/h2&gt;

&lt;p&gt;No, we aren’t. We are missing one test. One that will call &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LogRegisterAttempt&lt;/code&gt;, read the log file and verify if it has the log entry - a simple integration test. I leave it to the reader ;)&lt;/p&gt;

&lt;h1 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h1&gt;

&lt;p&gt;Testing is not only writing test code. It is also looking at the existing code and making it better.&lt;/p&gt;

&lt;div class=&quot;center&quot;&gt;
    &lt;div class=&quot;button&quot;&gt;
If something is hard to test, it means that it is badly written. &lt;br /&gt; 
&lt;b&gt;or&lt;/b&gt;
&lt;br /&gt; You are trying to test something that shouldn't be tested in this way.&lt;/div&gt;
&lt;/div&gt;
</description>
        <pubDate>Mon, 05 Aug 2019 00:00:00 +0200</pubDate>
        <link>https://IndexOutOfRange.com//Stop-trying-to-mock-the-ILogger-methods/</link>
        <guid isPermaLink="true">https://IndexOutOfRange.com//Stop-trying-to-mock-the-ILogger-methods/</guid>
      </item>
    
      <item>
        <title>Why use a service mesh? A few arguments</title>
        <description>&lt;img src='https://indexoutofrange.com/data/2019-07-29-Why-use-a-service-mesh-a-few-arguments/logo.jpg' /&gt;&lt;p&gt;I will be back to the &lt;a href=&quot;/Modeling-version-and-temporary-state-in-noSQL-databases/&quot;&gt;series about data modeling in noSQL databases&lt;/a&gt;, but for now, I want to note down a few arguments that are still hot after an interesting discussion with a friend.
The talk boiled down to a simple question:&lt;/p&gt;

&lt;div class=&quot;center&quot;&gt;
    &lt;div class=&quot;button&quot;&gt;Should I use a service mesh or use a bare bones Kubernetes?&lt;/div&gt;
&lt;/div&gt;

&lt;!--MORE--&gt;

&lt;p&gt;I know how strange the combination of bare-bones and Kubernetes sounds, but this is the world we are living in :).&lt;/p&gt;

&lt;p&gt;I’m standing firmly on the position that service mesh is the only way to go. Here is why:&lt;/p&gt;

&lt;h2 id=&quot;a-service-mesh-means-less-code&quot;&gt;A service mesh means less code&lt;/h2&gt;

&lt;p&gt;A correctly implemented synchronous call should have the following policies/rules around it:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;getting a JWT token for authentication&lt;/li&gt;
  &lt;li&gt;timeout for the service we are calling&lt;/li&gt;
  &lt;li&gt;retry policy with exponential backoff and jitter&lt;/li&gt;
  &lt;li&gt;circuit breaker (a distributed if possible)&lt;/li&gt;
  &lt;li&gt;caching&lt;/li&gt;
  &lt;li&gt;fallback policy on what happens if the service is down&lt;/li&gt;
  &lt;li&gt;a timeout to wrap the whole thing since it isn’t that simple any more.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Depending on what framework, or language this will be ~200-400 lines of code. For one HTTP/&lt;a href=&quot;https://grpc.io/&quot;&gt;gRPC &lt;/a&gt;call!
I know they can be applied globally using things like &lt;a href=&quot;https://docs.microsoft.com/en-US/dotnet/standard/microservices-architecture/implement-resilient-applications/use-httpclientfactory-to-implement-resilient-http-requests&quot;&gt;HttpClientFactory&lt;/a&gt; in .net, but they still need to be defined somewhere.
The argument that “we can define them once and reuse” is false. Those policies will/should differ depending on the business use case. Reuse will be possible, but not to a full extent.&lt;/p&gt;

&lt;h1 id=&quot;developers-dont-&quot;&gt;Developers don’t …&lt;/h1&gt;

&lt;h2 id=&quot;developers-dont-care&quot;&gt;Developers don’t care&lt;/h2&gt;

&lt;p&gt;This title is a read-bate, but let me explain. Developers are not the ones who will get the call when the system crashes. 
They should be, but in most cases, the on-call person will be someone with “DevOps” in the job title. 
This creates a week incentive for implementing those rules &lt;strong&gt;properly&lt;/strong&gt;. Most developers have their backlogs full of business features that will take them more than a year to implement. They won’t spend enough time on this. 
And even if they would:&lt;/p&gt;

&lt;h2 id=&quot;developers-dont-understand&quot;&gt;Developers don’t understand&lt;/h2&gt;

&lt;p&gt;Let’s take a developer that will want to do it properly. To implement all the policies correctly, he, or she would have to understand all the ways a system might fail.
This knowledge can be gained from:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Watching systems fail daily.&lt;/li&gt;
  &lt;li&gt;Doing post mortem and root cause analysis.&lt;/li&gt;
  &lt;li&gt;Having access to systems failing where people notice - the production environment.
Those are not the tasks of a developer, but an SRE (&lt;strong&gt;S&lt;/strong&gt;ervice &lt;strong&gt;R&lt;/strong&gt;eliability &lt;strong&gt;E&lt;/strong&gt;ngineer).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;developers-dont-have-the-numbers&quot;&gt;Developers don’t have the numbers&lt;/h2&gt;

&lt;p&gt;Let’s imagine a person who wants to do it properly, and will spend a lot of time understanding how a system might fail. They would be still missing some crucial information. &lt;strong&gt;The numbers.&lt;/strong&gt;
Almost every policy has some number attached to it:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;Policy&lt;/th&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;Number&lt;/th&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;Sources&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Timeout of the service we are calling&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Timeout value&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;SLA agreement verified using System monitoring&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Retry&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Number of retries &lt;br /&gt; Backoff time &lt;br /&gt; Jitter value&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;System monitoring&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Caching&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Caching time&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;HTTP headers &lt;br /&gt; System montoring&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Circuit breaker&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Open state time&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;System monitoring&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;style&gt;
    table {
      border-collapse: collapse;
    }
    table, th, td {
      border: 1px solid black;
    }
    th{
      font-weight: bold;
    }
&lt;/style&gt;

&lt;p&gt;Even if the developer acquires those values, they might change over time. What then? Should we redeploy the code to change the timeout value? It doesn’t sound reasonable. 
The alternative is to have them in a config file, leading do a large and unmaintainable file.&lt;/p&gt;

&lt;!-- Begin MailChimp Signup Form --&gt;

&lt;link href=&quot;//cdn-images.mailchimp.com/embedcode/horizontal-slim-10_7.css&quot; rel=&quot;stylesheet&quot; type=&quot;text/css&quot; /&gt;

&lt;style type=&quot;text/css&quot;&gt;
	#mc_embed_signup{
        clear:left; 
        font:14px Helvetica,Arial,sans-serif; 
        width:100%; 
        margin-top: 40px;
        margin-bottom: 40px;
        height:100px;
    }
    #mc_embed_signup .newsletter div{
        height: 100px;
    }
    #mc_embed_signup form{
        position: relative;
        top: -90px;
    }
	/* Add your own MailChimp form style overrides in your site stylesheet or in this style block.
	   We recommend moving this block and the preceding CSS link to the HEAD of your HTML file. */
&lt;/style&gt;

&lt;div id=&quot;mc_embed_signup&quot;&gt;
    &lt;div class=&quot;gradient newsletter&quot;&gt;
        &lt;div style=&quot;background:#000000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#1C0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#380000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#550000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#710000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#8D0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#AA0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#C60000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#E20000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF3800&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF5500&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF7100&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF8D00&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFAA00&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFC600&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFE200&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFFF00&quot;&gt;&lt;/div&gt;
    &lt;/div&gt;
    &lt;form action=&quot;https://IndexOutOfRange.us15.list-manage.com/subscribe/post?u=b1c1099bf7f49b95c64107c99&amp;amp;id=6a5eb68eb7&quot; method=&quot;post&quot; id=&quot;mc-embedded-subscribe-form&quot; name=&quot;mc-embedded-subscribe-form&quot; class=&quot;validate&quot; target=&quot;_blank&quot; novalidate=&quot;&quot;&gt;
        &lt;div id=&quot;mc_embed_signup_scroll&quot;&gt;
        &lt;label for=&quot;mce-EMAIL&quot; style=&quot;color: white;&quot;&gt;Get email notifications about new posts:&lt;/label&gt;
        &lt;input type=&quot;email&quot; value=&quot;&quot; name=&quot;EMAIL&quot; class=&quot;email&quot; id=&quot;mce-EMAIL&quot; placeholder=&quot;email address&quot; required=&quot;&quot; /&gt;
        &lt;!-- real people should not fill this in and expect good things - do not remove this or risk form bot signups--&gt;
        &lt;div style=&quot;position: absolute; left: -5000px;&quot; aria-hidden=&quot;true&quot;&gt;&lt;input type=&quot;text&quot; name=&quot;b_b1c1099bf7f49b95c64107c99_6a5eb68eb7&quot; tabindex=&quot;-1&quot; value=&quot;&quot; /&gt;&lt;/div&gt;
        &lt;div class=&quot;clear&quot;&gt;&lt;input type=&quot;submit&quot; value=&quot;Subscribe&quot; name=&quot;subscribe&quot; id=&quot;mc-embedded-subscribe&quot; class=&quot;button&quot; /&gt;&lt;/div&gt;
        &lt;/div&gt;
    &lt;/form&gt;
&lt;/div&gt;

&lt;!--End mc_embed_signup--&gt;

&lt;h1 id=&quot;the-circuit-breaker&quot;&gt;The circuit breaker&lt;/h1&gt;

&lt;p&gt;The circuit breaker policy is the one that gains the most when done in the layer of a service mesh. For two reasons:&lt;/p&gt;

&lt;h2 id=&quot;distributed-circuit-breaker&quot;&gt;Distributed circuit breaker&lt;/h2&gt;

&lt;p&gt;Having a circuit breaker is fine. But it is only the beginning of what it can and should do to protect our system from cascading failure.&lt;/p&gt;

&lt;p&gt;A standard circuit breaker works in the scope of a single application, not the whole system. It looks at requests going out of the service and monitors the number of errors. If the percentage of errors crosses a particular value, communication to that server is cut for some time. We do it not to escalate failure to other services. When looking from a single service point of view, it is the right solution.&lt;/p&gt;

&lt;p&gt;When looking from the point of view of the whole system, the problem is still unresolved. Because each service has to open it’s breaker independently, services will hammer the under stress service.
The more reasonable way to do it is to use a distributed circuit breaker. A distributed circuit breaker broadcasts the information about opening and closing a breaker to other services. If a breaker in one service opens, others will be notified about this via the broadcast, and also open. 
This way, we remove a faulty service from the whole system almost at once.&lt;/p&gt;

&lt;p&gt;Implementing a distributed circuit breaker in the application code is not a trivial task and will require the use of some centralized coordinator.&lt;/p&gt;

&lt;p&gt;When switching our mindset to a service mesh where we are proxying all incoming requests, the solution becomes very simple. We can break on the proxy — a much simpler solution.&lt;/p&gt;

&lt;h2 id=&quot;overload-circuit-breaker&quot;&gt;Overload circuit breaker&lt;/h2&gt;

&lt;p&gt;The circuit breaker pattern is protecting the caller from calling a faulty service. That is great. We fail faster and protect from requests piling in on our input while retrying or waiting on the defected service.
Now let’s think about the electric circuit breaker. It works differently. The real one protects from a too high current &lt;strong&gt;entering the system&lt;/strong&gt;. In system architecture terms: &lt;strong&gt;from too many requests entering the application&lt;/strong&gt;. 
Adding requests to a system under load will only make it worse. With the exception to this:&lt;/p&gt;

&lt;div style=&quot;text-align:center&quot;&gt;&lt;img src=&quot;/data/2019-07-29-Why-use-a-service-mesh-a-few-arguments/clicking.jpg&quot; /&gt;&lt;/div&gt;

&lt;p&gt;It is better to fail them earlier and have a chance for the system healing itself. 
An overload circuit breaker protects from failure happening, not from the consequences of failure. Such a circuit breaker is hard to implement on the application layer, but very simple when using a service mesh.&lt;/p&gt;

&lt;h1 id=&quot;get-rid-of-documentation&quot;&gt;Get rid of documentation&lt;/h1&gt;

&lt;p&gt;At least some parts of it. A service mesh can easily give us the &lt;strong&gt;actual&lt;/strong&gt; topology of the system. No more looking at diagrams and asking ourselves:&lt;/p&gt;

&lt;div class=&quot;center&quot;&gt;
    &lt;div class=&quot;button&quot;&gt;How outdated is it?&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Open Zipkin, Jaeger or Application Insights and see in real-time what service is used in which business process. Easy and, more importantly, accurate.
Some might argue that we can have this without a service mesh. Yes, we can. But it is easier to deploy and maintain it with a service mesh.&lt;/p&gt;

&lt;h1 id=&quot;monitoring-tracing-and-centralized-logging&quot;&gt;Monitoring, tracing and centralized logging&lt;/h1&gt;

&lt;p&gt;Except for reporting business metrics, the application should not care what type of centralized logging system is used.
Why should we add a wrapper for measuring execution time to every call? 
We will end up with something like this :&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;Timer&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Timer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Start&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;_http&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;http://google.com&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Stop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;_metrics&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ReportTime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;googlecall&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ElapsedMilliseconds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Application code isn’t the right place to do it. It can, and should be implemented globally. This way, we will be able to:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;guarantee a standard for the naming scheme.&lt;/li&gt;
  &lt;li&gt;be sure that all requests are logged.&lt;/li&gt;
  &lt;li&gt;have all applications log to the same system.&lt;/li&gt;
  &lt;li&gt;have logging independent from application framework and language.&lt;/li&gt;
  &lt;li&gt;minimize the infrastructure boilerplate that is needed before a team can start delivering value.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;reducing-complexity&quot;&gt;Reducing complexity&lt;/h1&gt;

&lt;p&gt;Granted, we can’t remove complexity. We can only move it to a different place in the system. But moving technical services such as service discovery and API gateways from application code to infrastructure sounds OK to me. They shouldn’t have any business code in them anyways.&lt;/p&gt;

&lt;h1 id=&quot;security&quot;&gt;Security&lt;/h1&gt;

&lt;p&gt;Kubernetes, Docker, VPN, and sub-networks give us the possibility to narrow down the list of who can talk to who. A service mesh is going a step forward by monitoring who &lt;strong&gt;is&lt;/strong&gt; talking and what type o traffic is it.
What makes it even better is that previously our monitoring would look at packets of TCP/IP or UDP traffic. In a service mesh, we are looking at HTTP traffic. This opens a lot of possibilities and makes some checks simpler.&lt;/p&gt;

&lt;h1 id=&quot;it-just-works&quot;&gt;It just works&lt;/h1&gt;

&lt;p&gt;How important are the decisions below?:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Eureka or Consul?&lt;/li&gt;
  &lt;li&gt;Jaeger or Zipkin?&lt;/li&gt;
  &lt;li&gt;Grafana with InfluxDB or Graphite?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Doesn’t the decision boil down to the question: &lt;strong&gt;What works with what we already have?&lt;/strong&gt;
Most service meshes are an opinionated set of tools that work together. That is a good thing. I can live with a bit less system integration code in my backlog. Can You?&lt;/p&gt;

&lt;h1 id=&quot;what-will-be-the-difference-in-the-end&quot;&gt;What will be the difference in the end?&lt;/h1&gt;

&lt;p&gt;Going back to the talk that sparked the need for writing this article. The more we discussed, the more I got closer to the essential point:&lt;/p&gt;

&lt;div class=&quot;center&quot;&gt;
    &lt;div class=&quot;button&quot;&gt;
Let's asume that you didn't use a service mesh.&lt;br /&gt; Then you add all the necessary infrastructure for a distributed system.&lt;br /&gt; &lt;b&gt;How different will it be from a service mesh?&lt;/b&gt; 
    &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;We won’t have a lightweight reverse proxy deployed with every service (probably). But is this such a high overhead versus all the things that a service mesh makes easier?&lt;/p&gt;

&lt;h1 id=&quot;no-flaws&quot;&gt;No flaws?&lt;/h1&gt;

&lt;p&gt;On the contrary! Service meshes offer even more ways to shoot ourselves in the feet, hands, the head, etc. Like with every technology we will have to spend time to learn it’s pitfalls and how to avoid them. But this is a topic for a different conversation.&lt;/p&gt;
</description>
        <pubDate>Mon, 29 Jul 2019 00:00:00 +0200</pubDate>
        <link>https://IndexOutOfRange.com//WhyUseAServiceMeshAFewArguments/</link>
        <guid isPermaLink="true">https://IndexOutOfRange.com//WhyUseAServiceMeshAFewArguments/</guid>
      </item>
    
      <item>
        <title>Modeling version and temporary state in noSQL databases</title>
        <description>&lt;img src='https://indexoutofrange.com/data/2019-07-22-Modeling-version-and-temporary-state-in-noSQL-databases/logo.jpg' /&gt;&lt;p&gt;The problem of storing draft state and auditing is not limited to noSQL databases, and as &lt;a href=&quot;/How-to-model-hierarchical-data-in-noSQL-datababases/&quot;&gt;previously&lt;/a&gt;, below patterns can be applied to SQL modeling. But because noSQL databases are, in most cases, lacking transactionality over multiple partitions, the problem is harder there. Making it more interesting :)
Additionally, smart use of neet features of noSQL databases allows for a novel solution.&lt;/p&gt;

&lt;h1 id=&quot;the-problems&quot;&gt;The problem(s):&lt;/h1&gt;

&lt;h2 id=&quot;problem-1-storing-temporary-state&quot;&gt;Problem 1: Storing temporary state&lt;/h2&gt;

&lt;p&gt;Most developers cringe when they hear about storing temporary state, but can’t imagine living without &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Save as draft&lt;/code&gt; in Gmail, or git stash :)
Give the users what You expect. 
A  different few use-cases :&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The user can edit a document and save it as a draft. That draft can be later on committed or discarded.&lt;/li&gt;
  &lt;li&gt;UI flow requires a page reload when working on a single object. I know that we have SPA applications now, but not everywhere and we might be switching between different systems, or refactoring a legacy system.&lt;/li&gt;
  &lt;li&gt;Our document validation logic is quite complex, requires external HTTP calls, takes a long time to execute, and sometimes requires retries. Since we are good developers, we don’t run that logic during saving but save as draft, schedule a background task to do the validation. If something fails, we notify the user - a good UX.&lt;/li&gt;
&lt;/ul&gt;

&lt;!--MORE--&gt;

&lt;p&gt;All the above can be simplified to a problem of storing not confirmed data.
We can solve it in a few ways:&lt;/p&gt;

&lt;h4 id=&quot;slap-a--state-flag-field-with-two-states-draft-and-confirmed-to-the-object&quot;&gt;Slap a  &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;State&lt;/code&gt; flag field with two states: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Draft&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Confirmed&lt;/code&gt; to the object.&lt;/h4&gt;

&lt;p&gt;This is one of the most common solutions I see in systems. It is effortless, and those are all of its advantages.
The list of disadvantages is longer:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Everyone has to remember to add &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;State = Confirmed&lt;/code&gt; to every query over this collection/table.&lt;/li&gt;
  &lt;li&gt;Modeling different objects (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DraftOrder&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Order&lt;/code&gt;) using enums is breaking SOLID principles.&lt;/li&gt;
  &lt;li&gt;Adding a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Status&lt;/code&gt; property opens the gates to other states. If we leave opened gates, we can be sure that dragons🐉 will come.&lt;/li&gt;
  &lt;li&gt;We can’t reuse the required fields, and validation logic since a draft is not a full object. Leading us to objects that are the same but are not the same.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;add-a-boolean-field-isdraft&quot;&gt;Add a boolean field &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IsDraft&lt;/code&gt;.&lt;/h4&gt;

&lt;p&gt;It might look like a good workaround to not leaving the gates open. But it is even worse because more flag fields will come making the problem of state distributed (current state = SUM(all flag fields)).&lt;/p&gt;

&lt;h4 id=&quot;a-separate-tablecollection-to-store-the-draft-object&quot;&gt;A separate table/collection to store the draft object.&lt;/h4&gt;

&lt;p&gt;We can create a separate table or collection to store draft state. Sounds OK, but again we have some drawbacks here:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;When migrating object structure, we have to migrate the structure of the original object &lt;strong&gt;and&lt;/strong&gt; the drafts.&lt;/li&gt;
  &lt;li&gt;Most noSQL databases guarantee transactionality only in the scope of a single partition. We loose this by splitting the collections.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;problem-2-entity-auditing&quot;&gt;Problem 2: Entity auditing&lt;/h2&gt;

&lt;p&gt;In essence: Who changed what and when. A must-have in most financial systems and with time will be implemented in every system that allows for any user data update. Why?&lt;/p&gt;

&lt;div style=&quot;text-align:center&quot;&gt;&lt;img src=&quot;/data/2019-07-22-Modeling-version-and-temporary-state-in-noSQL-databases/House.jpg&quot; /&gt;&lt;/div&gt;

&lt;p&gt;Why did I say that those two problems are very similar? Change the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;State&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;VersionNumber&lt;/code&gt; add who and when did the change and we have versioning. I know I am oversimplifying but stay with me.&lt;/p&gt;

&lt;p&gt;Now for a few well-known patterns:&lt;/p&gt;

&lt;h3 id=&quot;storing-only-the-changed-fields&quot;&gt;Storing only the changed fields&lt;/h3&gt;

&lt;p&gt;Because we want to track changes, we can only store the fields that changed. We will end up with something like this:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;FieldName&lt;/th&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;NewValue&lt;/th&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;Date&lt;/th&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;ChangingUser&lt;/th&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;ChangeGroup&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Name&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Anna&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;2019-07-19&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Rick Sanchez&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;10&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Surname&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Smith&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;2019-07-19&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Beth Smith&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;10&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;Where:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FieldName&lt;/code&gt; - name of the field what was changed&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NewValue&lt;/code&gt; - as the name suggests, the new value of the field&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Date&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ChangingUser&lt;/code&gt; - date and the user responsible for the change&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ChangeGroup&lt;/code&gt; - a unique number combining all changes in one save/update action&lt;/li&gt;
&lt;/ul&gt;

&lt;style&gt;
    table {
    border-collapse: collapse;
    width: auto !important;
    }
    table, th, td {
    border: 1px solid black;
    }
    th{
      font-weight: bold;
    }
&lt;/style&gt;

&lt;p&gt;The main benefits of this approach:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;We can very quickly answer the question who changed a particular field&lt;/li&gt;
  &lt;li&gt;Since in most cases, we change a small percentage of all properties, this solution saves a lot of space.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While it is very flexible, the flexibility has some drawbacks:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;When migrating the object structure, we also have to update &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FieldName&lt;/code&gt; values.&lt;/li&gt;
  &lt;li&gt;Reading object state in a specific moment in time is quite complicated. Requires reading all past events from the given date and applying them in order.&lt;/li&gt;
  &lt;li&gt;Auditing adding and removing from lists is not that easy.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;storing-full-objects-with-audit-data&quot;&gt;Storing full objects with audit data&lt;/h3&gt;

&lt;p&gt;In this approach, we store the whole changed object (as a blob or in a structured way) and only append audit data to it. 
The database structure would look something like this:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;Id&lt;/th&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;Original Entity Properties&lt;/th&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;EntityId&lt;/th&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;Date&lt;/th&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;ChangingUser&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;0&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;{…}&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;10&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;2018-06-19&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Rick Sanchez&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;1&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;{…}&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;10&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;2019-07-19&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Evil Morty&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;Again, there are plusses:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;getting the state in time is very easy&lt;/li&gt;
  &lt;li&gt;very easy to implement&lt;/li&gt;
  &lt;li&gt;object complexity is not an issue.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And minuses:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;we are storing a lot of duplicated data.&lt;/li&gt;
  &lt;li&gt;getting the information who changed a particular field is a non-trivial task.&lt;/li&gt;
&lt;/ul&gt;

&lt;!-- Begin MailChimp Signup Form --&gt;

&lt;link href=&quot;//cdn-images.mailchimp.com/embedcode/horizontal-slim-10_7.css&quot; rel=&quot;stylesheet&quot; type=&quot;text/css&quot; /&gt;

&lt;style type=&quot;text/css&quot;&gt;
	#mc_embed_signup{
        clear:left; 
        font:14px Helvetica,Arial,sans-serif; 
        width:100%; 
        margin-top: 40px;
        margin-bottom: 40px;
        height:100px;
    }
    #mc_embed_signup .newsletter div{
        height: 100px;
    }
    #mc_embed_signup form{
        position: relative;
        top: -90px;
    }
	/* Add your own MailChimp form style overrides in your site stylesheet or in this style block.
	   We recommend moving this block and the preceding CSS link to the HEAD of your HTML file. */
&lt;/style&gt;

&lt;div id=&quot;mc_embed_signup&quot;&gt;
    &lt;div class=&quot;gradient newsletter&quot;&gt;
        &lt;div style=&quot;background:#000000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#1C0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#380000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#550000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#710000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#8D0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#AA0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#C60000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#E20000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF3800&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF5500&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF7100&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF8D00&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFAA00&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFC600&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFE200&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFFF00&quot;&gt;&lt;/div&gt;
    &lt;/div&gt;
    &lt;form action=&quot;https://IndexOutOfRange.us15.list-manage.com/subscribe/post?u=b1c1099bf7f49b95c64107c99&amp;amp;id=6a5eb68eb7&quot; method=&quot;post&quot; id=&quot;mc-embedded-subscribe-form&quot; name=&quot;mc-embedded-subscribe-form&quot; class=&quot;validate&quot; target=&quot;_blank&quot; novalidate=&quot;&quot;&gt;
        &lt;div id=&quot;mc_embed_signup_scroll&quot;&gt;
        &lt;label for=&quot;mce-EMAIL&quot; style=&quot;color: white;&quot;&gt;Get email notifications about new posts:&lt;/label&gt;
        &lt;input type=&quot;email&quot; value=&quot;&quot; name=&quot;EMAIL&quot; class=&quot;email&quot; id=&quot;mce-EMAIL&quot; placeholder=&quot;email address&quot; required=&quot;&quot; /&gt;
        &lt;!-- real people should not fill this in and expect good things - do not remove this or risk form bot signups--&gt;
        &lt;div style=&quot;position: absolute; left: -5000px;&quot; aria-hidden=&quot;true&quot;&gt;&lt;input type=&quot;text&quot; name=&quot;b_b1c1099bf7f49b95c64107c99_6a5eb68eb7&quot; tabindex=&quot;-1&quot; value=&quot;&quot; /&gt;&lt;/div&gt;
        &lt;div class=&quot;clear&quot;&gt;&lt;input type=&quot;submit&quot; value=&quot;Subscribe&quot; name=&quot;subscribe&quot; id=&quot;mc-embedded-subscribe&quot; class=&quot;button&quot; /&gt;&lt;/div&gt;
        &lt;/div&gt;
    &lt;/form&gt;
&lt;/div&gt;

&lt;!--End mc_embed_signup--&gt;

&lt;h1 id=&quot;alternative-solution&quot;&gt;Alternative solution&lt;/h1&gt;

&lt;p&gt;All the above solutions can be implemented in SQL and noSQL databases, but they were designed with the first in mind.
When we take into account features that noSQL databases offer:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PartitionKey&lt;/code&gt;/&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PrimaryKey&lt;/code&gt; can be assigned to multiple rows/objects/states.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Id&lt;/code&gt;/&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SecondaryKey&lt;/code&gt;  can be used as a drill-down key to a specific object.&lt;/li&gt;
  &lt;li&gt;The ability to do commands pre-checks. A pre-check is an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;if&lt;/code&gt; statement. It has two properties:
    &lt;ul&gt;
      &lt;li&gt;is executed in the same transaction before the operation.&lt;/li&gt;
      &lt;li&gt;if it returns false, the operation won’t execute.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Having the above allows us for a bit different solution:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;PartitionKey&lt;/th&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;Version&lt;/th&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;CurrentVersion&lt;/th&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;Entity business attributes&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;0&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;0&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;2&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;{…}&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;0&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;1&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt; &lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;{…}&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;0&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;2&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt; &lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;{…}&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;Legend:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PartitionKey&lt;/code&gt; - primary entity key. It doesn’t change and is the &lt;strong&gt;boundary of our transaction&lt;/strong&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Version&lt;/code&gt; - as the name suggests, the number of the object version. &lt;strong&gt;It is our secondary key.&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CurrentVersion&lt;/code&gt; - this field might look like an unnecessary duplication but isn’t. We use it for optimistic locking. See the processes implementation below.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Additional rules:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Row with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Version=0&lt;/code&gt; is always the current row.&lt;/li&gt;
  &lt;li&gt;There is a unique index on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(PartitionKey, Version)&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CurrentVersion&lt;/code&gt; is the last version that was approved.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now to the processes. We have two:&lt;/p&gt;

&lt;h3 id=&quot;start-editing&quot;&gt;Start editing&lt;/h3&gt;

&lt;ol&gt;
  &lt;li&gt;Calculate the highest version&lt;/li&gt;
&lt;/ol&gt;

&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;Select&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;MAX&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;Version&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;Where&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PartitionKey&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;X&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ol&gt;
  &lt;li&gt;Copy the Version 0 item to a new record with Version = newMax +1&lt;/li&gt;
&lt;/ol&gt;

&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;COPY&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PartitionKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;Version&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CurrentVersion&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;Values&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PartitionKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;newMaxVersion&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CurrentVersion&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v0&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;business&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;properties&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;....)&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This is why we have a unique index on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(PartitionKey, Version)&lt;/code&gt; pair. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;newMaxVersion&lt;/code&gt; calculation is done in a separate call/transaction, so there is no guarantee that nothing happened in the middle (no new version was created). If a new version was created in the meantime, we will get an error. All we have to do is to recalculate the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;newMaxVersion&lt;/code&gt; and try to do a new insert.&lt;/p&gt;

&lt;h3 id=&quot;approve-version&quot;&gt;Approve version&lt;/h3&gt;

&lt;p&gt;Here, we use only one statement:&lt;/p&gt;

&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;UPDATE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CurrentVersion&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;newRow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;Version&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BusiessProp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;newRow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BusinessProp&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IF&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CurrentVersion&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;newRow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CurrentVersion&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Some explanation to the above:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;v0&lt;/code&gt; - the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Version = 0&lt;/code&gt; row.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;newRow&lt;/code&gt; - our new row.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;why-does-it-work&quot;&gt;Why does it work?&lt;/h4&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IF v0.CurrentVersion = newRow.CurrentVersion&lt;/code&gt; is a command pre-check mentioned before. If this statement is false, the operation will fail. 
What it gives us, and why do we have it? 
We are comparing the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CurrentVersion&lt;/code&gt; of the current state of the record with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CurrentVersion&lt;/code&gt; of our row when we started editing.&lt;/p&gt;

&lt;p&gt;When will this fail? Think about it.&lt;/p&gt;

&lt;p&gt;Remember that we are updating the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CurrentVersion&lt;/code&gt; &lt;strong&gt;with each approval&lt;/strong&gt;. It will fail if someone approved a version between &lt;strong&gt;us&lt;/strong&gt; starting editing and approving the version. 
Without the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;if&lt;/code&gt; we would override changes made by someone else. With it, we will discover a version conflict that has to be resolved.&lt;/p&gt;

&lt;p&gt;Another benefit to this approach is ACID like transactionality from starting editing to approving the version.&lt;/p&gt;

&lt;h1 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h1&gt;

&lt;p&gt;Yes, noSQL databases are simpler and less powerful in terms of features than their SQL cousins. But data modeling is about looking at the limitations and turning them into advantages.&lt;/p&gt;
</description>
        <pubDate>Mon, 22 Jul 2019 00:00:00 +0200</pubDate>
        <link>https://IndexOutOfRange.com//Modeling-version-and-temporary-state-in-noSQL-databases/</link>
        <guid isPermaLink="true">https://IndexOutOfRange.com//Modeling-version-and-temporary-state-in-noSQL-databases/</guid>
      </item>
    
      <item>
        <title>How to model hierarchical data in noSQL databases</title>
        <description>&lt;img src='https://indexoutofrange.com/data/2019-07-15-How-to-model-hierarchical-data-in-noSQL-datababases/logo.jpg' /&gt;&lt;p&gt;Querying hierarchical data is always where the big boys of SQL shined. And I really mean the &lt;strong&gt;big boys&lt;/strong&gt; part since &lt;s&gt;only Oracle, and Microsoft SQL Server have support for CTE&lt;/s&gt; [As Thomas Levesque pointed out in the comments, not only those have support for CTE. Full list on &lt;a href=&quot;https://en.wikipedia.org/wiki/Hierarchical_and_recursive_queries_in_SQL#Common_table_expression&quot;&gt;wikipedia&lt;/a&gt;] (&lt;strong&gt;C&lt;/strong&gt;ommon &lt;strong&gt;T&lt;/strong&gt;able &lt;strong&gt;E&lt;/strong&gt;xpressions) that allow for executing one SQL statement what will fetch a subtree.
There are data modeling approaches that allow for doing hierarchical data reads with noSQL databases and databases without support for CTE.&lt;/p&gt;

&lt;!--MORE--&gt;

&lt;h1 id=&quot;an-example&quot;&gt;An Example&lt;/h1&gt;

&lt;p&gt;The most common and obvious example of hierarchical data is the family tree (we are using parent and child when talking about hierarchical data for a reason). But because of limitations that we will discuss in the end, let’s look at another widespread usage: folder structure.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://upload.wikimedia.org/wikipedia/commons/6/69/FolderStructure_07ShotsDepartmentsDetailed.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Modeling the structure in a relational database is very easy and can be done in one table:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;Id&lt;/th&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;Name&lt;/th&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;ParentId&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;1&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;07-Shots&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;null&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;2&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;EX-000&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;2&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;3&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;0000&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;2&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;4&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Anin&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;3&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;5&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Cloth&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;3&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;names are self-explanatory.&lt;/p&gt;

&lt;style&gt;
    table {
    border-collapse: collapse;
    width: auto !important;
    }
    table, th, td {
    border: 1px solid black;
    }
&lt;/style&gt;

&lt;h1 id=&quot;sql&quot;&gt;SQL&lt;/h1&gt;

&lt;p&gt;As I wrote earlier, with SQL, we can use CTE. It will look more or less like this:&lt;/p&gt;

&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;WITH&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Folder_CTE&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;Name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;AS&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;-- Select the root&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; 
        &lt;span class=&quot;n&quot;&gt;rootParent&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;rootParent&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;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Folder&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rootParent&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;Where&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Id&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;-- The most parent Id from which we want to read the structure&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;-- Union the result&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;UNION&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;ALL&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;-- Select the next level of hierarchy by joining Folder with the already selected elements &lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;SELECT&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;Name&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;Folder&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;child&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;Join&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Folder_CTE&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parent&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;on&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;child&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ParentId&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parent&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;c1&quot;&gt;-- Join existing with new. &lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;-- Select the whole result&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;SELECT&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;Name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Surname&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Folder_CTE&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;What will happen is SQL Server engine will unwind the query fetching results until no new results are returned. It still means doing multiple joins, but the performance penalty isn’t that big.&lt;/p&gt;

&lt;p&gt;There are some limits to this approach.&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;As with most  (all to my knowledge) programming languages, there is a limit to this recursion. In case of SQL Server it is &lt;a href=&quot;https://stackoverflow.com/questions/2644281/how-many-maximum-recursion-possible-for-cte-in-sql-server&quot;&gt;100 by default&lt;/a&gt; but &lt;a href=&quot;https://social.msdn.microsoft.com/Forums/sqlserver/en-US/db9187df-5c0e-4fe6-bcb7-5d8039fab279/capacity-of-cte?forum=sqldatabaseengine&quot;&gt;can be changed to 32,767&lt;/a&gt;. With OLTP (&lt;strong&gt;O&lt;/strong&gt;n&lt;strong&gt;l&lt;/strong&gt;ine &lt;strong&gt;T&lt;/strong&gt;ransaction &lt;strong&gt;P&lt;/strong&gt;rocessing) loads this shouldn’t be a problem. For reporting (OLAP - &lt;strong&gt;O&lt;/strong&gt;n&lt;strong&gt;l&lt;/strong&gt;ine &lt;strong&gt;A&lt;/strong&gt;nalytics &lt;strong&gt;P&lt;/strong&gt;rocessing), you should be denormalizing your data anyway.&lt;/li&gt;
&lt;/ul&gt;

&lt;!-- Begin MailChimp Signup Form --&gt;

&lt;link href=&quot;//cdn-images.mailchimp.com/embedcode/horizontal-slim-10_7.css&quot; rel=&quot;stylesheet&quot; type=&quot;text/css&quot; /&gt;

&lt;style type=&quot;text/css&quot;&gt;
	#mc_embed_signup{
        clear:left; 
        font:14px Helvetica,Arial,sans-serif; 
        width:100%; 
        margin-top: 40px;
        margin-bottom: 40px;
        height:100px;
    }
    #mc_embed_signup .newsletter div{
        height: 100px;
    }
    #mc_embed_signup form{
        position: relative;
        top: -90px;
    }
	/* Add your own MailChimp form style overrides in your site stylesheet or in this style block.
	   We recommend moving this block and the preceding CSS link to the HEAD of your HTML file. */
&lt;/style&gt;

&lt;div id=&quot;mc_embed_signup&quot;&gt;
    &lt;div class=&quot;gradient newsletter&quot;&gt;
        &lt;div style=&quot;background:#000000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#1C0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#380000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#550000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#710000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#8D0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#AA0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#C60000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#E20000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF3800&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF5500&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF7100&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF8D00&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFAA00&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFC600&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFE200&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFFF00&quot;&gt;&lt;/div&gt;
    &lt;/div&gt;
    &lt;form action=&quot;https://IndexOutOfRange.us15.list-manage.com/subscribe/post?u=b1c1099bf7f49b95c64107c99&amp;amp;id=6a5eb68eb7&quot; method=&quot;post&quot; id=&quot;mc-embedded-subscribe-form&quot; name=&quot;mc-embedded-subscribe-form&quot; class=&quot;validate&quot; target=&quot;_blank&quot; novalidate=&quot;&quot;&gt;
        &lt;div id=&quot;mc_embed_signup_scroll&quot;&gt;
        &lt;label for=&quot;mce-EMAIL&quot; style=&quot;color: white;&quot;&gt;Get email notifications about new posts:&lt;/label&gt;
        &lt;input type=&quot;email&quot; value=&quot;&quot; name=&quot;EMAIL&quot; class=&quot;email&quot; id=&quot;mce-EMAIL&quot; placeholder=&quot;email address&quot; required=&quot;&quot; /&gt;
        &lt;!-- real people should not fill this in and expect good things - do not remove this or risk form bot signups--&gt;
        &lt;div style=&quot;position: absolute; left: -5000px;&quot; aria-hidden=&quot;true&quot;&gt;&lt;input type=&quot;text&quot; name=&quot;b_b1c1099bf7f49b95c64107c99_6a5eb68eb7&quot; tabindex=&quot;-1&quot; value=&quot;&quot; /&gt;&lt;/div&gt;
        &lt;div class=&quot;clear&quot;&gt;&lt;input type=&quot;submit&quot; value=&quot;Subscribe&quot; name=&quot;subscribe&quot; id=&quot;mc-embedded-subscribe&quot; class=&quot;button&quot; /&gt;&lt;/div&gt;
        &lt;/div&gt;
    &lt;/form&gt;
&lt;/div&gt;

&lt;!--End mc_embed_signup--&gt;

&lt;h1 id=&quot;modeling-hierarchy-in-nosql-database-or-without-cte&quot;&gt;Modeling hierarchy in noSQL database or without CTE&lt;/h1&gt;

&lt;p&gt;Techniques for modeling hierarchy efficiently can be applied in noSQL databases and in SQL databases without the support for CTE.&lt;/p&gt;

&lt;h2 id=&quot;application-recursion&quot;&gt;Application recursion&lt;/h2&gt;

&lt;p&gt;The first approach is to fetch each individual layer of hierarchy one at a time with the looping done by the application. 
The initial SQLs will look like this:&lt;/p&gt;

&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;SELECT&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;Name&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Folder&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The next SQL will look like this:&lt;/p&gt;

&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;SELECT&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;Name&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;Folder&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;Where&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ParentId&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;IN&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(...)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;--Ids of parents read in the previous iteration&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;There are a few problems with this approach:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;We will be executing multiple SQL queries&lt;/li&gt;
  &lt;li&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IN&lt;/code&gt; operator has a limit to the number of elements it can have. I remember it being around 2100, but now the documentation mentions &lt;a href=&quot;https://docs.microsoft.com/en-us/sql/t-sql/language-elements/in-transact-sql?view=sql-server-2017&quot;&gt;many thousands&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;The query plan optimizer selects existing plans for procedures with &lt;strong&gt;the same text and number of parameters&lt;/strong&gt; (if you are sending parameter &lt;strong&gt;values&lt;/strong&gt; in the query text please stop reading and fix it). For every laver of hierarchy, we will be changing the number of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IN&lt;/code&gt; parameters (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@p1, @p2, @p3, .... @pN&lt;/code&gt;) so every query will have the overhead of the optimizer.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;building-the-hierarchy-in-the-application&quot;&gt;Building the hierarchy in the application&lt;/h2&gt;

&lt;p&gt;Another approach is to get all the data, build the hierarchy in the app, and then do filtering. If we will be holding the data in the application cache, this is the simplest solution, so let’s not over enginer.&lt;/p&gt;

&lt;h2 id=&quot;hierarchy-path&quot;&gt;Hierarchy path&lt;/h2&gt;

&lt;p&gt;The idea of this approach is to extend our object/table with one additional field - &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HierarchyPath&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;Id&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;Name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;ParentId&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;HierarchyPath&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In this field, we put Ids of our parents (from the furthest away to the closest) separated by some unique character. Like this:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;5$18$201$8
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;For folder structure example from the start of the post, it will look like this:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;Id&lt;/th&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;Name&lt;/th&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;ParentId&lt;/th&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;HierarchyPath&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;1&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;07-Shots&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;null&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt; &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;2&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;EX-000&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;2&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;1$&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;3&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;0000&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;2&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;1$2$&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;4&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Anin&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;3&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;1$2$3$&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;5&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Cloth&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;3&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;1$2$3$&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;Where &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$&lt;/code&gt; plays the role of the separator.&lt;/p&gt;

&lt;p&gt;You might say. It’s stupid. Why would this make it any better?
We are missing two additional ingredients:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Create a &lt;strong&gt;text index&lt;/strong&gt; on the field.&lt;/li&gt;
  &lt;li&gt;Use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;StartsWith&lt;/code&gt; (or a right hand like) to search for the structure.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We can’t use a standard index since it will create an index of hashed values. That will not help us since a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;StartsWith&lt;/code&gt; on hashes just doesn’t make any sense. &lt;strong&gt;We need to query actual values&lt;/strong&gt;.
This type of indexes are available in most document databases under different names:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://dzone.com/articles/indexing-in-mongodb&quot;&gt;special text indexes in MongoDB&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://docs.microsoft.com/en-us/azure/cosmos-db/index-policy&quot;&gt;range indexes in CosmosDB&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://aws.amazon.com/blogs/database/using-sort-keys-to-organize-data-in-amazon-dynamodb/&quot;&gt;sort keys in DynamoDB&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In our case, the query will look more or less like this :&lt;/p&gt;

&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;SELECT&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;Name&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Folder&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;Where&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;HierarchyPath&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;StartsWith&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;&quot;1$&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Using this approach, we can use a single query to select the whole subtree without doing a scan over all the records.&lt;/p&gt;

&lt;h3 id=&quot;criticism&quot;&gt;Criticism&lt;/h3&gt;

&lt;p&gt;When I saw it, it felt like this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/data/2019-07-15-How-to-model-hierarchical-data-in-noSQL-datababases/engine.jpg&quot; alt=&quot;plane ducktaping&quot; /&gt;
source: Daily Mail.&lt;/p&gt;

&lt;p&gt;But the same as with the image, going deeper made me appreciate the solution more. For the plane ducktape I will give it to the experts:&lt;/p&gt;

&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/mG6gHpP6r1o&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;

&lt;h3 id=&quot;limitations&quot;&gt;Limitations:&lt;/h3&gt;

&lt;p&gt;We have the “feeling” part sorted, so let’s talk about the limitations.:&lt;/p&gt;

&lt;h4 id=&quot;selecting-the-identifier&quot;&gt;Selecting the identifier&lt;/h4&gt;

&lt;p&gt;This one isn’t significant, but being aware of.
When using string identifiers inputted by users selecting the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HierarchyPath&lt;/code&gt; separator isn’t that simple since it can’t exist in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Id&lt;/code&gt; itself.&lt;/p&gt;

&lt;h4 id=&quot;multiple-parent-scenario&quot;&gt;Multiple parent scenario.&lt;/h4&gt;

&lt;p&gt;This limitation is why we didn’t model the parent-child / family tree scenario. In most cases, you have at least two (biological) parents, and the only way to support this is to generate all paths (all 2^N of them where &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;N&lt;/code&gt; is the depth of the structure)&lt;/p&gt;

&lt;h4 id=&quot;changing-the-id-or-the-parentid&quot;&gt;Changing the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Id&lt;/code&gt; or the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ParentId&lt;/code&gt;&lt;/h4&gt;

&lt;p&gt;When we change the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Id&lt;/code&gt;, or the hierarchy structure, we need to update the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HierarchyPath&lt;/code&gt; in the whole subtree. Solution for this varies a but for SQL and noSQL databases.&lt;/p&gt;

&lt;p&gt;With SQL databases we can use a trigger (I know triggers are bad, but this isn’t business logic but technical, so they are less bad here).
The main benefit of doing it this way is that triggers are executed in the same transaction, so we will not lose data integrity.&lt;/p&gt;

&lt;p&gt;Even noSQL databases that offer the functionality of a trigger don’t execute them in the same transaction. Here we are left with eventual consistency.&lt;/p&gt;

&lt;p&gt;The approach that can be used in both SQL and noSQL implementations is to trigger a background job (AWS Lambda, Azure Function, or a &lt;a href=&quot;/Don't %20do%20it%20now!%20Part%202.%20Background%20tasks,%20job%20queuing%20and%20scheduling%20with%20Hangfire/&quot;&gt;Hangfire job&lt;/a&gt; that will go over the data and update the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HierarchyPath&lt;/code&gt; values.&lt;/p&gt;

&lt;h3 id=&quot;starting-from-the-middle&quot;&gt;Starting from the middle&lt;/h3&gt;

&lt;p&gt;The last, and a quite significant problem is that we can’t effectively ask for substructure that would start in the middle of the tree. When starting from the middle, we can’t use a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;StartsWith&lt;/code&gt; clause, but will have to go with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Contains&lt;/code&gt;. This will scan all values in the index. It will still be faster than scanning the documents, but not as optimal as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;StartsWith&lt;/code&gt;.&lt;/p&gt;

&lt;h1 id=&quot;summary&quot;&gt;Summary&lt;/h1&gt;

&lt;p&gt;The solutions above aren’t ideal, but no answer is. As always think about the pros and cons and select the best for your use case.&lt;/p&gt;
</description>
        <pubDate>Mon, 15 Jul 2019 00:00:00 +0200</pubDate>
        <link>https://IndexOutOfRange.com//How-to-model-hierarchical-data-in-noSQL-datababases/</link>
        <guid isPermaLink="true">https://IndexOutOfRange.com//How-to-model-hierarchical-data-in-noSQL-datababases/</guid>
      </item>
    
      <item>
        <title>Lessons learned from making a video course for Pluralsight</title>
        <description>&lt;img src='https://indexoutofrange.com/data/2019-07-08-Lessons-learned-from-making-a-video-course-for-Pluralsight/logo.jpg' /&gt;&lt;p&gt;So, Yes. I hit a pause button on writing because many things were happening, and as it turns out, you can only squeeze 24 hours in one day. Who knew? 
However (hopefully) my blog will come back to life. 
One of the things that kept me busy during this time was realizing one of my goals:&lt;/p&gt;

&lt;div class=&quot;center&quot;&gt;
    &lt;div class=&quot;button&quot;&gt; Make a video course for Pluralsight. &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;And I &lt;a href=&quot;https://app.pluralsight.com/library/courses/microsoft-tpl-dataflow/table-of-contents&quot;&gt;made it&lt;/a&gt;:
&lt;!--MORE--&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://app.pluralsight.com/library/courses/microsoft-tpl-dataflow/table-of-contents&quot;&gt;&lt;img src=&quot;/data/2019-07-08-Lessons-learned-from-making-a-video-course-for-Pluralsight/pluralsight.jpg&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now that it is done, and I had a few months to reflect, a few lessons for those thinking about doing &lt;strong&gt;any video course&lt;/strong&gt;.&lt;/p&gt;

&lt;h1 id=&quot;preface&quot;&gt;Preface&lt;/h1&gt;

&lt;h2 id=&quot;choosing-the-course&quot;&gt;Choosing the course&lt;/h2&gt;

&lt;p&gt;Before we talk about what I learned, a few words about the course itself. First, how did I choose the topic. I had a few criteria:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;I wanted to make a course about something that I feel is very underrated mostly because of lack of awareness in the development community.&lt;/li&gt;
  &lt;li&gt;I didn’t want to do &lt;strong&gt;yet another&lt;/strong&gt; course about what is driving the hype train currently.&lt;/li&gt;
  &lt;li&gt;I wanted to make a course about something that I know but could use the course to structure and deepen my knowledge. As the saying goes: &lt;em&gt;if You want to learn something, teach it to someone&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A few topics fitted those criteria:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;graph databases&lt;/li&gt;
  &lt;li&gt;TPL Dataflow&lt;/li&gt;
  &lt;li&gt;general concepts of data modeling&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After much thinking and talking with people from Pluralsight, the decision was made to do a course about TPL Dataflow. It fitted the criteria perfectly:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Not too many devs know TPL Dataflow&lt;/li&gt;
  &lt;li&gt;I used it a lot when &lt;a href=&quot;/How_I_calculate_similarities_in_cookit/&quot;&gt;optimizing cookit&lt;/a&gt; and &lt;a href=&quot;/How-to-calculate-17-billion-similarities/&quot;&gt;calculating 17 billion similarities&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;It’s a perfect tool for some use-cases. I wanted to have a deeper understanding of how it works.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;what-is-tpl-dataflow&quot;&gt;What is TPL Dataflow?&lt;/h2&gt;

&lt;p&gt;TPL Dataflow is one of those gems that Microsoft sometimes develops and doesn’t put enough effort to inform the public (similar cases: Reactive Extensions, Orleans).&lt;/p&gt;

&lt;p&gt;Apart from the above it’s a &lt;a href=&quot;https://www.nuget.org/packages/System.Threading.Tasks.Dataflow/&quot;&gt;nuget package&lt;/a&gt; (available for .net framework and .net Core ) that implements the &lt;a href=&quot;https://en.wikipedia.org/wiki/Dataflow_programming&quot;&gt;Dataflow Programming Model&lt;/a&gt;. Dataflow Programming Model might sound ancient and abstract but just looking at the current implementations: &lt;a href=&quot;https://www.tensorflow.org/&quot;&gt;TensorFlow&lt;/a&gt;, &lt;a href=&quot;https://beam.apache.org/&quot;&gt;Apache Beam&lt;/a&gt; and &lt;a href=&quot;https://flink.apache.org/&quot;&gt;Apache Flink&lt;/a&gt; gives the domain where it is appliable: &lt;strong&gt;highly parallel, throughput orientated workloads&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In a nutshell, the main concepts are:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;business logic should not mix with execution logic.&lt;/li&gt;
  &lt;li&gt;code is encapsulated in blocks that can be linked to each other.&lt;/li&gt;
  &lt;li&gt;optimize for the throughput, not latency (can be tweaked).&lt;/li&gt;
  &lt;li&gt;optimize the performance of the whole workflow, not a single step.&lt;/li&gt;
  &lt;li&gt;data consistency over availability (this also can be changed).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Since this post isn’t about TPL Dataflow or the Dataflow Programming Model I will leave it here. If You want to know more &lt;a href=&quot;https://app.pluralsight.com/library/courses/microsoft-tpl-dataflow/table-of-contents&quot;&gt;see me the course I guess&lt;/a&gt;.&lt;/p&gt;

&lt;h1 id=&quot;the-lessons&quot;&gt;The lessons&lt;/h1&gt;

&lt;p&gt;I won’t advise on choosing the topic, but let’s assume You have one. What next?&lt;/p&gt;

&lt;h2 id=&quot;0-find-the-key&quot;&gt;0. Find the key&lt;/h2&gt;

&lt;p&gt;You have the title, but can’t get to actually making the thing?
You might say that this is normal because starting is hard. Which part of starting is hard? Why is it hard?&lt;/p&gt;

&lt;p&gt;For me, and reading the lessons learned of other people that made a video course, the biggest stopper for starting was knowing &lt;strong&gt;how do I structure the course&lt;/strong&gt;? Phrasing it differently: &lt;strong&gt;how to tell the story&lt;/strong&gt;?&lt;/p&gt;

&lt;p&gt;There are a few approaches:&lt;/p&gt;

&lt;h3 id=&quot;01-the-builder&quot;&gt;0.1 The builder&lt;/h3&gt;

&lt;p&gt;During the course, we build something (in 95% of the cases a website) using some framework and learn along the way. The most significant advantage of this theme is that it is &lt;em&gt;very engaging&lt;/em&gt;. Developers want to build stuff. It also gives a purpose and some sense of accomplishment. On the downside, You will be building a yet another typical example (blog, forum, shop, etc.) because choosing an overcomplicated domain will waste to much time on explaining it.
Additionally, the building order isn’t the learning order, so You will end up with digressions or using some feature that will be explained later on. Lastly, and for me, it was the biggest drawback, some features of the framework don’t make sense in what You are building. So you either leave them out (not a good idea) or cram them in somehow with little sense.&lt;/p&gt;

&lt;h3 id=&quot;02-feature-centric&quot;&gt;0.2 Feature centric&lt;/h3&gt;

&lt;p&gt;This approach concentrates on the features of the framework/topic at hand without actually building anything bigger than a few lines of code. The most significant advantage of this is that we can start from the fundamental parts of the framework and then progress to the more intricate features building on the knowledge gained earlier. This gives a natural, easy to understand progress path. 
The benefit of not building anything big is that the code samples demonstrating the feature can be more narrowed down to showcase the problem, making them easier to understand.
On the downside, it is less rewarding for the viewer, we have less real-life usages, and no fully working solution at the end.&lt;/p&gt;

&lt;!-- Begin MailChimp Signup Form --&gt;

&lt;link href=&quot;//cdn-images.mailchimp.com/embedcode/horizontal-slim-10_7.css&quot; rel=&quot;stylesheet&quot; type=&quot;text/css&quot; /&gt;

&lt;style type=&quot;text/css&quot;&gt;
	#mc_embed_signup{
        clear:left; 
        font:14px Helvetica,Arial,sans-serif; 
        width:100%; 
        margin-top: 40px;
        margin-bottom: 40px;
        height:100px;
    }
    #mc_embed_signup .newsletter div{
        height: 100px;
    }
    #mc_embed_signup form{
        position: relative;
        top: -90px;
    }
	/* Add your own MailChimp form style overrides in your site stylesheet or in this style block.
	   We recommend moving this block and the preceding CSS link to the HEAD of your HTML file. */
&lt;/style&gt;

&lt;div id=&quot;mc_embed_signup&quot;&gt;
    &lt;div class=&quot;gradient newsletter&quot;&gt;
        &lt;div style=&quot;background:#000000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#1C0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#380000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#550000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#710000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#8D0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#AA0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#C60000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#E20000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF3800&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF5500&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF7100&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF8D00&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFAA00&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFC600&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFE200&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFFF00&quot;&gt;&lt;/div&gt;
    &lt;/div&gt;
    &lt;form action=&quot;https://IndexOutOfRange.us15.list-manage.com/subscribe/post?u=b1c1099bf7f49b95c64107c99&amp;amp;id=6a5eb68eb7&quot; method=&quot;post&quot; id=&quot;mc-embedded-subscribe-form&quot; name=&quot;mc-embedded-subscribe-form&quot; class=&quot;validate&quot; target=&quot;_blank&quot; novalidate=&quot;&quot;&gt;
        &lt;div id=&quot;mc_embed_signup_scroll&quot;&gt;
        &lt;label for=&quot;mce-EMAIL&quot; style=&quot;color: white;&quot;&gt;Get email notifications about new posts:&lt;/label&gt;
        &lt;input type=&quot;email&quot; value=&quot;&quot; name=&quot;EMAIL&quot; class=&quot;email&quot; id=&quot;mce-EMAIL&quot; placeholder=&quot;email address&quot; required=&quot;&quot; /&gt;
        &lt;!-- real people should not fill this in and expect good things - do not remove this or risk form bot signups--&gt;
        &lt;div style=&quot;position: absolute; left: -5000px;&quot; aria-hidden=&quot;true&quot;&gt;&lt;input type=&quot;text&quot; name=&quot;b_b1c1099bf7f49b95c64107c99_6a5eb68eb7&quot; tabindex=&quot;-1&quot; value=&quot;&quot; /&gt;&lt;/div&gt;
        &lt;div class=&quot;clear&quot;&gt;&lt;input type=&quot;submit&quot; value=&quot;Subscribe&quot; name=&quot;subscribe&quot; id=&quot;mc-embedded-subscribe&quot; class=&quot;button&quot; /&gt;&lt;/div&gt;
        &lt;/div&gt;
    &lt;/form&gt;
&lt;/div&gt;

&lt;!--End mc_embed_signup--&gt;

&lt;h3 id=&quot;03-problem-solver&quot;&gt;0.3 Problem solver&lt;/h3&gt;

&lt;p&gt;An interesting approach mitigating the problems of the &lt;strong&gt;feature centric approach&lt;/strong&gt;  is to demonstrate the features on tiny problems that don’t work at first. From my experience in mentoring people, &lt;a href=&quot;/workshops/&quot;&gt;doing workshops&lt;/a&gt;, and based on Pluralsight review feedback, it is more engaging than just showing things that work out of the box. 
Troubleshooting issues also make it easier to show the underlying principles of the framework.&lt;/p&gt;

&lt;h3 id=&quot;04-mix-it-and-my-approach&quot;&gt;0.4 Mix it! And my approach&lt;/h3&gt;

&lt;p&gt;Those themes are not exclusive. You can switch between them during the course and use multiple at the same time (especially the problem solver).&lt;br /&gt;
I went with the feature-centric approach with a lot of problem-solving. This allowed me to do a deep dive into how Dataflow works and show how the basic principles that we discovered in the early clips apply to the advanced features. Such combination allowed me to fulfill one of my goals - &lt;strong&gt;teach how it works, not only how to use it&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Choosing the feature-centric approach doesn’t mean that we have to say goodbye to the problem solver. One way we can use it is to extend the same code sample in progressive exercises. We start with something simple, then add problems and features showing how to build more substantial systems. That proved to be a significant time-saver for me since it eliminated the need to explain the starting point with each clip.&lt;/p&gt;

&lt;h2 id=&quot;1-plan-your-work&quot;&gt;1. Plan your work&lt;/h2&gt;

&lt;p&gt;You have the vision soo start coding? No.
Don’t just start doing the course. Planning is important. People will watch it to learn something. Don’t waste their time with chaotic mumbling, or get a per review saying rethink Your life.
If You don’t care about viewers time (that is strange on its own. Please rethink it. ) You should care about Your time. 
The same chart we know from software development:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/data/2019-07-08-Lessons-learned-from-making-a-video-course-for-Pluralsight/bugfixingcost.jpg&quot; alt=&quot;&quot; /&gt;
source: https://deepsource.io/blog/exponential-cost-of-fixing-bugs/&lt;/p&gt;

&lt;p&gt;Applies to courses also. Redoing a recorded video because You forgot to say something essential that is needed one hour later is frustrating and very time-consuming.&lt;/p&gt;

&lt;h2 id=&quot;2-write-a-checklist&quot;&gt;2. Write a checklist&lt;/h2&gt;

&lt;p&gt;Write a list of things that You want to talk about. Don’t concentrate on order. There will be time for this later. It might be some high-level stuff or really tiny bits that are interesting. Don’t focus on this. Just dump everything into a text file or a piece of paper.&lt;br /&gt; 
Once You have it go through it and check if nothing is missing. Give yourself time since doing it properly now will save a lot of time in the future.&lt;/p&gt;

&lt;h2 id=&quot;3-write-an-index-first&quot;&gt;3. Write an index first&lt;/h2&gt;

&lt;p&gt;You have the checklist. Now:&lt;/p&gt;

&lt;h3 id=&quot;31-group-it&quot;&gt;3.1 Group it.&lt;/h3&gt;

&lt;p&gt;Assign the small bits to some larger topics that are best suited for explaining them. If there is no such topic just create one. Now you should have topics of more or less the same size. Next step is to:&lt;/p&gt;

&lt;h3 id=&quot;32-add-order&quot;&gt;3.2 Add order&lt;/h3&gt;

&lt;p&gt;Now we need some order in our list. Try to put the main topics in such a way that the viewer will build upon the gained knowledge. &lt;br /&gt;
This might sound simple, but there is a problem. We can’t bore someone with the basics for the first 45 minutes because noone will have enough paitience to wait for the usefull stuff. The first question that viewers will ask is: is this useful for me? If no, they will stop watching.&lt;br /&gt;
The best approaches I found was to show how to use the framework while demonstraiting the underlying principles in the meantime.&lt;a href=&quot;https://app.pluralsight.com/player?course=microsoft-tpl-dataflow&amp;amp;author=szymon-warda&amp;amp;name=bea807e8-2958-499e-9a35-2031aa12d8eb&amp;amp;clip=0&amp;amp;mode=live&quot;&gt;Part 3 of my course&lt;/a&gt; uses this approach. In each clip, I go through one building block of Dataflow and also show the basics as input and output queues, how to control concurrency, and how messages are delivered. Talking about them separately and without real-life examples would make the basics boring. 
To be frank, this is the part of the course I am most happy with (except for non-technical issues, but more about them later).&lt;/p&gt;

&lt;h2 id=&quot;4-write-a-script-and-code&quot;&gt;4. Write a script and code&lt;/h2&gt;

&lt;p&gt;I know that for some people having the list above is enough. They just start live coding and recording. For me, and probably for anyone doing it for the first time, it wasn’t the case.
I tried it and the amount of time that went into editing the recorded video and audio to make it watchable was too big. It turns out editing text is easier than editing video. Again who knew? ;)
For the n-th course, I will probably be able to do that. But for the first one, I decided to write an exact script that I would record.
Another great idea was to write the code samples with the script.&lt;br /&gt;
For me, this approach was a blessing. Thanks to it I:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;discovered topics that I needed to explain before for some clips.&lt;/li&gt;
  &lt;li&gt;noticed that in some cases, I need to rearrange the clips.&lt;/li&gt;
  &lt;li&gt;saw opportunities where I could reuse code from previous exercises in the next ones making the course more connected.&lt;/li&gt;
  &lt;li&gt;removed the writer’s block. For me, writing code is more natural than writing a script. Starting from the code and writing the script along the way was just more comfortable.&lt;/li&gt;
  &lt;li&gt;verified my own knowledge. To be honest, there were a few cases, especially with some inner working details, where I thought Dataflow would behave differently.  Having code that proved and verified my assumptions eliminated errors.&lt;/li&gt;
  &lt;li&gt;was able to reuse the audio from different takes to make the final cut.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Writing the script was a significant time investment, but looking back, I would make it once again.&lt;/p&gt;

&lt;h2 id=&quot;5-just-do-it&quot;&gt;5. Just do it&lt;/h2&gt;

&lt;p&gt;Having said so much positive stuff about the benefits of writing a script don’t over do it. I made the mistake of spending to much time reading and fixing it.&lt;br /&gt; 
Write the script, read and fix it once, and move on to recording. Record the audio and video and then fix the script. A few reasons why:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Trust me. You will find way more bugs and issues in the text, and code samples, by watching the recording than by reading the script and looking at the code samples.&lt;/li&gt;
  &lt;li&gt;Long, complex sentences are acceptable when written, but reading them is a nightmare. Listening also isn’t easy. I had to fix a lot of such sentences.&lt;/li&gt;
  &lt;li&gt;Doing the whole pipeline now will give You an overall view of what awaits. Every medium has its own does and don’ts. Knowing them soon is very beneficial.&lt;/li&gt;
  &lt;li&gt;You will gain some estimations on how long each clip is. They shouldn’t be too long or too short. About 7 minutes is perfect.&lt;/li&gt;
  &lt;li&gt;Start getting used to Your own voice. Most people don’t like how they sound on a recording. This is normal. People around You don’t mind, and You will spend a few hours listening to Yourself. Have it over with.&lt;/li&gt;
  &lt;li&gt;The first take will be bad. It will go into the trash can. Don’t spend to much time on it. &lt;strong&gt;Do it, learn from it and move on.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;6-do-audio-and-video-separately&quot;&gt;6. Do audio and video separately&lt;/h2&gt;

&lt;p&gt;Again, more seasoned trainers do it differently. For me doing the audio when codding was too much to do at once. It leads to many “yyyyyy” and code errors. Doing it separately was easier for me, and I didn’t have to worry about recording the keystrokes.&lt;/p&gt;

&lt;h2 id=&quot;7-dont-strive-for-perfection&quot;&gt;7. Don’t strive for perfection&lt;/h2&gt;

&lt;p&gt;You will see more errors, issues, and things to improve in the video than any other viewer. But keep in mind that people watch it for knowledge, not artistic perfection. If the knowledge is there and it is well served You will do just fine.&lt;/p&gt;

&lt;h1 id=&quot;faq&quot;&gt;FAQ&lt;/h1&gt;

&lt;h2 id=&quot;what-was-the-hardest&quot;&gt;What was the hardest?&lt;/h2&gt;

&lt;p&gt;Finding a concept of how I wanted the video to be structured and recording audio.&lt;/p&gt;

&lt;h2 id=&quot;how-much-time-did-it-take&quot;&gt;How much time did it take?&lt;/h2&gt;

&lt;p&gt;I didn’t count exactly but way too much because I had to learn so many things. At the end, doing one clip (audio + codding +  slides + cutting + export) took between 1-4 hours.
In the beginning, it was closer to 7 hours (mostly because multiple audio takes).&lt;/p&gt;

&lt;h2 id=&quot;would-you-do-it-again&quot;&gt;Would you do it again?&lt;/h2&gt;

&lt;p&gt;Yes. I learned a ton. Not only how to make video courses, but also about Dataflow and I have a ton of killer exercises for &lt;a href=&quot;/workshops/application-architecture/&quot;&gt;my workshops about Application Architecture&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;would-would-you-do-differently&quot;&gt;Would would you do differently?&lt;/h2&gt;

&lt;p&gt;I would redo the recording. But after recording it once, I would probably want to redo it once again…&lt;/p&gt;

&lt;h2 id=&quot;are-you-happy-with-how-it-turned-out&quot;&gt;Are you happy with how it turned out?&lt;/h2&gt;

&lt;p&gt;No. Anyone who knows me knows that I always see things to improve. The same with the course. I would rate myself with 3/5, but &lt;a href=&quot;https://app.pluralsight.com/library/courses/microsoft-tpl-dataflow/table-of-contents&quot;&gt;viewers on Pluralsight&lt;/a&gt; give it 4/5 soo I won’t argue.&lt;/p&gt;

&lt;h2 id=&quot;what-would-i-change&quot;&gt;What would I change?&lt;/h2&gt;

&lt;p&gt;How slow I talk. It should be faster. In person, I am a fast talker, and I was concerned that I would be in hard to understand for non-native speakers. I overdid it. But this is what the video playback speed regulation is for. I guess.&lt;/p&gt;

&lt;h1 id=&quot;links-further-reading-etc&quot;&gt;Links, further reading etc:&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.nuget.org/packages/System.Threading.Tasks.Dataflow/&quot;&gt;Dataflow nuget package&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://docs.microsoft.com/en-us/dotnet/standard/parallel-programming/dataflow-task-parallel-library&quot;&gt;Dataflow documentation&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://app.pluralsight.com/library/courses/microsoft-tpl-dataflow/table-of-contents&quot;&gt;My Pluralsight course&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/workshops/application-architecture/&quot;&gt;My workshops on Application Architecture where I show more non standard architectures&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Mon, 08 Jul 2019 00:00:00 +0200</pubDate>
        <link>https://IndexOutOfRange.com//Lessons-learned-from-making-a-Pluralsight-course/</link>
        <guid isPermaLink="true">https://IndexOutOfRange.com//Lessons-learned-from-making-a-Pluralsight-course/</guid>
      </item>
    
      <item>
        <title>Troubleshooting compiled Azure Functions in F#</title>
        <description>&lt;img src='https://indexoutofrange.com/data/2018-01-08-Troubleshooting-compiled-Azure-Functions-in-F/logo.png' /&gt;&lt;p&gt;As I wrote in the &lt;a href=&quot;https://indexoutofrange.com/The-missing-Azure-Functions-documentation/&quot;&gt;previous post&lt;/a&gt; there are two ways to run precompiled .NET code in Azure Functions - .NET 4.6.x or .NET Core. Why did I decide to go with the old .NET runtime? For the current moment, F# on .NET Core does not support type providers (there is &lt;a href=&quot;https://github.com/Microsoft/visualfsharp/issues/3303&quot;&gt;a workaround&lt;/a&gt;, but I didn’t want to go with it for the current moment). I went to work thinking that it will be a breeze. Just attach the repo and keep on coding. It turned out that I learned more Azure Functions troubleshooting and below is the shortened version.&lt;/p&gt;

&lt;!--MORE--&gt;

&lt;h2 id=&quot;the-problem&quot;&gt;The problem&lt;/h2&gt;

&lt;p&gt;The easiest way to run precompiled functions is to attach a repository with a F# project containing the function’s code to Azure Functions. This can be done&lt;br /&gt;
from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Platform features-&amp;gt;Deployment options-&amp;gt;Setup&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/data/2018-01-08-Troubleshooting-compiled-Azure-Functions-in-F/deployment-options.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Doing this will trigger code compilation. And to my astoundment, a failure:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/data/2018-01-08-Troubleshooting-compiled-Azure-Functions-in-F/deployment-failure.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Now we have a problem, so let’s investigate.&lt;/p&gt;

&lt;h2 id=&quot;build-failure-investigations&quot;&gt;Build failure investigations&lt;/h2&gt;

&lt;p&gt;The fist step into investigation should be checking the logs for details:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/data/2018-01-08-Troubleshooting-compiled-Azure-Functions-in-F/deployment-details.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;This shows a MSBuild error:&lt;/p&gt;

&lt;div class=&quot;language-batch highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;Command&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;D:\home\site\deployments\tools\deploy.cmd&quot;&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;Handling&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;App&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;deployment&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;MSBuild&lt;/span&gt;.
&lt;span class=&quot;kd&quot;&gt;Using&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;Msbuild&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'D:\Program Files (x86)\MSBuild-15.3.409.57025\MSBuild\15.0\Bin'&lt;/span&gt;.
&lt;span class=&quot;kd&quot;&gt;Nothing&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;. &lt;span class=&quot;kd&quot;&gt;None&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;of&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;the&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;projects&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;this&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;solution&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;specify&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;any&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;packages&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;NuGet&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;restore&lt;/span&gt;.
&lt;span class=&quot;kd&quot;&gt;Microsoft&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;R&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;Build&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;Engine&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;version&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;15&lt;/span&gt;.3.409.57025 &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; .NET &lt;span class=&quot;kd&quot;&gt;Framework&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;Copyright&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;Microsoft&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;Corporation&lt;/span&gt;. &lt;span class=&quot;kd&quot;&gt;All&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;rights&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;reserved&lt;/span&gt;.

&lt;span class=&quot;kd&quot;&gt;Build&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;started&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;/1/2018 &lt;span class=&quot;m&quot;&gt;11&lt;/span&gt;:08:14 &lt;span class=&quot;kd&quot;&gt;AM&lt;/span&gt;.
&lt;span class=&quot;kd&quot;&gt;Project&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;D:\home\site\repository\fsharptest.fsproj&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;on&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;node&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;targets&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;.
&lt;span class=&quot;kd&quot;&gt;D&lt;/span&gt;:\Program &lt;span class=&quot;kd&quot;&gt;Files&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;x86&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;\MSBuild&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;15&lt;/span&gt;.3.409.57025\MSBuild\Microsoft\VisualStudio\v15.0\FSharp\Microsoft.FSharp.NetSdk.props&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;: &lt;span class=&quot;kd&quot;&gt;error&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;MSB4019&lt;/span&gt;: &lt;span class=&quot;kd&quot;&gt;The&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;imported&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;project&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;D:\Program Files (x86)\Microsoft SDKs\F#\4.1\Framework\v4.0\Microsoft.FSharp.NetSdk.props&quot;&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;was&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;found&lt;/span&gt;. &lt;span class=&quot;kd&quot;&gt;Confirm&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;that&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;the&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;path&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;the&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;Import&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;declaration&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;correct&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;that&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;the&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;file&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;exists&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;on&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;disk&lt;/span&gt;. &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;D&lt;/span&gt;:\home\site\repository\fsharptest.fsproj&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;Done&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;Building&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;Project&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;D:\home\site\repository\fsharptest.fsproj&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;targets&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;--&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;FAILED&lt;/span&gt;.

&lt;span class=&quot;kd&quot;&gt;Build&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;FAILED&lt;/span&gt;.

&lt;span class=&quot;s2&quot;&gt;&quot;D:\home\site\repository\fsharptest.fsproj&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;D&lt;/span&gt;:\Program &lt;span class=&quot;kd&quot;&gt;Files&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;x86&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;\MSBuild&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;15&lt;/span&gt;.3.409.57025\MSBuild\Microsoft\VisualStudio\v15.0\FSharp\Microsoft.FSharp.NetSdk.props&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;: &lt;span class=&quot;kd&quot;&gt;error&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;MSB4019&lt;/span&gt;: &lt;span class=&quot;kd&quot;&gt;The&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;imported&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;project&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;D:\Program Files (x86)\Microsoft SDKs\F#\4.1\Framework\v4.0\Microsoft.FSharp.NetSdk.props&quot;&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;was&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;found&lt;/span&gt;. &lt;span class=&quot;kd&quot;&gt;Confirm&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;that&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;the&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;path&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;the&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;Import&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;declaration&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;correct&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;that&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;the&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;file&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;exists&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;on&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;disk&lt;/span&gt;. &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;D&lt;/span&gt;:\home\site\repository\fsharptest.fsproj&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;

    &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;Warning&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;Time&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;Elapsed&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;00&lt;/span&gt;:00:00.90
&lt;span class=&quot;kd&quot;&gt;Failed&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;exitCode&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;command&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;D:\Program Files (x86)\MSBuild-15.3.409.57025\MSBuild\15.0\Bin\MSBuild.exe&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;D:\home\site\repository\fsharptest.fsproj&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;/p&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;:DeployOnBuild&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;/p&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;:configuration&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;Release&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;/p&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;:publishurl&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;D:\local\Temp\8d55107eb70a8ff&quot;&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;An&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;error&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;has&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;occurred&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;during&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;web&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;site&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;deployment&lt;/span&gt;.
\r\nD:\Program &lt;span class=&quot;kd&quot;&gt;Files&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;x86&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;\SiteExtensions\Kudu\69.61204.3166\bin\Scripts\starter.cmd &lt;span class=&quot;s2&quot;&gt;&quot;D:\home\site\deployments\tools\deploy.cmd&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The key line is this one:&lt;/p&gt;

&lt;div class=&quot;language-batch highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;D&lt;/span&gt;:\Program &lt;span class=&quot;kd&quot;&gt;Files&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;x86&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;\MSBuild&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;15&lt;/span&gt;.3.409.57025\MSBuild\Microsoft\VisualStudio\v15.0\FSharp\Microsoft.FSharp.NetSdk.props&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;: 
&lt;span class=&quot;kd&quot;&gt;error&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;MSB4019&lt;/span&gt;: 
&lt;span class=&quot;kd&quot;&gt;The&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;imported&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;project&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;D:\Program Files (x86)\Microsoft SDKs\F#\4.1\Framework\v4.0\Microsoft.FSharp.NetSdk.props&quot;&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;was&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;found&lt;/span&gt;. 
&lt;span class=&quot;kd&quot;&gt;Confirm&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;that&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;the&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;path&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;the&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;Import&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;declaration&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;correct&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;that&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;the&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;file&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;exists&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;on&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;disk&lt;/span&gt;. &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;D&lt;/span&gt;:\home\site\repository\fsharptest.fsproj&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It is a standard MSBuild output indicating that a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.props&lt;/code&gt; (the same as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.target&lt;/code&gt;. &lt;a href=&quot;https://blogs.msdn.microsoft.com/msbuild/2010/02/25/getting-started-with-msbuild/&quot;&gt;MSBuild doesn’t care about the extension&lt;/a&gt;) file is missing. Lets check is the file really missing.&lt;/p&gt;

&lt;!-- Begin MailChimp Signup Form --&gt;

&lt;link href=&quot;//cdn-images.mailchimp.com/embedcode/horizontal-slim-10_7.css&quot; rel=&quot;stylesheet&quot; type=&quot;text/css&quot; /&gt;

&lt;style type=&quot;text/css&quot;&gt;
	#mc_embed_signup{
        clear:left; 
        font:14px Helvetica,Arial,sans-serif; 
        width:100%; 
        margin-top: 40px;
        margin-bottom: 40px;
        height:100px;
    }
    #mc_embed_signup .newsletter div{
        height: 100px;
    }
    #mc_embed_signup form{
        position: relative;
        top: -90px;
    }
	/* Add your own MailChimp form style overrides in your site stylesheet or in this style block.
	   We recommend moving this block and the preceding CSS link to the HEAD of your HTML file. */
&lt;/style&gt;

&lt;div id=&quot;mc_embed_signup&quot;&gt;
    &lt;div class=&quot;gradient newsletter&quot;&gt;
        &lt;div style=&quot;background:#000000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#1C0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#380000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#550000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#710000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#8D0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#AA0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#C60000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#E20000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF3800&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF5500&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF7100&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF8D00&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFAA00&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFC600&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFE200&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFFF00&quot;&gt;&lt;/div&gt;
    &lt;/div&gt;
    &lt;form action=&quot;https://IndexOutOfRange.us15.list-manage.com/subscribe/post?u=b1c1099bf7f49b95c64107c99&amp;amp;id=6a5eb68eb7&quot; method=&quot;post&quot; id=&quot;mc-embedded-subscribe-form&quot; name=&quot;mc-embedded-subscribe-form&quot; class=&quot;validate&quot; target=&quot;_blank&quot; novalidate=&quot;&quot;&gt;
        &lt;div id=&quot;mc_embed_signup_scroll&quot;&gt;
        &lt;label for=&quot;mce-EMAIL&quot; style=&quot;color: white;&quot;&gt;Get email notifications about new posts:&lt;/label&gt;
        &lt;input type=&quot;email&quot; value=&quot;&quot; name=&quot;EMAIL&quot; class=&quot;email&quot; id=&quot;mce-EMAIL&quot; placeholder=&quot;email address&quot; required=&quot;&quot; /&gt;
        &lt;!-- real people should not fill this in and expect good things - do not remove this or risk form bot signups--&gt;
        &lt;div style=&quot;position: absolute; left: -5000px;&quot; aria-hidden=&quot;true&quot;&gt;&lt;input type=&quot;text&quot; name=&quot;b_b1c1099bf7f49b95c64107c99_6a5eb68eb7&quot; tabindex=&quot;-1&quot; value=&quot;&quot; /&gt;&lt;/div&gt;
        &lt;div class=&quot;clear&quot;&gt;&lt;input type=&quot;submit&quot; value=&quot;Subscribe&quot; name=&quot;subscribe&quot; id=&quot;mc-embedded-subscribe&quot; class=&quot;button&quot; /&gt;&lt;/div&gt;
        &lt;/div&gt;
    &lt;/form&gt;
&lt;/div&gt;

&lt;!--End mc_embed_signup--&gt;

&lt;h2 id=&quot;azure-functions-advanced-tools-kudu&quot;&gt;Azure Functions Advanced tools (Kudu)&lt;/h2&gt;

&lt;p&gt;Azure functions offer a way to look into the underlying machine that is serving our functions - &lt;strong&gt;Kudu&lt;/strong&gt;. It can be accessed in two ways:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;using a link &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;https://FUNCTION_APP_NAME.scm.azurewebsites.net/&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;by clicking on the portal &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Platform features-&amp;gt;DEVELOPMENT TOOLS-&amp;gt;Advanced tools (Kudu)&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Kudu offers a lot of advanced functionalities (more than I have time to write in this blog post) but today we are interested in accessing the file system. This can be done by clicking the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Debug console-&amp;gt;CMD/Powershell&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/data/2018-01-08-Troubleshooting-compiled-Azure-Functions-in-F/kudu-file-system.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;This bings us to the file system, and cmd, explorer:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/data/2018-01-08-Troubleshooting-compiled-Azure-Functions-in-F/kudu-file-system-explorer.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;According to the error message, we are interested in two paths:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;MSBuild props: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;D:\Program Files (x86)\MSBuild-15.3.409.57025\MSBuild\Microsoft\VisualStudio\v15.0\FSharp\Microsoft.FSharp.NetSdk.props&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;FSharp props: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;D:\Program Files (x86)\Microsoft SDKs\F#\4.1\Framework\v4.0\Microsoft.FSharp.NetSdk.props&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To explore the file system we can use normal cmd commands, or just click using the graphic representation (don’t use the browser back button!).&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Kudu file explorer has some glitches:&lt;/p&gt;
  &lt;ul&gt;
    &lt;li&gt;for reasons unknown to me the only way to go upper than default &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;d:\home&lt;/code&gt; is to use the cmd &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cd ..&lt;/code&gt; command&lt;/li&gt;
    &lt;li&gt;entering the exact path to the folder using cd like: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cd D:\Program Files (x86)\MSBuild-15.3.409.57025\MSBuild\Microsoft\VisualStudio\v15.0\FSharp&lt;/code&gt; does work in cmd, but the graphic file representation doesn’t refresh&lt;/li&gt;
    &lt;li&gt;hitting Tab auto-completes the file/folder name (like in normal cmd), but only for the current level files/folders.&lt;/li&gt;
  &lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;After navigating to the first file, its content can be viewed using the pen icon on the left. And it looks like this:&lt;/p&gt;

&lt;div class=&quot;language-xml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;Project&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;xmlns=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;http://schemas.microsoft.com/developer/msbuild/2003&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;

  &lt;span class=&quot;nt&quot;&gt;&amp;lt;Import&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Project=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;$(MSBuildProgramFiles32)\Microsoft SDKs\F#\4.1\Framework\v4.0\Microsoft.FSharp.NetSdk.targets&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;

&lt;span class=&quot;nt&quot;&gt;&amp;lt;/Project&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;So indeed &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;D:\Program Files (x86)\Microsoft SDKs\F#\4.1\Framework\v4.0\Microsoft.FSharp.NetSdk.props&lt;/code&gt; is the file we are looking for.&lt;/p&gt;

&lt;h3 id=&quot;locating-the-problem&quot;&gt;Locating the problem&lt;/h3&gt;

&lt;p&gt;Trying to locate the file will end on the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;D:\Program Files (x86)\Microsoft SDKs\F#\&lt;/code&gt; part of the file since it looks like this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/data/2018-01-08-Troubleshooting-compiled-Azure-Functions-in-F/kudu-file-explorer-fsharp.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;See what is wrong?&lt;/p&gt;

&lt;p&gt;The first prop file (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Microsoft.FSharp.NetSdk.props&lt;/code&gt;) is pointing to
&lt;strong&gt;D:\Program Files (x86)\Microsoft SDKs\F#\4.1&lt;/strong&gt;, but in the &lt;strong&gt;F#&lt;/strong&gt; there is only a &lt;strong&gt;4.0&lt;/strong&gt; folder, so MSBuild reports a missing file.&lt;/p&gt;

&lt;h2 id=&quot;how-to-solve-it&quot;&gt;How to solve it?&lt;/h2&gt;

&lt;p&gt;The fastest, but not the cleanest, solution would be to upload the missing files. While Kudu supports file upload, it is only allowed in specific folders, and this is not one of them :(.
The second solution is to use the fact that Azure Functions are hosted like an IIS website and use WebDeploy for deploying a prepared package. How to use VSTS for package creation and build/deployment automation - in the next post.&lt;/p&gt;

&lt;style&gt;
.entry-content img

{
    margin: 0 auto;
    display: block;
}
&lt;/style&gt;

</description>
        <pubDate>Mon, 08 Jan 2018 00:00:00 +0100</pubDate>
        <link>https://IndexOutOfRange.com//Troubleshooting-compiled-Azure-Functions-in-F/</link>
        <guid isPermaLink="true">https://IndexOutOfRange.com//Troubleshooting-compiled-Azure-Functions-in-F/</guid>
      </item>
    
      <item>
        <title>The missing Azure Functions documentation</title>
        <description>&lt;img src='https://indexoutofrange.com/data/2018-01-01-The-missing-Azure-Functions-documentation/logo.jpg' /&gt;&lt;p&gt;Trying to understand how to run code in Azure Functions is not an easy task since this product has evolved on its own and thanks to the rise of .NET Core. This post will give You a history background necessary to understand the documentation and, most of all, all the blog posts talking about Azure Functions.&lt;/p&gt;

&lt;!--MORE--&gt;

&lt;h3 id=&quot;v10---script-files&quot;&gt;v1.0 - script files&lt;/h3&gt;

&lt;p&gt;The initial way to run code in Azure Function was to write a script file in Azure Functions portal editor. Yes, You read correctly - &lt;strong&gt;in the portal editor&lt;/strong&gt;. Later on, deployment support was added, so we could deploy the script files (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fsx&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;csx&lt;/code&gt;). 
It works good, but has some drawbacks:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;the compilation is done when the function is called for the first time (or called after an extended inactivity when Azure decided to kill the process)&lt;/li&gt;
  &lt;li&gt;IntelliSense support is quite clumsy&lt;/li&gt;
  &lt;li&gt;there is no compilation during development. When working on the code locally compiling the project did nothing since script files are not taken into account when compiling. This means that we are losing a lot of the benefits of a compiled language.&lt;/li&gt;
&lt;/ul&gt;

&lt;!-- Begin MailChimp Signup Form --&gt;

&lt;link href=&quot;//cdn-images.mailchimp.com/embedcode/horizontal-slim-10_7.css&quot; rel=&quot;stylesheet&quot; type=&quot;text/css&quot; /&gt;

&lt;style type=&quot;text/css&quot;&gt;
	#mc_embed_signup{
        clear:left; 
        font:14px Helvetica,Arial,sans-serif; 
        width:100%; 
        margin-top: 40px;
        margin-bottom: 40px;
        height:100px;
    }
    #mc_embed_signup .newsletter div{
        height: 100px;
    }
    #mc_embed_signup form{
        position: relative;
        top: -90px;
    }
	/* Add your own MailChimp form style overrides in your site stylesheet or in this style block.
	   We recommend moving this block and the preceding CSS link to the HEAD of your HTML file. */
&lt;/style&gt;

&lt;div id=&quot;mc_embed_signup&quot;&gt;
    &lt;div class=&quot;gradient newsletter&quot;&gt;
        &lt;div style=&quot;background:#000000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#1C0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#380000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#550000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#710000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#8D0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#AA0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#C60000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#E20000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF3800&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF5500&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF7100&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF8D00&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFAA00&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFC600&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFE200&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFFF00&quot;&gt;&lt;/div&gt;
    &lt;/div&gt;
    &lt;form action=&quot;https://IndexOutOfRange.us15.list-manage.com/subscribe/post?u=b1c1099bf7f49b95c64107c99&amp;amp;id=6a5eb68eb7&quot; method=&quot;post&quot; id=&quot;mc-embedded-subscribe-form&quot; name=&quot;mc-embedded-subscribe-form&quot; class=&quot;validate&quot; target=&quot;_blank&quot; novalidate=&quot;&quot;&gt;
        &lt;div id=&quot;mc_embed_signup_scroll&quot;&gt;
        &lt;label for=&quot;mce-EMAIL&quot; style=&quot;color: white;&quot;&gt;Get email notifications about new posts:&lt;/label&gt;
        &lt;input type=&quot;email&quot; value=&quot;&quot; name=&quot;EMAIL&quot; class=&quot;email&quot; id=&quot;mce-EMAIL&quot; placeholder=&quot;email address&quot; required=&quot;&quot; /&gt;
        &lt;!-- real people should not fill this in and expect good things - do not remove this or risk form bot signups--&gt;
        &lt;div style=&quot;position: absolute; left: -5000px;&quot; aria-hidden=&quot;true&quot;&gt;&lt;input type=&quot;text&quot; name=&quot;b_b1c1099bf7f49b95c64107c99_6a5eb68eb7&quot; tabindex=&quot;-1&quot; value=&quot;&quot; /&gt;&lt;/div&gt;
        &lt;div class=&quot;clear&quot;&gt;&lt;input type=&quot;submit&quot; value=&quot;Subscribe&quot; name=&quot;subscribe&quot; id=&quot;mc-embedded-subscribe&quot; class=&quot;button&quot; /&gt;&lt;/div&gt;
        &lt;/div&gt;
    &lt;/form&gt;
&lt;/div&gt;

&lt;!--End mc_embed_signup--&gt;

&lt;h3 id=&quot;v11---compiled-functions&quot;&gt;v1.1 - compiled functions&lt;/h3&gt;

&lt;p&gt;Microsoft addressed most problems with script files with the introduction of compiled functions. This was not a change to how they worked since Azure Functions are hosted in WebJobs, so as IIS application. Compilation can be done two ways:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;by deploying project code&lt;/strong&gt;. When we deploy a project (csproj/fsproj/sln) Azure Functions machine will trigger compilation on the hosted machine, deploy the result to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;wwwroot&lt;/code&gt; as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Default Website&lt;/code&gt; and run discovery looking for functions declaration (this is done by a config file or special attributes).&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;by deploying compiled code&lt;/strong&gt;. This does not mean that we have to store binaries in the repository (although it would work). This means that we can treat Azure Functions as an IIS Website and use the good (?) old Web Deploy that we have been using since ASP.NET (btw. VSTS has an excellent configuration for Azure Functions deployment)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Why should we bother with option two since Azure can handle it? Option one (deploying just code) has some drawbacks:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;compilation is limited to .NET 4.6.1 (this is the version installed on the Azure Functions machines)&lt;/li&gt;
  &lt;li&gt;use of custom steps like Paket or Fake requires manual upload to the hosting machine to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tools&lt;/code&gt; folder for them to work.&lt;/li&gt;
  &lt;li&gt;if we want to change the build process we have to change the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.deployment&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;deploy.cmd&lt;/code&gt; files and checking them into our repository. So from now on, we are responsible for maintaining and troubleshooting them, not Microsoft. Also, there is no point in looking for documentation for them (but they are quite easy batch scripts).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;v20---azure-functions-v20&quot;&gt;v2.0 - Azure Functions v2.0&lt;/h3&gt;

&lt;p&gt;Azure Functions 2.0 (in beta at the time of writing) is Azure Functions running on Linux (the OS can be selected when creating the Function App):
&lt;img src=&quot;/data/2018-01-01-The-missing-Azure-Functions-documentation/AzureFunctions2.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;There are some changes/limitations compared to version 1.0:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;the OS is Linux&lt;/li&gt;
  &lt;li&gt;runtime is .NET Core&lt;/li&gt;
  &lt;li&gt;only C#, F#, JavaScript and Java is supported (Azure functions 1.0 supported Batch, C#, F#, JavaScript, PowerShell, Bash, Python, and TypeScript)&lt;/li&gt;
  &lt;li&gt;&lt;del&gt;there is no consumption plan billing (as of the time of writing, but I’m sure that one will be offered they go to stable)&lt;/del&gt; (apparently this is a false assumption - look at the comments)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Of course, there are some benefits:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;.NET  Core is faster and consumes less memory. It is a significant benefit since in Azure Functions we are paying for execution time and used memory so expect a lower bill.&lt;/li&gt;
  &lt;li&gt;I suspect Linux offering will be a bit cheaper (VM with Linux tend to be less expensive)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;

&lt;p&gt;Azure Functions is evolving fast so make sure to look at the date when project/documentation/blog post was recently updated.&lt;/p&gt;

</description>
        <pubDate>Mon, 01 Jan 2018 00:00:00 +0100</pubDate>
        <link>https://IndexOutOfRange.com//The-missing-Azure-Functions-documentation/</link>
        <guid isPermaLink="true">https://IndexOutOfRange.com//The-missing-Azure-Functions-documentation/</guid>
      </item>
    
      <item>
        <title>What is the problem with key-value databases and how wide column stores solve it.</title>
        <description>&lt;img src='https://indexoutofrange.com/data/2017-04-10-What-is-the-problem-with-key-value-databases-and-how-wide-column-stores-solve-it/logo.jpg' /&gt;&lt;p&gt;&lt;a href=&quot;/Want-unlimited-scale-and-performanceThis-is-where-to-start/&quot;&gt;Previously I’ve wrote about key-value databases&lt;/a&gt;. They are awesome - ultra-fast, simple, can scale almost linear with the number of nodes. So why bother with complicating them?&lt;/p&gt;

&lt;p&gt;Well, they have some issues.&lt;/p&gt;

&lt;!--MORE--&gt;

&lt;h1 id=&quot;problems-with-key-value-databases&quot;&gt;Problems with key-value databases&lt;/h1&gt;

&lt;p&gt;The central concept of a key-value database is that the database doesn’t care what the is value. It may have some assumptions, &lt;a href=&quot;/Want-unlimited-scale-and-performanceThis-is-where-to-start#Redis&quot;&gt;like Redis&lt;/a&gt;, but the structure of the data is not of its interest. This leads to some limitations that can be problematic in some scenarios.&lt;/p&gt;

&lt;h2 id=&quot;1-cant-filter-on-value-fields&quot;&gt;1. Can’t filter on value fields&lt;/h2&gt;

&lt;p&gt;Quite evident since from the database point of view value is a blob.&lt;/p&gt;

&lt;h2 id=&quot;2-the-whole-value-is-returned&quot;&gt;2. The whole value is returned&lt;/h2&gt;

&lt;p&gt;This may not seem as a problem, but remember, key-value databases are chosen for speed. When looking at a flow of retrieving data from a database:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/data/2017-04-10-What-is-the-problem-with-key-value-databases-and-how-wide-column-stores-solve-it/database-request-flow.png&quot; alt=&quot;&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Most of the steps performance is dependent on the &lt;strong&gt;size of the transmitted data, not the data used&lt;/strong&gt; (this is why &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SELECT *&lt;/code&gt; is a sign of someone not giving a f**k about performance).&lt;/p&gt;

&lt;h2 id=&quot;3-the-value-can-be-updated-only-as-a-whole&quot;&gt;3. The value can be updated only as a whole&lt;/h2&gt;

&lt;p&gt;It is a problem because we have to:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;get the complete data to the client (see point above)&lt;/li&gt;
  &lt;li&gt;operate on the entire data&lt;/li&gt;
  &lt;li&gt;send the whole data back to the database&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sounds not that bad, even good. We want to have the whole object when updating it, right?&lt;/p&gt;

&lt;p&gt;Think about those cases:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;update users last login date&lt;/li&gt;
  &lt;li&gt;append the element to the list (like online checkout basket)&lt;/li&gt;
  &lt;li&gt;change the prices on certain products because of a promotion&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;center-text&quot;&gt;&lt;b&gt; So how to solve those problems and not loose all that speed? &lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;

&lt;h1 id=&quot;wide-column-databases&quot;&gt;Wide column databases&lt;/h1&gt;

&lt;p&gt;The idea behind it is simple:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Let's structure data (that is the value part) again into key-value pairs.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This is hat we have in key-value databases:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/data/2017-04-10-What-is-the-problem-with-key-value-databases-and-how-wide-column-stores-solve-it/key-value.png&quot; alt=&quot;&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;This is how wide column databases represent data:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/data/2017-04-10-What-is-the-problem-with-key-value-databases-and-how-wide-column-stores-solve-it/wide-column.png&quot; alt=&quot;&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Having columns allows defining a subset of data we want to return to the client or subset of data that should be updated.&lt;/p&gt;

&lt;h2 id=&quot;how-is-it-different-from-a-regular-table-in-a-relational-database&quot;&gt;How is it different from a regular table in a relational database?&lt;/h2&gt;

&lt;p&gt;In most wide column databases, columns are defined on the &lt;strong&gt;single item level&lt;/strong&gt; meaning there is no database-wide schema, which leads us to some interesting features of wide column databases:&lt;/p&gt;

&lt;h2 id=&quot;benefits-from-wide-column-databases&quot;&gt;Benefits from wide column databases&lt;/h2&gt;

&lt;p&gt;While wide column databases keep most of the &lt;a href=&quot;/Want-unlimited-scale-and-performanceThis-is-where-to-start/&quot;&gt;perks of key-value databases mentioned previously&lt;/a&gt; they have some additional ones (They don’t have to exist in every implementation of a wide-column database, but most of them have it):&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;partial operations&lt;/strong&gt; (add column value, update column value).&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;data compression&lt;/strong&gt;. When dealing with sparse data we don’t have to store empty/null values. This way we can save space normally reserved because schema defined them.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;WHERE clause&lt;/strong&gt;. This feature is not that common in this type of databases, but filtering on data starts to appear.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the next post a sample domain modeling using a wide-column database.&lt;/p&gt;

&lt;style&gt;
.center-image
{
    margin: 0 auto;
    display: block;
}
.center-text{
    text-align: center;
    font-size: 1.5em;
}
&lt;/style&gt;

</description>
        <pubDate>Mon, 10 Apr 2017 00:00:00 +0200</pubDate>
        <link>https://IndexOutOfRange.com//What-is-the-problem-with-key-value-databases-and-how-wide-column-databases-solve-it/</link>
        <guid isPermaLink="true">https://IndexOutOfRange.com//What-is-the-problem-with-key-value-databases-and-how-wide-column-databases-solve-it/</guid>
      </item>
    
      <item>
        <title>Want unlimited scale and performance? This is where to start</title>
        <description>&lt;img src='https://indexoutofrange.com/data/2017-03-28-Want-unlimited-scale-and-performanceThis-is-where-to-start/logo.jpg' /&gt;&lt;p&gt;The &lt;a href=&quot;/What-is-the-simplest-database/&quot; target=&quot;_blank&quot;&gt;previous post&lt;/a&gt; laid out the most minimum requirements for something to be called a database. While they may be too bare bones for many, there are a lot of databases that don’t fulfill even half of them, and this isn’t stopping from using them on a daily basis.&lt;/p&gt;

&lt;p&gt;The last time I’ve looked at files, this time something a bit more complex - key-value databases.&lt;/p&gt;

&lt;!--MORE--&gt;

&lt;h1 id=&quot;the-idea&quot;&gt;The idea&lt;/h1&gt;

&lt;p&gt;The idea behind key-value databases is very simple:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Store and retrieve objects based on a key.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;So we are saying goodbye to:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;tables, columns or ant data typing - everything is a blob of some kind&lt;/li&gt;
  &lt;li&gt;relations&lt;/li&gt;
  &lt;li&gt;complex operations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We gave almost everything,  what do we gain in exchange?&lt;/p&gt;

&lt;h1 id=&quot;why-use-a-key-value-database&quot;&gt;Why use a key-value database?&lt;/h1&gt;

&lt;h2 id=&quot;speed&quot;&gt;Speed&lt;/h2&gt;

&lt;p&gt;If You are thinking that getting the object from a key-value database is more or less the same as an index lookup in a relational database, keep on reading because You are very wrong, an order of &lt;a href=&quot;https://en.wikipedia.org/wiki/Big_O_notation&quot; target=&quot;_blank&quot;&gt;big &lt;strong&gt;O&lt;/strong&gt;&lt;/a&gt; wrong.&lt;/p&gt;

&lt;p&gt;Indexes in relational databases are implemented using a &lt;a href=&quot;https://en.wikipedia.org/wiki/B-tree&quot; target=&quot;_blank&quot;&gt;B-Tree structure&lt;/a&gt; that looks like this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/data/2017-03-28-Want-unlimited-scale-and-performanceThis-is-where-to-start/B-tree.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;This is one of the most fundamental data structure in modern computer science. If You don’t know it please at least read &lt;a href=&quot;https://en.wikipedia.org/wiki/B-tree&quot; target=&quot;_blank&quot;&gt;this Wikipedia page&lt;/a&gt;. It will be a time well spend.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;While this is a remarkable structure it has to obey the rules of mathematics when it comes to the cost of search:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;O(log(n/m))&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;where:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;n - the total number of elements&lt;/li&gt;
  &lt;li&gt;m - the number of items in a single node.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To contrast it, &lt;strong&gt;most&lt;/strong&gt; key-value databases store the data in memory, so they can use a hashing function to determine the position of the element in the array. It’s cost is:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;O(1)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;You can’t get any better than this.&lt;/p&gt;

&lt;h2 id=&quot;simplicity&quot;&gt;Simplicity&lt;/h2&gt;

&lt;p&gt;If something is simple it breaks less often, is easier to maintain and to reason about. Without this simplicity, we wouldn’t have the next point.&lt;/p&gt;

&lt;h2 id=&quot;horizontal-scaling&quot;&gt;Horizontal scaling&lt;/h2&gt;

&lt;p&gt;When we introduce the following rules, that most key-value databases implement:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;the key is the only way to identify an item&lt;/li&gt;
  &lt;li&gt;the hash function transforms the key into an integer in a deterministic way&lt;/li&gt;
  &lt;li&gt;we aren’t doing any, or are limiting the scope, of aggregate operations&lt;/li&gt;
  &lt;li&gt;update changes the &lt;strong&gt;whole&lt;/strong&gt; value (since the database doesn’t know about the schema of the item). There are some databases that bypassed this rule. For more keep on reading.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Having those assumptions allow scaling such a solution horizontally easily. In the most simplistic way:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hash(key) % NUMBER_OF_SERVERS&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;While an oversimplification, but some key-value databases use it.&lt;/p&gt;

&lt;!-- Begin MailChimp Signup Form --&gt;

&lt;link href=&quot;//cdn-images.mailchimp.com/embedcode/horizontal-slim-10_7.css&quot; rel=&quot;stylesheet&quot; type=&quot;text/css&quot; /&gt;

&lt;style type=&quot;text/css&quot;&gt;
	#mc_embed_signup{
        clear:left; 
        font:14px Helvetica,Arial,sans-serif; 
        width:100%; 
        margin-top: 40px;
        margin-bottom: 40px;
        height:100px;
    }
    #mc_embed_signup .newsletter div{
        height: 100px;
    }
    #mc_embed_signup form{
        position: relative;
        top: -90px;
    }
	/* Add your own MailChimp form style overrides in your site stylesheet or in this style block.
	   We recommend moving this block and the preceding CSS link to the HEAD of your HTML file. */
&lt;/style&gt;

&lt;div id=&quot;mc_embed_signup&quot;&gt;
    &lt;div class=&quot;gradient newsletter&quot;&gt;
        &lt;div style=&quot;background:#000000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#1C0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#380000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#550000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#710000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#8D0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#AA0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#C60000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#E20000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF3800&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF5500&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF7100&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF8D00&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFAA00&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFC600&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFE200&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFFF00&quot;&gt;&lt;/div&gt;
    &lt;/div&gt;
    &lt;form action=&quot;https://IndexOutOfRange.us15.list-manage.com/subscribe/post?u=b1c1099bf7f49b95c64107c99&amp;amp;id=6a5eb68eb7&quot; method=&quot;post&quot; id=&quot;mc-embedded-subscribe-form&quot; name=&quot;mc-embedded-subscribe-form&quot; class=&quot;validate&quot; target=&quot;_blank&quot; novalidate=&quot;&quot;&gt;
        &lt;div id=&quot;mc_embed_signup_scroll&quot;&gt;
        &lt;label for=&quot;mce-EMAIL&quot; style=&quot;color: white;&quot;&gt;Get email notifications about new posts:&lt;/label&gt;
        &lt;input type=&quot;email&quot; value=&quot;&quot; name=&quot;EMAIL&quot; class=&quot;email&quot; id=&quot;mce-EMAIL&quot; placeholder=&quot;email address&quot; required=&quot;&quot; /&gt;
        &lt;!-- real people should not fill this in and expect good things - do not remove this or risk form bot signups--&gt;
        &lt;div style=&quot;position: absolute; left: -5000px;&quot; aria-hidden=&quot;true&quot;&gt;&lt;input type=&quot;text&quot; name=&quot;b_b1c1099bf7f49b95c64107c99_6a5eb68eb7&quot; tabindex=&quot;-1&quot; value=&quot;&quot; /&gt;&lt;/div&gt;
        &lt;div class=&quot;clear&quot;&gt;&lt;input type=&quot;submit&quot; value=&quot;Subscribe&quot; name=&quot;subscribe&quot; id=&quot;mc-embedded-subscribe&quot; class=&quot;button&quot; /&gt;&lt;/div&gt;
        &lt;/div&gt;
    &lt;/form&gt;
&lt;/div&gt;

&lt;!--End mc_embed_signup--&gt;

&lt;h1 id=&quot;what-not-to-expect-from-key-value-databases&quot;&gt;What not to expect from key-value databases&lt;/h1&gt;

&lt;p&gt;If You have been living in RDMS land here are some things not to look for in key-value databases:&lt;/p&gt;

&lt;h2 id=&quot;transactions&quot;&gt;Transactions&lt;/h2&gt;

&lt;p&gt;It is very rare to see them in key-value databases. Instead, we have &lt;strong&gt;atomicity&lt;/strong&gt;. What is the difference?&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Atomicity&lt;/strong&gt; - means that the operation will execute or not. In short, in the case of failure, we won’t end up with corrupted or partially changed data.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Transactionality&lt;/strong&gt; - a series of multiple operations that will execute atomicity as one.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Is the lack of transactions a problem? No. Let’s examine the cases when we would use them:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SELECT&lt;/code&gt; - no need for transactions. We ask for an element and get it back.&lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DELETE&lt;/code&gt;- single &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DELETE&lt;/code&gt; is atomic, so no problem here. The need could arrive when doing multiple deletes. This case boils down to the fact how did we get the keys of the elements to delete?&lt;/p&gt;

    &lt;ul&gt;
      &lt;li&gt;If we stored those keys as a value of another key - go to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;complex statements flows&lt;/code&gt;.&lt;/li&gt;
      &lt;li&gt;If we want to remove values, which keys fulfill some pattern then just retry the delete.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;UPDATE&lt;/code&gt; - the same as with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DELETE&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;complex statements flows&lt;/code&gt; - the need for it happens when the value of one key contains keys that should be, for example, deleted. This means that there is a relation, and this means that we are trying to simulate an RDMS on top of a key-value database, and it’s not a good idea.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;examples&quot;&gt;Examples&lt;/h2&gt;

&lt;p&gt;While those are very simple databases, they differ quite significantly. To show that let’s examine &lt;a href=&quot;http://db-engines.com/en/ranking/key-value+store&quot; target=&quot;_blank&quot;&gt;3 most popular key-value databases according to db-engines&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/data/2017-03-28-Want-unlimited-scale-and-performanceThis-is-where-to-start/memcached.jpg&quot; alt=&quot;&quot; class=&quot;logo&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;memcached&quot;&gt;Memcached&lt;/h2&gt;

&lt;blockquote&gt;
  &lt;p&gt;Designed for: &lt;strong&gt;cache&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I’m starting from the third place and also from the oldest database in the ranking (initial release in 2003).
Memcached is not exactly a database since its main feature involves auto deleting data. Think of it as a massive, fixed size, in memory cache. When there is no more memory available Memcached will start removing elements using the LRU algorithm. It starts deleting the least used values until it frees enough memory to store the new value.  Memcached doesn’t have any option of persistence to disc, but let’s face it: there is no sense for persistence if the database can delete the data at any time.&lt;/p&gt;

&lt;p&gt;Since Memcached is a cache store it has some limits on key and value sizes:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;key: up to 250 bytes&lt;/li&gt;
  &lt;li&gt;value: up to 1MB&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s look at the must and should haves:&lt;/p&gt;

&lt;h3 id=&quot;must-haves&quot;&gt;Must-haves:&lt;/h3&gt;

&lt;ul class=&quot;task-list&quot;&gt;
  &lt;li&gt;[-] &lt;strong&gt;ability to reliably persist data&lt;/strong&gt; - Memcached will auto delete the oldest data, and we are talking about a database that stores everything in memory, so let’s not call it &lt;em&gt;reliable persistence&lt;/em&gt;.&lt;/li&gt;
  &lt;li&gt;[-] &lt;strong&gt;ability to reliably retrieve data&lt;/strong&gt; - If the data wasn’t deleted it will be returned.&lt;/li&gt;
  &lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; class=&quot;task-list-item-checkbox&quot; disabled=&quot;disabled&quot; checked=&quot;checked&quot; /&gt;&lt;strong&gt;ability to delete data&lt;/strong&gt; - using &lt;a href=&quot;https://www.tutorialspoint.com/memcached/memcached_delete_key.htm&quot; target=&quot;_blank&quot;&gt;delete command&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;should-haves&quot;&gt;Should-haves:&lt;/h3&gt;

&lt;ul class=&quot;task-list&quot;&gt;
  &lt;li&gt;[-] &lt;strong&gt;ability to query data&lt;/strong&gt; - We can’t do any matching on keys.&lt;/li&gt;
  &lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; class=&quot;task-list-item-checkbox&quot; disabled=&quot;disabled&quot; checked=&quot;checked&quot; /&gt;&lt;strong&gt;ability to update data&lt;/strong&gt; - We can update the whole value. No partial updates.&lt;/li&gt;
  &lt;li class=&quot;task-list-item&quot;&gt;[-] &lt;strong&gt;has transactions&lt;/strong&gt; - No the case in this databases.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;img src=&quot;/data/2017-03-28-Want-unlimited-scale-and-performanceThis-is-where-to-start/riak.png&quot; alt=&quot;&quot; class=&quot;logo&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;riak&quot;&gt;Riak&lt;/h2&gt;

&lt;blockquote&gt;
  &lt;p&gt;Designed for: key-value database synchronized across multiple data centers&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Riak, an implementation of &lt;a href=&quot;http://www.allthingsdistributed.com/files/amazon-dynamo-sosp2007.pdf&quot; target=&quot;_blank&quot;&gt;Amazon Dynamo paper&lt;/a&gt;,  is an entirely different beast than Memcached and was build to solve other problems. It is also the closes we get to a database in the classical definition. It’s a distributed, cross data center, persistent key-value database aiming for availability, even at the cost of consistency. The above statement contains a lot of information, so let’s decompose.&lt;/p&gt;

&lt;h3 id=&quot;data-types&quot;&gt;Data types&lt;/h3&gt;

&lt;p&gt;Key-value databases treat stored values as blobs, but some of them implement types that have a particular purpose and have separate API. In Riak case its:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://docs.basho.com/riak/kv/2.2.1/developing/data-types/maps/#flags&quot; target=&quot;_blank&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Flags&lt;/code&gt;&lt;/a&gt; - true/false values. Can only be used inside a map type.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://docs.basho.com/riak/kv/2.2.1/developing/data-types/maps/#registers&quot; target=&quot;_blank&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Registers&lt;/code&gt;&lt;/a&gt; - named binaries. Also can only be used inside a map&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://docs.basho.com/riak/kv/2.2.1/developing/data-types/counters/&quot; target=&quot;_blank&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Counters&lt;/code&gt;&lt;/a&gt; - as the number suggests incremented integers. Can be used in a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;map&lt;/code&gt; and as a value on its own.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://docs.basho.com/riak/kv/2.2.1/developing/data-types/sets/&quot; target=&quot;_blank&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Sets&lt;/code&gt;&lt;/a&gt; - collection of binary values. Similar to the Counter type can be used on its own and in a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;map&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://docs.basho.com/riak/kv/2.2.1/developing/data-types/maps/&quot; target=&quot;_blank&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Maps&lt;/code&gt;&lt;/a&gt; - collection of values. Differently than Sets they can contain other data types, even other maps.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://docs.basho.com/riak/kv/2.2.0/developing/data-types/hyperloglogs/&quot; target=&quot;_blank&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HyperLogLog&lt;/code&gt;&lt;/a&gt; - a probabilistic structure for checking cardinality of a set.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;clustering&quot;&gt;Clustering&lt;/h3&gt;

&lt;p&gt;Riak supports clustering with tunable consistency. How is it done? Since the cluster is a ring architecture, like this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/data/2017-03-28-Want-unlimited-scale-and-performanceThis-is-where-to-start/riak-ring.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Tuning the level of consistency is done by defining how many nodes have to accept the operation before it’s confirmed (default is 3).&lt;/p&gt;

&lt;p&gt;Riak goal from CAP is A, and it tries to achieve it by constructing a cluster where:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;nodes are organized in a ring&lt;/li&gt;
  &lt;li&gt;there are no master nodes&lt;/li&gt;
  &lt;li&gt;any node can accept writes for any key (no master node for a given hash value).&lt;/li&gt;
  &lt;li&gt;allows concurrent writes on multiple machines for a single key.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All of the above lead to the need to handle conflict resolution resolution. Riak recommends using custom types whenever possible, but it will also work with blob values. Behavior when dealing with conflicts can be configured, and ranges from &lt;a href=&quot;http://docs.basho.com/riak/kv/2.2.1/developing/usage/conflict-resolution/#timestamp-based-resolution&quot; target=&quot;_blank&quot;&gt;timestamp&lt;/a&gt;, &lt;a href=&quot;http://docs.basho.com/riak/kv/2.2.1/developing/usage/conflict-resolution/#last-write-wins&quot; target=&quot;_blank&quot;&gt;last-write-wins&lt;/a&gt; to &lt;a href=&quot;http://docs.basho.com/riak/kv/2.2.1/developing/usage/conflict-resolution/#resolve-conflicts-on-the-application-side&quot; target=&quot;_blank&quot;&gt;letting the client decide&lt;/a&gt;. 
One thing to note is that it’s not hard to find people complaining about &lt;a href=&quot;https://www.trustradius.com/reviews/riak-2015-12-01-11-11-07&quot; target=&quot;_blank&quot;&gt;Riak resurrecting deleted values even days after deletion&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;must-haves-1&quot;&gt;Must-haves:&lt;/h3&gt;

&lt;ul class=&quot;task-list&quot;&gt;
  &lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; class=&quot;task-list-item-checkbox&quot; disabled=&quot;disabled&quot; checked=&quot;checked&quot; /&gt;&lt;strong&gt;ability to reliably persist data&lt;/strong&gt; - This is one of the main points of Riak&lt;/li&gt;
  &lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; class=&quot;task-list-item-checkbox&quot; disabled=&quot;disabled&quot; checked=&quot;checked&quot; /&gt;&lt;strong&gt;ability to reliably retrieve data&lt;/strong&gt; - Since Riak consistency is tunable this point is also partly passed.&lt;/li&gt;
  &lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; class=&quot;task-list-item-checkbox&quot; disabled=&quot;disabled&quot; checked=&quot;checked&quot; /&gt;&lt;strong&gt;ability to delete data&lt;/strong&gt; - works, although &lt;a href=&quot;https://www.trustradius.com/reviews/riak-2015-12-01-11-11-07&quot; target=&quot;_blank&quot;&gt;resurecting deleted items is a reported problem&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;should-haves-1&quot;&gt;Should-haves:&lt;/h3&gt;

&lt;ul class=&quot;task-list&quot;&gt;
  &lt;li&gt;[-] &lt;strong&gt;ability to query data&lt;/strong&gt; - We can’t do any matching on keys, although it supports key searches using Solr.&lt;/li&gt;
  &lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; class=&quot;task-list-item-checkbox&quot; disabled=&quot;disabled&quot; checked=&quot;checked&quot; /&gt;&lt;strong&gt;ability to update data&lt;/strong&gt; - When using custom types they are possible. With blobs, no.&lt;/li&gt;
  &lt;li class=&quot;task-list-item&quot;&gt;[-] &lt;strong&gt;has transactions&lt;/strong&gt; - No transaction support.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;img src=&quot;/data/2017-03-28-Want-unlimited-scale-and-performanceThis-is-where-to-start/Redis.png&quot; alt=&quot;&quot; class=&quot;logo&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;redis&quot;&gt;&lt;a name=&quot;Redis&quot;&gt;&lt;/a&gt;Redis&lt;/h2&gt;

&lt;blockquote&gt;
  &lt;p&gt;Designed for: speed&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The number one should not be a shock to anyone. Redis is, as the full name suggests, a  &lt;strong&gt;RE&lt;/strong&gt;mote &lt;strong&gt;DI&lt;/strong&gt;ctionary &lt;strong&gt;S&lt;/strong&gt;erver. Over the years it has grown a few functionalities, but it still is a memory key-value dictionary.&lt;/p&gt;

&lt;h3 id=&quot;architecture&quot;&gt;Architecture&lt;/h3&gt;

&lt;p&gt;Redis show that simplicity is speed. Important thing to note is that it is mainly an in-memory store with &lt;a href=&quot;https://redis.io/topics/persistence&quot; target=&quot;_blank&quot;&gt;&lt;em&gt;optional&lt;/em&gt; persistence&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;point in time snapshot&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;A&lt;/strong&gt;ppend &lt;strong&gt;O&lt;/strong&gt;nly &lt;strong&gt;F&lt;/strong&gt;ile with async writes&lt;/li&gt;
  &lt;li&gt;both of the above&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Building upon the idea that &lt;em&gt;everything is a string&lt;/em&gt; Redis exposes an interface for manipulating the values right on the database, without the need to send them to the client.&lt;br /&gt;
One last thing to note is that Redis has the option to write Lua scripts.&lt;/p&gt;

&lt;h3 id=&quot;data-structures&quot;&gt;Data structures&lt;/h3&gt;

&lt;p&gt;Redis, similarly to Riak implements custom data structure, but nonstructured data is stored as a string, not as binary. Custom data structures are:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Binary-safe string&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Lists&lt;/code&gt; - collections of strings sorted according to the order of insertion (a linked list)&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Sets&lt;/code&gt; -  collections of unique, unsorted strings.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Sorted sets&lt;/code&gt; - similar to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Sets&lt;/code&gt; but every string has a score (a floating number). Elements are sorted by score, so unlike &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Sets&lt;/code&gt; it is possible to retrieve ranges like top or bottom 10.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Hashes&lt;/code&gt; - maps composed of fields associated with values. Both the field and the value are strings.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Bit arrays&lt;/code&gt; - allows to set, clear, count and find the first set or unset bit.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HyperLogLogs&lt;/code&gt; - the same as in Riak&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;clustering-1&quot;&gt;Clustering&lt;/h3&gt;

&lt;p&gt;Redis is taking a different approach to clustering than the previous two:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;all nodes are connected&lt;/li&gt;
  &lt;li&gt;values are automatically propagated to multiple servers&lt;/li&gt;
  &lt;li&gt;has the concept of master and slave datasets&lt;/li&gt;
  &lt;li&gt;it does not guarantee &lt;a href=&quot;https://redis.io/topics/cluster-tutorial&quot; target=&quot;_blank&quot;&gt;strong constistency&lt;/a&gt;, but it can be achieved using &lt;a href=&quot;https://redis.io/commands/wait&quot;&gt;WAIT&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;it if advised for the client to keep an up to date routing table of the cluster&lt;/li&gt;
  &lt;li&gt;it can detect not responding and new nodes.&lt;/li&gt;
  &lt;li&gt;nodes do not proxy requests. This means that if we request a key not present on the current node the server will return &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MOVED&lt;/code&gt; command to the client.&lt;/li&gt;
  &lt;li&gt;multi-node commands and Lua scripts are limited to near keys (no cross server operations)&lt;/li&gt;
  &lt;li&gt;replication is asynchronous&lt;/li&gt;
  &lt;li&gt;only one node accepts a write for a given key&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;pub-sub&quot;&gt;Pub-sub&lt;/h3&gt;

&lt;p&gt;One feature that is unique to Redis, and to key-value databases in general (since it is not a database feature) is &lt;a href=&quot;https://redis.io/topics/pubsub&quot;&gt;pub sub capability of Redis&lt;/a&gt;. With features as full cluster support and pattern matching for subscriptions, it is a first class citizen in Redis features and works quite well.&lt;/p&gt;

&lt;h3 id=&quot;must-haves-2&quot;&gt;Must-haves:&lt;/h3&gt;

&lt;ul class=&quot;task-list&quot;&gt;
  &lt;li&gt;[-] &lt;strong&gt;ability to reliably persist data&lt;/strong&gt; - This is not the main goal of Redis. Provided persistence options don’t give 100% certainty of data recovery in case of for example power failure.&lt;/li&gt;
  &lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; class=&quot;task-list-item-checkbox&quot; disabled=&quot;disabled&quot; checked=&quot;checked&quot; /&gt;&lt;strong&gt;ability to reliably retrieve data&lt;/strong&gt; - Redis has the notion of a master node for a given key and if we don’t mess with the routing table data will be returned reliably.&lt;/li&gt;
  &lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; class=&quot;task-list-item-checkbox&quot; disabled=&quot;disabled&quot; checked=&quot;checked&quot; /&gt;&lt;strong&gt;ability to delete data&lt;/strong&gt; - just works.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;should-haves-2&quot;&gt;Should-haves:&lt;/h3&gt;

&lt;ul class=&quot;task-list&quot;&gt;
  &lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; class=&quot;task-list-item-checkbox&quot; disabled=&quot;disabled&quot; checked=&quot;checked&quot; /&gt;&lt;strong&gt;ability to query data&lt;/strong&gt; - Redis exposes API to search for keys matching a pattern. What to note is &lt;strong&gt;it will return the keys, not the values&lt;/strong&gt;.&lt;/li&gt;
  &lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; class=&quot;task-list-item-checkbox&quot; disabled=&quot;disabled&quot; checked=&quot;checked&quot; /&gt;&lt;strong&gt;ability to update data&lt;/strong&gt; - Works with custom types, and with blobs. Since everything is a string Redis provides string operations that are executed on the server and thus don’t require a round trip to the client.&lt;/li&gt;
  &lt;li class=&quot;task-list-item&quot;&gt;[o] &lt;strong&gt;has transactions&lt;/strong&gt; - As Funbit and Alex pointed out, there are transactions in Redis. In Lua scripts and using the &lt;a href=&quot;https://redis.io/topics/transactions&quot;&gt;MULTI statement&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;comparison&quot;&gt;Comparison&lt;/h1&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;Option&lt;/th&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;Memcached&lt;/th&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;Riak&lt;/th&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;Redis&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Key limits&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;250 bytes&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;No limit&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;No limit&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Value limits&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;1 MB&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;No limit&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;a href=&quot;https://redis.io/topics/data-types-intro#redis-strings&quot;&gt;512 MB&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Persistent&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;No&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Yes&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Optional&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Transactions&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;No&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;No&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Yes&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Connection protocol&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;TCP/IP&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;HTTP&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;TCP/IP&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Key scans&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;No&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Done with Solr&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Yes&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Scripting&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;No&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;No&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Yes(Lua)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Data schema&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;No&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Custom types + blob&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Custom types + blob&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Data stored&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;binary&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;binary&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;string&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Licence&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;BSD 3-clause&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Apache 2&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;BSD 3-clause&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt; &lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt; &lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt; &lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt; &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;Cluster&lt;/strong&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt; &lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt; &lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt; &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Cluster info&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Client knows all servers in cluster&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Client knows some nodes&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Client knows the routing table&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Cluster architecture&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;share nothing&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;ring&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;all connected&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Consistency&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Doesn’t apply&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Tunable from eventual to strong&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;No guarantee&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Replication&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;No&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Configurable&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Async&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Multi data center sync&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;No&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Yes&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Yes(only Enterprise version)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt; &lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt; &lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt; &lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt; &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Run on&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Windows/Linux/Unix&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Linux&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Windows/Linux&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Main features&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;auto deletion of data&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;multi data center replication&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;speed/pub-sub&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Build for&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;cache server&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Key-value store across multiple data centers&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;speed&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Big thanks to Łukasz Pyrzyk for proofreading and pointing out some mistackes. Go check out &lt;a href=&quot;http://pyrzyk.net&quot;&gt;his blog&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Next, wide column databases.&lt;/p&gt;

&lt;h2 id=&quot;further-reading&quot;&gt;Further reading:&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/HyperLogLog&quot; target=&quot;_blank&quot;&gt;HyperLogLogs data structure - Wikipedia&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://antirez.com/news/75&quot; target=&quot;_blank&quot;&gt;Very good analysys of HeyperLogLogs algorythm&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://redis.io/topics/cluster-tutorials&quot; target=&quot;_blank&quot;&gt;Redis cluster documentation&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Hash_table#Collision_resolution&quot; target=&quot;_blank&quot;&gt;Collision resolution&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://key-value-stories.blogspot.com/2015/01/redis-core-implementation.html&quot; target=&quot;_blank&quot;&gt;Top Level analysys of Redis architecture&lt;/a&gt; and a &lt;a href=&quot;https://groups.google.com/forum/#!topic/redis-dev/blzNXKjsBCk&quot; target=&quot;_blank&quot;&gt;conversation on Redis google group&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.g2crowd.com/products/riak/reviews&quot; target=&quot;_blank&quot;&gt;Riak reviews&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://db-engines.com/en/system/Memcached%3BRedis%3BRiak+KV&quot; target=&quot;_blank&quot;&gt;Most popular Key-value databases comparison on db-engines.com&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Memcached&quot; target=&quot;_blank&quot;&gt;Very good Memcached Wikipedia page&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;style&gt;
div.entry-content .logo{
    height:150px;
}
&lt;/style&gt;

</description>
        <pubDate>Tue, 28 Mar 2017 00:00:00 +0200</pubDate>
        <link>https://IndexOutOfRange.com//Want-unlimited-scale-and-performanceThis-is-where-to-start/</link>
        <guid isPermaLink="true">https://IndexOutOfRange.com//Want-unlimited-scale-and-performanceThis-is-where-to-start/</guid>
      </item>
    
      <item>
        <title>What is the simplest database?</title>
        <description>&lt;img src='https://indexoutofrange.com/data/2017-03-20-What-is-the-simplest-database/logo.jpg' /&gt;&lt;p&gt;The world of databases is a fascinating topic. It is very diverse. Many of them are extremely complex systems, but there are also very simple ones. There are the general purpose ones, and ones that do only one thing good, but they do it excelent. Despite all of this we tend to pick them just like we order food in a restaurant:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;I’ll take the same as last time. It wasn’t ideal for what I wanted, but I could pick worse.&lt;/li&gt;
  &lt;li&gt;Hmm… Everyone is taking this one, so I’ll take it also.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Well, maybe it is time to dig deeper into it?&lt;/p&gt;

&lt;!--MORE--&gt;

&lt;h2 id=&quot;preface&quot;&gt;Preface&lt;/h2&gt;

&lt;p&gt;I’m writing this post in addition to my &lt;a href=&quot;/speaking/cfp/You-are-using-the-wrong-database!/&quot;&gt;You are using the wrong database!&lt;/a&gt; talk which intention is to show:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;how important is picking the right database and how strongly it affects the whole system&lt;/li&gt;
  &lt;li&gt;How diverse is the world of databases.&lt;/li&gt;
  &lt;li&gt;Why the most common criterium for choosing: &lt;em&gt;“I’ll use what I know”&lt;/em&gt; sucks, putting it lightly.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;definition&quot;&gt;Definition&lt;/h2&gt;

&lt;p&gt;Here is where a copy and paste from Wikipedia typically happens, but let’s create a definition based a more look and feel approach and let’s define simple requirements.
I divided them into two parts: &lt;strong&gt;must-haves&lt;/strong&gt; and &lt;strong&gt;should-haves&lt;/strong&gt;. Here we go:&lt;/p&gt;

&lt;h3 id=&quot;must-haves&quot;&gt;Must haves&lt;/h3&gt;

&lt;p&gt;Those points are what, for me, defines a database. The core functionalities that make a product a database:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;ability to reliably persist data&lt;/strong&gt; - kind of a no-brainer, but this paragraph is just for that.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;ability to reliably retrieve data&lt;/strong&gt; - there is little use for a database that can only accept data but can’t retrieve it.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;ability to delete data&lt;/strong&gt; - the first point defines &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;INSERT&lt;/code&gt;, the second a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SELECT&lt;/code&gt; operation, so all that is missing is a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DELETE&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Only three points? Yes, but remember, we are talking about the must haves.&lt;/p&gt;

&lt;!-- Begin MailChimp Signup Form --&gt;

&lt;link href=&quot;//cdn-images.mailchimp.com/embedcode/horizontal-slim-10_7.css&quot; rel=&quot;stylesheet&quot; type=&quot;text/css&quot; /&gt;

&lt;style type=&quot;text/css&quot;&gt;
	#mc_embed_signup{
        clear:left; 
        font:14px Helvetica,Arial,sans-serif; 
        width:100%; 
        margin-top: 40px;
        margin-bottom: 40px;
        height:100px;
    }
    #mc_embed_signup .newsletter div{
        height: 100px;
    }
    #mc_embed_signup form{
        position: relative;
        top: -90px;
    }
	/* Add your own MailChimp form style overrides in your site stylesheet or in this style block.
	   We recommend moving this block and the preceding CSS link to the HEAD of your HTML file. */
&lt;/style&gt;

&lt;div id=&quot;mc_embed_signup&quot;&gt;
    &lt;div class=&quot;gradient newsletter&quot;&gt;
        &lt;div style=&quot;background:#000000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#1C0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#380000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#550000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#710000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#8D0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#AA0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#C60000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#E20000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF3800&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF5500&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF7100&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF8D00&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFAA00&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFC600&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFE200&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFFF00&quot;&gt;&lt;/div&gt;
    &lt;/div&gt;
    &lt;form action=&quot;https://IndexOutOfRange.us15.list-manage.com/subscribe/post?u=b1c1099bf7f49b95c64107c99&amp;amp;id=6a5eb68eb7&quot; method=&quot;post&quot; id=&quot;mc-embedded-subscribe-form&quot; name=&quot;mc-embedded-subscribe-form&quot; class=&quot;validate&quot; target=&quot;_blank&quot; novalidate=&quot;&quot;&gt;
        &lt;div id=&quot;mc_embed_signup_scroll&quot;&gt;
        &lt;label for=&quot;mce-EMAIL&quot; style=&quot;color: white;&quot;&gt;Get email notifications about new posts:&lt;/label&gt;
        &lt;input type=&quot;email&quot; value=&quot;&quot; name=&quot;EMAIL&quot; class=&quot;email&quot; id=&quot;mce-EMAIL&quot; placeholder=&quot;email address&quot; required=&quot;&quot; /&gt;
        &lt;!-- real people should not fill this in and expect good things - do not remove this or risk form bot signups--&gt;
        &lt;div style=&quot;position: absolute; left: -5000px;&quot; aria-hidden=&quot;true&quot;&gt;&lt;input type=&quot;text&quot; name=&quot;b_b1c1099bf7f49b95c64107c99_6a5eb68eb7&quot; tabindex=&quot;-1&quot; value=&quot;&quot; /&gt;&lt;/div&gt;
        &lt;div class=&quot;clear&quot;&gt;&lt;input type=&quot;submit&quot; value=&quot;Subscribe&quot; name=&quot;subscribe&quot; id=&quot;mc-embedded-subscribe&quot; class=&quot;button&quot; /&gt;&lt;/div&gt;
        &lt;/div&gt;
    &lt;/form&gt;
&lt;/div&gt;

&lt;!--End mc_embed_signup--&gt;

&lt;h3 id=&quot;should-haves&quot;&gt;Should-haves&lt;/h3&gt;

&lt;p&gt;So this is where I put all the theoretical features mumbling? Not exactly, here are my &lt;strong&gt;should-haves&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;ability to query data&lt;/strong&gt; - how this one differs from the must-haves ability to retrieve data? There we identified the data using a single key. Here we require the capacity to return a list of data that meets certain parameters. Think of it as the conditions on columns in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WHERE&lt;/code&gt; clause from SQL.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;ability to update data&lt;/strong&gt; - this, in theory, could be achieved by deleting and inserting a new record, but this implementation fails quite fast when taking into account a bit more advanced features (deleting and inserting would change the auto-generated ID, or could fail if the row was referenced).&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;has transactions&lt;/strong&gt; - I am not talking here about the more advanced things like isolation levels or distributed transactions, but the simple fact that if something fails while executing an update the database won’t get corrupted.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;the-simplest-database&quot;&gt;The simplest database&lt;/h2&gt;

&lt;p&gt;Go on have a guess. What is the simplest database that fulfills all the must-haves and almost all should-haves?&lt;/p&gt;

&lt;p&gt;Are You sure You know? Think again, but if You are sure&lt;/p&gt;

&lt;div class=&quot;center&quot; id=&quot;wrapper&quot;&gt;
    &lt;div type=&quot;button&quot; class=&quot;button btn&quot; onclick=&quot;show()&quot;&gt;CLICK HERE if You know &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&quot;entry-image-index&quot; style=&quot;background:url('/data/2017-03-20-What-is-the-simplest-database/files.png') no-repeat scroll center center; background-size: cover;&quot;&gt; &lt;/div&gt;

&lt;h3 id=&quot;file-system-is-the-simplest-database&quot;&gt;File system is the simplest database&lt;/h3&gt;

&lt;p&gt;Did You get it right? Do You believe it? Let’s got through the lists.
&lt;strong&gt;Must haves:&lt;/strong&gt;&lt;/p&gt;

&lt;ul class=&quot;task-list&quot;&gt;
  &lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; class=&quot;task-list-item-checkbox&quot; disabled=&quot;disabled&quot; checked=&quot;checked&quot; /&gt;&lt;strong&gt;ability to reliable persist data&lt;/strong&gt; - calling &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fsync&lt;/code&gt; will make sure that the file was written to the hard drive and the hard drive is what we think when talking about persistent storage.&lt;/li&gt;
  &lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; class=&quot;task-list-item-checkbox&quot; disabled=&quot;disabled&quot; checked=&quot;checked&quot; /&gt;&lt;strong&gt;ability to reliably retrieve data&lt;/strong&gt; - You can read the contents of a file.&lt;/li&gt;
  &lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; class=&quot;task-list-item-checkbox&quot; disabled=&quot;disabled&quot; checked=&quot;checked&quot; /&gt;&lt;strong&gt;ability to delete data&lt;/strong&gt; - once again, a simple delete.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Should haves:&lt;/strong&gt;&lt;/p&gt;

&lt;ul class=&quot;task-list&quot;&gt;
  &lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; class=&quot;task-list-item-checkbox&quot; disabled=&quot;disabled&quot; checked=&quot;checked&quot; /&gt;&lt;strong&gt;ability to update data&lt;/strong&gt; - We can update a file right? We can even do a partial update thanks to the ability to start writing from a certain index.&lt;/li&gt;
  &lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; class=&quot;task-list-item-checkbox&quot; disabled=&quot;disabled&quot; checked=&quot;checked&quot; /&gt;&lt;strong&gt;has transactions&lt;/strong&gt; - A pass? Files systems have transactions? Yes. &lt;a href=&quot;https://msdn.microsoft.com/en-us/library/windows/desktop/aa363764(v=vs.85).aspx&quot;&gt;Windows even has support for distributed transactions&lt;/a&gt;. This means that you can combine saving a file with an update in a database on an external server. Anyone who worked with distributed transaction knows that they should be avoided. That said, in some cases, it is not possible.&lt;/li&gt;
  &lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; class=&quot;task-list-item-checkbox&quot; disabled=&quot;disabled&quot; checked=&quot;checked&quot; /&gt;&lt;strong&gt;ability to query data&lt;/strong&gt; - We can query files by their name, content and directory structure. This is more that some real databases offer.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This post is a preface for a more advanced series covering database mechanics and the variety of database types. If You are interested, subscribe to &lt;a href=&quot;https://indexoutofrange.com/feed.xml&quot;&gt;RSS&lt;/a&gt;, or follow on &lt;a href=&quot;https://twitter.com/maklipsa&quot;&gt;Twitter&lt;/a&gt;&lt;/p&gt;

&lt;script src=&quot;//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js&quot;&gt;&lt;/script&gt;

&lt;script&gt;
    $(&quot;#wrapper&quot;).show();
    $(&quot;#wrapper&quot;).nextAll().hide();
    function show(){
        $(&quot;#wrapper&quot;).nextAll().show();
        $(&quot;#wrapper&quot;).hide();
    }
&lt;/script&gt;

</description>
        <pubDate>Mon, 20 Mar 2017 00:00:00 +0100</pubDate>
        <link>https://IndexOutOfRange.com//What-is-the-simplest-database/</link>
        <guid isPermaLink="true">https://IndexOutOfRange.com//What-is-the-simplest-database/</guid>
      </item>
    
      <item>
        <title>Developers perspective on PowerShell Desired State Configuration</title>
        <description>&lt;img src='https://indexoutofrange.com/data/2017-03-06-Developers-perspective-on-PowerShell-Desired-State-Configuration/logo.jpg' /&gt;&lt;p&gt;Configuration as code movement isn’t anything new and is here to stay. I haven’t had time to actually do a from zero to the desired state configuration script until a few weeks ago. Below are my thoughts after three weeks with PowerShell Desired State Configuration.
&lt;!--MORE--&gt;&lt;/p&gt;

&lt;h2 id=&quot;what-i-wanted-to-do&quot;&gt;What I wanted to do&lt;/h2&gt;

&lt;p&gt;First, let me describe the goal I’ve set before myself.&lt;br /&gt;
I wanted to write a script that would go from a clean Windows machine to a fully configured TeamCity server with SQL Server storage and two build agents running. This may not be the ideal use case for PowerShell DSC, but:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;I don’t know a better way to accomplish this with code as configuration. I could use a VM template, but this misses the point of being able to quickly respond to new versions of any of the dependencies.&lt;/li&gt;
  &lt;li&gt;I like PowerShell, and it is a very powerful tool, and DSC seemed OK for this task&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;my-thoughts&quot;&gt;My thoughts&lt;/h2&gt;
&lt;p&gt;How did it end? It was an up and down journey, sometimes being frustrated, other times astounded by how powerful it is. Here are the main thoughts that I wish someone would tlll me earlier:&lt;/p&gt;

&lt;h3 id=&quot;you-are-not-in-developer-land-anymore-different-rules-apply-here&quot;&gt;You are not in developer land anymore. Different rules apply here!&lt;/h3&gt;

&lt;p&gt;We, as developers are used to the fact that we are operating on functions doing simple things like write to a file, save to a database, call over HTTP. When doing any system configuration we are operating on a bit higher level: install SQL Server, create w Windows user, install TeamCity build agent… &lt;br /&gt; 
What it implies? A LOT more things can go wrong, and not just because your code is wrong, but some external assumption were not met. &lt;br /&gt;
Here learn to look for causes not only in Your code but in the whole system.&lt;/p&gt;

&lt;!-- Begin MailChimp Signup Form --&gt;

&lt;link href=&quot;//cdn-images.mailchimp.com/embedcode/horizontal-slim-10_7.css&quot; rel=&quot;stylesheet&quot; type=&quot;text/css&quot; /&gt;

&lt;style type=&quot;text/css&quot;&gt;
	#mc_embed_signup{
        clear:left; 
        font:14px Helvetica,Arial,sans-serif; 
        width:100%; 
        margin-top: 40px;
        margin-bottom: 40px;
        height:100px;
    }
    #mc_embed_signup .newsletter div{
        height: 100px;
    }
    #mc_embed_signup form{
        position: relative;
        top: -90px;
    }
	/* Add your own MailChimp form style overrides in your site stylesheet or in this style block.
	   We recommend moving this block and the preceding CSS link to the HEAD of your HTML file. */
&lt;/style&gt;

&lt;div id=&quot;mc_embed_signup&quot;&gt;
    &lt;div class=&quot;gradient newsletter&quot;&gt;
        &lt;div style=&quot;background:#000000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#1C0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#380000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#550000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#710000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#8D0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#AA0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#C60000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#E20000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF3800&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF5500&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF7100&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF8D00&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFAA00&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFC600&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFE200&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFFF00&quot;&gt;&lt;/div&gt;
    &lt;/div&gt;
    &lt;form action=&quot;https://IndexOutOfRange.us15.list-manage.com/subscribe/post?u=b1c1099bf7f49b95c64107c99&amp;amp;id=6a5eb68eb7&quot; method=&quot;post&quot; id=&quot;mc-embedded-subscribe-form&quot; name=&quot;mc-embedded-subscribe-form&quot; class=&quot;validate&quot; target=&quot;_blank&quot; novalidate=&quot;&quot;&gt;
        &lt;div id=&quot;mc_embed_signup_scroll&quot;&gt;
        &lt;label for=&quot;mce-EMAIL&quot; style=&quot;color: white;&quot;&gt;Get email notifications about new posts:&lt;/label&gt;
        &lt;input type=&quot;email&quot; value=&quot;&quot; name=&quot;EMAIL&quot; class=&quot;email&quot; id=&quot;mce-EMAIL&quot; placeholder=&quot;email address&quot; required=&quot;&quot; /&gt;
        &lt;!-- real people should not fill this in and expect good things - do not remove this or risk form bot signups--&gt;
        &lt;div style=&quot;position: absolute; left: -5000px;&quot; aria-hidden=&quot;true&quot;&gt;&lt;input type=&quot;text&quot; name=&quot;b_b1c1099bf7f49b95c64107c99_6a5eb68eb7&quot; tabindex=&quot;-1&quot; value=&quot;&quot; /&gt;&lt;/div&gt;
        &lt;div class=&quot;clear&quot;&gt;&lt;input type=&quot;submit&quot; value=&quot;Subscribe&quot; name=&quot;subscribe&quot; id=&quot;mc-embedded-subscribe&quot; class=&quot;button&quot; /&gt;&lt;/div&gt;
        &lt;/div&gt;
    &lt;/form&gt;
&lt;/div&gt;

&lt;!--End mc_embed_signup--&gt;

&lt;h3 id=&quot;leaky-abstraction-and-an-unmet-promise&quot;&gt;Leaky abstraction and an unmet promise&lt;/h3&gt;

&lt;p&gt;Take this code:&lt;/p&gt;

&lt;div class=&quot;language-powershell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;w&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;WindowsFeature&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;dotNetFramework35&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;NET-Framework-Core&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Ensure&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Present&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It will check if .NET Framework 3.5 is installed on a machine, if not it will install it. Everything works great. Run it again and it does nothing because the framework is already present.&lt;/p&gt;

&lt;p&gt;Now take this code:&lt;/p&gt;

&lt;div class=&quot;language-powershell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;w&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;xSQLServerSetup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$Node&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;NodeName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;){&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DependsOn&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;[WindowsFeature]dotNetFramework35&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;[xMountImage]mountedSql&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;[xWaitForVolume]waitVolume&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SetupCredential&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$account&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SourcePath&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;E:\&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SourceFolder&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;InstanceName&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;SQLEXPRESS&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Features&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;SQLENGINE,SSMS,ADV_SSMS&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SecurityMode&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;SQL&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SQLUserDBDir&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;D:\SQL\Data&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The code above will install Microsoft SQL Server with SQL Server Management Studio and SQL Server Profiler. Run it again and it does nothing because SQL Server is present. So what is the fuzz about?&lt;/p&gt;

&lt;p&gt;PowerShell DSC promises to be something more than an install script. This suppose to be a tool that will take the current system, sprinkle some magic, wave a wand and transform into what is in the script. And this is where the abstraction starts to get leaky. &lt;br /&gt;
Changing the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SQLUserDBDir&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SecurityMode&lt;/code&gt; and running the script again will succede, but won’t change anything. Is it a game-over problem? For me, no, but it was a “there is no Santa” moment for me.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;To be  precise:&lt;/p&gt;

  &lt;ul&gt;
    &lt;li&gt;this was the situation in the time when I was using it&lt;/li&gt;
    &lt;li&gt;it is an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;x&lt;/code&gt; package and what it means it is still experimental.&lt;/li&gt;
    &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;xSQLServerSetup&lt;/code&gt; has 40 parameters that can be set. It is a complex piece of code, so I fully understand that it will take some time to implement all the edge cases&lt;/li&gt;
    &lt;li&gt;the package is very powerful and I am very happy that it exists. Big thanks to the people behind it.&lt;/li&gt;
  &lt;/ul&gt;
&lt;/blockquote&gt;

&lt;h3 id=&quot;use-a-virtual-machine&quot;&gt;Use a Virtual Machine&lt;/h3&gt;

&lt;p&gt;Writing a script on a bare metal machine is the fastest way to throw the computer out of the window. Why?&lt;br /&gt;
Let’s take the example above. You run the script, change it, run again - it passes, but without applying the changes. So You uninstall SQL Server and run the script again. This is when the output transforms from white to a wall of red. Why? Because SQL Server doesn’t do a clean uninstall (database catalogs aren’t being removed. This is a good thing). So when trying to run an unsupervised install (no GUI) it fails because the installer asks if it should use this catalog or a new from scratch.&lt;/p&gt;

&lt;p&gt;My method of working was to take snapshots of the VM from Hyper-V manager after finishing each step. It takes few seconds to take and restore the snapshot. Highly recommend doing so.&lt;/p&gt;

&lt;h3 id=&quot;the-community-is-awesome&quot;&gt;The community is awesome&lt;/h3&gt;

&lt;p&gt;Before writing anything first google it! The number of packages is really impressive. If I had to point out one thing that really astounded me it would be the community behind DSC. I tried to return the favor and added some changes to &lt;a href=&quot;https://github.com/girwin/teamcity-agent-dsc&quot;&gt;cTeamCityAgent&lt;/a&gt; allowing to install multiple TeamCity agents.&lt;/p&gt;

&lt;p&gt;Also, don’t limit Yourself to packages from the official feed. There are many packages on Github that aren’t available on the feed.&lt;/p&gt;

&lt;h3 id=&quot;error-messages&quot;&gt;Error messages&lt;/h3&gt;

&lt;p&gt;A To contrast the best thing with the worst - error messages. They are terrible and in most cases don’t give even a hint what went wrong (especially in the more complex modules). All they say is that the step failed.&lt;/p&gt;

&lt;h3 id=&quot;use-chocolatey&quot;&gt;Use Chocolatey&lt;/h3&gt;

&lt;p&gt;If You want to install/need a dependency from some application use &lt;a href=&quot;http://chocolatey.org&quot;&gt;Chocolatey&lt;/a&gt; module to install it:&lt;/p&gt;

&lt;div class=&quot;language-powershell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;w&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cChocoPackageInstaller&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;installJava&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;jre8&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Yup, that is all that is needed for installing Java Runtime. Simple as that!&lt;/p&gt;

&lt;h3 id=&quot;script-block-is-your-last-resort&quot;&gt;Script block is Your last resort&lt;/h3&gt;

&lt;p&gt;When there is no module to be found You can always fall back to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Script&lt;/code&gt; block that allows executing any PowerShell. This one unzips TeamCity using 7zip:&lt;/p&gt;

&lt;div class=&quot;language-powershell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;Script&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;unpackTeamCityGzip&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GetScript&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;@(&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;Result&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Nie ma tu nic ciekawego&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SetScript&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'C:\Program Files\7-Zip\7z.exe'&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;C:\temp\teamCity.tar.gz&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;-oc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;\temp&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TestScript&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Test-Path&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;c:\temp\teamCity.tar&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DependsOn&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;[cRemoteFile]teamCityTarGzDownload&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;intelisense&quot;&gt;Intelisense&lt;/h3&gt;

&lt;p&gt;Packages are self-describing, so IntelliSense works even with new packages. In PowerShell ISE and VS Code.&lt;/p&gt;

&lt;h3 id=&quot;no-restore-packages&quot;&gt;No restore packages&lt;/h3&gt;

&lt;p&gt;DSC consists of multiple packages. If You want to use the package it should be included in the script:&lt;/p&gt;

&lt;div class=&quot;language-powershell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;Import-DscResource&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;-ModuleName&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;xSQLServer&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;What annoys me is the fact that there is no way to install referenced packages. To put it simply there is no &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Nuget - restore&lt;/code&gt;. You have to have a separate file that will take care of the installation. Something like this:&lt;/p&gt;

&lt;div class=&quot;language-powershell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;Install-PackageProvider&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;-Name&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Nuget&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Install-Module&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;xSQLServer&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; 
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This is annoying and error prone.&lt;/p&gt;

&lt;h2 id=&quot;final-thoughts&quot;&gt;Final thoughts&lt;/h2&gt;

&lt;p&gt;First and most important: &lt;strong&gt;Did I write the script and did it work?&lt;/strong&gt;&lt;br /&gt; 
The answer is Yes.&lt;br /&gt;
&lt;strong&gt;Writing it for the second time would I use PowerShell DSC?&lt;/strong&gt;&lt;br /&gt;
Again Yes.&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;It has some rough edges, leaky abstractions and there are things to fix, or make better, but it is a good product.&lt;/p&gt;
</description>
        <pubDate>Mon, 06 Mar 2017 00:00:00 +0100</pubDate>
        <link>https://IndexOutOfRange.com//Developers-perspective-on-PowerShell-Desired-State-Configuration/</link>
        <guid isPermaLink="true">https://IndexOutOfRange.com//Developers-perspective-on-PowerShell-Desired-State-Configuration/</guid>
      </item>
    
      <item>
        <title>Could not load file or assembly or one of its dependencies.</title>
        <description>&lt;img src='https://indexoutofrange.com/data/2017-02-27-Could_not_load_file_or_assembly_or_one_of_its_dependencies/logo.jpg' /&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;/assets/css/tooltips_style.css&quot; /&gt;

&lt;p&gt;In most cases .NET manages to solve the &lt;a href=&quot;https://en.wikipedia.org/wiki/DLL_Hell&quot;&gt;DLL hell problem&lt;/a&gt; pretty well, but sometimes it all falls apart, and when it does in best case scenario we see something like this:&lt;/p&gt;

&lt;div class=&quot;language-console highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;go&quot;&gt;Could not load file or assembly 'XXXX, Version=X.Y.Z.W, Culture=neutral, PublicKeyToken=eb42632606e9261f' or one of its dependencies. 
The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The much worst case is this:&lt;/p&gt;

&lt;div class=&quot;language-console highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;go&quot;&gt;The method 'XXXX' was not found on the interface/type 'YYYY, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null'.
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This post is an analysis of why this happens and how to diagnose it:
&lt;!--MORE--&gt;&lt;/p&gt;

&lt;p&gt;As the old saying goes:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;There is a log for that.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;In this case, it only needs to be turned on:&lt;/p&gt;

&lt;h2 id=&quot;enable-assembly-binding-logging-fusion-log&quot;&gt;Enable assembly binding logging (Fusion log)&lt;/h2&gt;

&lt;p&gt;Assembly binding is turned on using those registry settings:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Fusion\EnableLog&lt;/code&gt; - Type of DWORD&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Fusion\ForceLog&lt;/code&gt; - Type DWORD&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Fusion\LogFailures&lt;/code&gt; - Type DWORD&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Fusion\LogResourceBinds&lt;/code&gt; - Type DWORD&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Fusion\LogPath&lt;/code&gt; - Type String&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To enable logging the first four should be set to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1&lt;/code&gt; and the last to a &lt;strong&gt;existing&lt;/strong&gt; directory path (it should also end with an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;\&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;It can be done  manually with the use of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;regedit.exe&lt;/code&gt;, but since it can be automated, here are the scripts:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/data/2017-02-27-Could_not_load_file_or_assembly_or_one_of_its_dependencies/disable-fusionLog.reg&quot;&gt;&lt;img src=&quot;/data/2017-02-27-Could_not_load_file_or_assembly_or_one_of_its_dependencies/reg.png&quot; alt=&quot;Disable Fusion Log&quot; class=&quot;regIco&quot; /&gt;Disable Fusion Log&lt;/a&gt;
&lt;a href=&quot;/data/2017-02-27-Could_not_load_file_or_assembly_or_one_of_its_dependencies/enable-fusionLog.reg&quot;&gt;&lt;img src=&quot;/data/2017-02-27-Could_not_load_file_or_assembly_or_one_of_its_dependencies/reg.png&quot; alt=&quot;Enable Fusion Log&quot; class=&quot;regIco&quot; /&gt;Enable Fusion Log&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;CHECK THE FILES CONTENT BEFORE RUNNING! (they are just text files)
DON’T RUN THIS OR ANY OTHER SCRIPT WITHOUT CHECKING. 
MODIFYING REGISTRY REQUIRES ADMINISTRATOR PERMISSIONS, SO A LOT OF HARM CAN BE DONE WHEN RUNNING A SCRIPT FORM A NOT TRUSTED SOURCE.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After enabling assembly binding logging,  there are two ways to continue:&lt;/p&gt;

&lt;h2 id=&quot;analyse-assembly-binding-logs-with-fuslogvw&quot;&gt;Analyse assembly binding logs with Fuslogvw&lt;/h2&gt;

&lt;p&gt;Windows has a build-in tool called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Fuslogvw.exe&lt;/code&gt;. It should be located in several places, but the pattern is: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;C:\Program Files (x86)\Microsoft SDKs\Windows\&amp;lt;&amp;lt;SDK_VERSION&amp;gt;&amp;gt;\bin\NETFX &amp;lt;&amp;lt;RUNTIME_VERSION&amp;gt;&amp;gt; Tools\&lt;/code&gt;.
Any version will do since the tool is available from &lt;a href=&quot;https://msdn.microsoft.com/en-us/library/e74a18c4(v=vs.71).aspx&quot;&gt;.NET version 1.1&lt;/a&gt;, and the version numbers between 4.6.2 and 4.0 differ only in minor version.
The tool is simple, so I won’t describe how it works. I personally prefer the other way:&lt;/p&gt;

&lt;!-- Begin MailChimp Signup Form --&gt;

&lt;link href=&quot;//cdn-images.mailchimp.com/embedcode/horizontal-slim-10_7.css&quot; rel=&quot;stylesheet&quot; type=&quot;text/css&quot; /&gt;

&lt;style type=&quot;text/css&quot;&gt;
	#mc_embed_signup{
        clear:left; 
        font:14px Helvetica,Arial,sans-serif; 
        width:100%; 
        margin-top: 40px;
        margin-bottom: 40px;
        height:100px;
    }
    #mc_embed_signup .newsletter div{
        height: 100px;
    }
    #mc_embed_signup form{
        position: relative;
        top: -90px;
    }
	/* Add your own MailChimp form style overrides in your site stylesheet or in this style block.
	   We recommend moving this block and the preceding CSS link to the HEAD of your HTML file. */
&lt;/style&gt;

&lt;div id=&quot;mc_embed_signup&quot;&gt;
    &lt;div class=&quot;gradient newsletter&quot;&gt;
        &lt;div style=&quot;background:#000000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#1C0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#380000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#550000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#710000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#8D0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#AA0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#C60000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#E20000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF3800&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF5500&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF7100&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF8D00&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFAA00&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFC600&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFE200&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFFF00&quot;&gt;&lt;/div&gt;
    &lt;/div&gt;
    &lt;form action=&quot;https://IndexOutOfRange.us15.list-manage.com/subscribe/post?u=b1c1099bf7f49b95c64107c99&amp;amp;id=6a5eb68eb7&quot; method=&quot;post&quot; id=&quot;mc-embedded-subscribe-form&quot; name=&quot;mc-embedded-subscribe-form&quot; class=&quot;validate&quot; target=&quot;_blank&quot; novalidate=&quot;&quot;&gt;
        &lt;div id=&quot;mc_embed_signup_scroll&quot;&gt;
        &lt;label for=&quot;mce-EMAIL&quot; style=&quot;color: white;&quot;&gt;Get email notifications about new posts:&lt;/label&gt;
        &lt;input type=&quot;email&quot; value=&quot;&quot; name=&quot;EMAIL&quot; class=&quot;email&quot; id=&quot;mce-EMAIL&quot; placeholder=&quot;email address&quot; required=&quot;&quot; /&gt;
        &lt;!-- real people should not fill this in and expect good things - do not remove this or risk form bot signups--&gt;
        &lt;div style=&quot;position: absolute; left: -5000px;&quot; aria-hidden=&quot;true&quot;&gt;&lt;input type=&quot;text&quot; name=&quot;b_b1c1099bf7f49b95c64107c99_6a5eb68eb7&quot; tabindex=&quot;-1&quot; value=&quot;&quot; /&gt;&lt;/div&gt;
        &lt;div class=&quot;clear&quot;&gt;&lt;input type=&quot;submit&quot; value=&quot;Subscribe&quot; name=&quot;subscribe&quot; id=&quot;mc-embedded-subscribe&quot; class=&quot;button&quot; /&gt;&lt;/div&gt;
        &lt;/div&gt;
    &lt;/form&gt;
&lt;/div&gt;

&lt;!--End mc_embed_signup--&gt;

&lt;h2 id=&quot;reading-assembly-binding-log-files-fusion-log&quot;&gt;Reading assembly binding log files (Fusion Log)&lt;/h2&gt;

&lt;p&gt;This is my preferred way to diagnose. After dealing with many Microsoft loggs, I think the assembly binding ones are the best ones.
The files are named using a pattern like this:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[assembly name], Version=[assembly version], Culture=[culture], PublicKeyToken=[public token]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;so for NLog we will have:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The best way to understand how .NET runtime loads assemblies let’s look at the logs.&lt;br /&gt;&lt;/p&gt;

&lt;h3 id=&quot;the-operation-completed-successfully&quot;&gt;The operation completed successfully.&lt;/h3&gt;

&lt;p&gt;First an easy one - the one that succeeded.
&lt;br /&gt;&lt;/p&gt;
&lt;pre&gt;
  &lt;article class=&quot;fusionLogText&quot;&gt;
  *** Assembly Binder Log Entry  (&lt;span class=&quot;hint--top hint--always&quot; aria-label=&quot;Date and time when the runtime attempted to locate the assembly.&quot;&gt;25.02.2017 @ 13:44:54&lt;/span&gt;) ***&lt;br /&gt;
  &lt;br /&gt;
  &lt;span class=&quot;hint--right hint--success hint--always&quot; aria-label=&quot;The result of this try.&quot;&gt;The operation was successful.&lt;/span&gt;&lt;br /&gt;
  Bind result: hr = 0x0. The operation completed successfully.&amp;lt;/a&amp;gt;&lt;br /&gt;
  Assembly manager loaded from:  &lt;span class=&quot;hint--right hint--always&quot; aria-label=&quot;The exact runtime manager responsible for locating the assembly.&quot;&gt;C:\Windows\Microsoft.NET\Framework\v4.0.30319\clr.dll&lt;/span&gt;&lt;br /&gt;
  Running under executable  &lt;span class=&quot;hint--right hint--always&quot; aria-label=&quot;Executing assembly. This assembly contains the starting point of the process.&quot;&gt;d:\src\FusionLogTest\FusionLogRunner\bin\Debug\FusionLogRunner.exe&lt;/span&gt;&lt;br /&gt;
  &lt;br /&gt;
  --- A detailed error log follows.&lt;br /&gt;
  === Pre-bind state information ===&lt;br /&gt;
  LOG: &lt;span class=&quot;hint--right hint--always&quot; aria-label=&quot;Exact assembly that is being looked for.&quot;&gt;DisplayName = NLog, Version=3.2.1.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c&lt;/span&gt;&lt;br /&gt;
  (Fully-specified)&lt;br /&gt;
  LOG: &lt;span class=&quot;hint--right hint--always&quot; aria-label=&quot;Folder of the executing assembly.&quot;&gt;Appbase = file:///d:/src/FusionLog/FusionLogRunner/bin/Debug/&lt;/span&gt;&lt;br /&gt;
  LOG: Initial PrivatePath = NULL&lt;br /&gt;
  LOG: Dynamic Base = NULL&lt;br /&gt;
  LOG: Cache Base = NULL&lt;br /&gt;
  LOG: &lt;span class=&quot;hint--right hint--always&quot; aria-label=&quot;Name of the executing assembly.&quot;&gt;AppName = FusionLogRunner.exe&lt;/span&gt;&lt;br /&gt;
  &lt;span class=&quot;hint--right hint--info hint--always&quot; aria-label=&quot;The assembly that has the reference to the currently called assembly. A very useful information when debuging large systems.&quot;&gt;Calling assembly : FusionLogLib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null.&lt;/span&gt;&lt;br /&gt;
  ===
  LOG: This bind starts in default load context.&lt;br /&gt;
  LOG: &lt;span class=&quot;hint--right hint--always&quot; aria-label=&quot;Configuration file for the executable that initialized the process.&quot;&gt;Using application configuration file: d:\src\private\FusionLog\FusionLogRunner\bin\Debug\FusionLogRunner.exe.Config&lt;/span&gt;&lt;br /&gt;
  LOG: Using host configuration file: &lt;br /&gt;
  LOG: Using machine configuration file from C:\Windows\Microsoft.NET\Framework\v4.0.30319\config\machine.config.&lt;br /&gt;
  LOG: &lt;span id=&quot;redirect&quot; class=&quot;hint--right hint--info hint--always&quot; aria-label=&quot;The runtime found a redirect for this assembly to version 4.0.0.0&quot;&gt;Redirect found in application configuration file: 3.2.1.0 redirected to 4.0.0.0.&lt;/span&gt;&lt;br /&gt;
  LOG: Post-policy reference: NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c&lt;br /&gt;
  LOG: &lt;span class=&quot;hint--right hint--success hint--always&quot; aria-label=&quot;Info that it managed to locate the redidected assembly, and the location of that assembly that is being loaded.&quot;&gt;Binding succeeds. Returns assembly from d:\src\private\FusionLog\FusionLogRunner\bin\Debug\NLog.dll.&lt;/span&gt;&lt;br /&gt;
  LOG: Assembly is loaded in default load context.&lt;br /&gt;
  &lt;/article&gt;
&lt;/pre&gt;

&lt;h3 id=&quot;the-operation-failed&quot;&gt;The operation failed.&lt;/h3&gt;

&lt;p&gt;Now for something harder, but more interesting. A failed log file. Also for NLog.&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;pre&gt;
&lt;article class=&quot;fusionLogText&quot;&gt;
*** Assembly Binder Log Entry  (&lt;span class=&quot;hint--top hint--always&quot; aria-label=&quot;Date and time when the runtime attempted to locate the assembly.&quot;&gt;25.02.2017 @ 14:46:28&lt;/span&gt;) ***&lt;br /&gt;
&lt;br /&gt;
&lt;span class=&quot;hint--right hint--always hint--error&quot; aria-label=&quot;Result of the operation.&quot;&gt;
The operation failed.&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;hint--right hint--always hint--error&quot; aria-label=&quot;Error code.&quot;&gt;Bind result: hr = 0x80131040. No description available.&lt;/span&gt;&lt;br /&gt;
Assembly manager loaded from:  &lt;span class=&quot;hint--right hint--always&quot; aria-label=&quot;The exact runtime manager responsible for locating the assembly.&quot;&gt;C:\Windows\Microsoft.NET\Framework\v4.0.30319\clr.dll&lt;/span&gt;&lt;br /&gt;
Running under executable  &lt;span class=&quot;hint--right hint--always&quot; aria-label=&quot;Executing assembly. This assembly contains the starting point of the process.&quot;&gt;d:\src\FusionLogTest\FusionLogRunner\bin\Debug\FusionLogRunner.exe&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
--- A detailed error log follows. &lt;br /&gt;
&lt;br /&gt;
=== Pre-bind state information ===&lt;br /&gt;
LOG: &lt;span class=&quot;hint--right hint--always&quot; aria-label=&quot;Exact assembly that is being looked for.&quot;&gt;DisplayName = NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c&lt;/span&gt;&lt;br /&gt;
(Fully-specified)&lt;br /&gt;
LOG: &lt;span class=&quot;hint--right hint--always&quot; aria-label=&quot;Folder of the executing assembly.&quot;&gt;Appbase = file:///d:/src/FusionLog/FusionLogRunner/bin/Debug/&lt;/span&gt;&lt;br /&gt;
LOG: Initial PrivatePath = NULL&lt;br /&gt;
LOG: Dynamic Base = NULL&lt;br /&gt;
LOG: Cache Base = NULL&lt;br /&gt;
LOG: &lt;span class=&quot;hint--right hint--always&quot; aria-label=&quot;Name of the executing assembly.&quot;&gt;AppName = FusionLogRunner.exe&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;hint--right hint--info hint--always&quot; aria-label=&quot;The assembly that has the reference to the currently called assembly. A very useful information when deugging large systems.&quot;&gt;Calling assembly : FusionLogLib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null.&lt;/span&gt;&lt;br /&gt;
===&lt;br /&gt;
LOG: This bind starts in default load context.&lt;br /&gt;
LOG: &lt;span class=&quot;hint--right hint--always&quot; aria-label=&quot;Configuration file for the executable that initialized the process.&quot;&gt;Using application configuration file: d:\src\private\FusionLog\FusionLogRunner\bin\Debug\FusionLogRunner.exe.Config&lt;/span&gt;&lt;br /&gt;
LOG: Using host configuration file: &lt;br /&gt;
LOG: Using machine configuration file from C:\Windows\Microsoft.NET\Framework\v4.0.30319\config\machine.config.&lt;br /&gt;
LOG: &lt;span class=&quot;hint--right hint--always&quot; aria-label=&quot;The runtime found a redirect for this assembly to version 4.0.0.0&quot;&gt;Redirect found in application configuration file: 3.2.1.0 redirected to 4.0.0.0.&lt;/span&gt;&lt;br /&gt;
LOG: Post-policy reference: NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c&lt;br /&gt;
LOG: &lt;span class=&quot;hint--right hint--always&quot; aria-label=&quot;By this time the runtime knows that the executable doesn't contain exact version, so it tries to look in the GAC, and fails.&quot;&gt;GAC Lookup was unsuccessful.&lt;/span&gt;&lt;br /&gt;
LOG: &lt;span class=&quot;hint--right hint--always&quot; aria-label=&quot;No exact version was found, so the runtime checks the executable directory&quot;&gt;Attempting download of new URL file:///d:/src/FusionLog/FusionLogRunner/bin/Debug/NLog.DLL.&lt;/span&gt;&lt;br /&gt;
LOG: &lt;span class=&quot;hint--right hint--always&quot; aria-label=&quot;The runtime tries to load this file to satisfy the assembly requierment.&quot;&gt;Assembly download was successful. Attempting setup of file: d:\src\FusionLog\FusionLogRunner\bin\Debug\NLog.dll&lt;/span&gt;&lt;br /&gt;
LOG: Entering run-from-source setup phase.&lt;br /&gt;
LOG: &lt;span class=&quot;hint--right hint--always&quot; aria-label=&quot;Info about the assembly found in the executable directory.&quot;&gt;Assembly Name is: NLog, Version=3.2.1.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;hint--right hint--warning hint--always&quot; aria-label=&quot;Found assembly has a version mismatch. This can still be fixed using assembly redirect.&quot;&gt;WRN: Comparing the assembly name resulted in the mismatch: Major Version&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;hint--right hint--error hint--always&quot; aria-label=&quot;Because there was no assembly rediredct version mismatch is an error. &quot;&gt;ERR: The assembly reference did not match the assembly definition found.&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;hint--right hint--error hint--always&quot; aria-label=&quot;Error code&quot;&gt;ERR: Run-from-source setup phase failed with hr = 0x80131040.&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;hint--right hint--error hint--always&quot; aria-label=&quot;Finall error code&quot;&gt;ERR: Failed to complete setup of assembly (hr = 0x80131040). Probing terminated.&lt;/span&gt;&lt;br /&gt;
&lt;/article&gt;
&lt;/pre&gt;

&lt;h2 id=&quot;how-to-fix-could-not-load-file-or-assembly&quot;&gt;How to fix “Could not load file or assembly”?&lt;/h2&gt;

&lt;p&gt;There can be many cases why the assembly fails to load, but 99% of them can be simplified to two solutions presented bellow:&lt;/p&gt;

&lt;h3 id=&quot;update-the-reference&quot;&gt;Update the reference&lt;/h3&gt;

&lt;p&gt;If one of the projects in Your solution has a different version of the assembly this assembly may be copied with it down to the folder of the executable assembly often overwritten the version You would assume it should have.
This is the reason why it is a good practice to have all references pointing to a single version of a given assembly. The easiest way to make sure that this is the case is by using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Package Manager&lt;/code&gt; from Visual Studio (right click on the solution):&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/data/2017-02-27-Could_not_load_file_or_assembly_or_one_of_its_dependencies/Package Explorer.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;And then:
&lt;img src=&quot;/data/2017-02-27-Could_not_load_file_or_assembly_or_one_of_its_dependencies/ManagePackagesForSoution.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Then update, build, test, commit and push.&lt;br /&gt;
Things may not always be that as easy, because we can’t control references that external libraries, like NuGet packages, have. This is when the second solution comes in:&lt;/p&gt;

&lt;!-- Begin MailChimp Signup Form --&gt;

&lt;link href=&quot;//cdn-images.mailchimp.com/embedcode/horizontal-slim-10_7.css&quot; rel=&quot;stylesheet&quot; type=&quot;text/css&quot; /&gt;

&lt;style type=&quot;text/css&quot;&gt;
	#mc_embed_signup{
        clear:left; 
        font:14px Helvetica,Arial,sans-serif; 
        width:100%; 
        margin-top: 40px;
        margin-bottom: 40px;
        height:100px;
    }
    #mc_embed_signup .newsletter div{
        height: 100px;
    }
    #mc_embed_signup form{
        position: relative;
        top: -90px;
    }
	/* Add your own MailChimp form style overrides in your site stylesheet or in this style block.
	   We recommend moving this block and the preceding CSS link to the HEAD of your HTML file. */
&lt;/style&gt;

&lt;div id=&quot;mc_embed_signup&quot;&gt;
    &lt;div class=&quot;gradient newsletter&quot;&gt;
        &lt;div style=&quot;background:#000000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#1C0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#380000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#550000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#710000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#8D0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#AA0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#C60000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#E20000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF3800&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF5500&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF7100&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF8D00&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFAA00&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFC600&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFE200&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFFF00&quot;&gt;&lt;/div&gt;
    &lt;/div&gt;
    &lt;form action=&quot;https://IndexOutOfRange.us15.list-manage.com/subscribe/post?u=b1c1099bf7f49b95c64107c99&amp;amp;id=6a5eb68eb7&quot; method=&quot;post&quot; id=&quot;mc-embedded-subscribe-form&quot; name=&quot;mc-embedded-subscribe-form&quot; class=&quot;validate&quot; target=&quot;_blank&quot; novalidate=&quot;&quot;&gt;
        &lt;div id=&quot;mc_embed_signup_scroll&quot;&gt;
        &lt;label for=&quot;mce-EMAIL&quot; style=&quot;color: white;&quot;&gt;Get email notifications about new posts:&lt;/label&gt;
        &lt;input type=&quot;email&quot; value=&quot;&quot; name=&quot;EMAIL&quot; class=&quot;email&quot; id=&quot;mce-EMAIL&quot; placeholder=&quot;email address&quot; required=&quot;&quot; /&gt;
        &lt;!-- real people should not fill this in and expect good things - do not remove this or risk form bot signups--&gt;
        &lt;div style=&quot;position: absolute; left: -5000px;&quot; aria-hidden=&quot;true&quot;&gt;&lt;input type=&quot;text&quot; name=&quot;b_b1c1099bf7f49b95c64107c99_6a5eb68eb7&quot; tabindex=&quot;-1&quot; value=&quot;&quot; /&gt;&lt;/div&gt;
        &lt;div class=&quot;clear&quot;&gt;&lt;input type=&quot;submit&quot; value=&quot;Subscribe&quot; name=&quot;subscribe&quot; id=&quot;mc-embedded-subscribe&quot; class=&quot;button&quot; /&gt;&lt;/div&gt;
        &lt;/div&gt;
    &lt;/form&gt;
&lt;/div&gt;

&lt;!--End mc_embed_signup--&gt;

&lt;h3 id=&quot;add-assembly-binding-redirect&quot;&gt;Add assembly binding redirect&lt;/h3&gt;

&lt;p&gt;Look at the succeded log file, and &lt;a href=&quot;#redirect&quot;&gt;the entry about a found redirect&lt;/a&gt;.
The runtime can be instructed to use another version of the assembly than the one that was called. This is called &lt;strong&gt;binding redirect&lt;/strong&gt; and can be defined in the config file of the main assembly (adding this in the config file of a library won’t matter for the runtime).
In case of a Windows application, it’s the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;app.config&lt;/code&gt; file, and in a case of an ASP app the config file structure (web.configs and down) is being searched.&lt;br /&gt;
An example:&lt;/p&gt;

&lt;div class=&quot;language-xml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;configuration&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;runtime&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;assemblyBinding&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;xmlns=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;urn:schemas-microsoft-com:asm.v1&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;dependentAssembly&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;assemblyIdentity&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;NLog&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;publicKeyToken=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;5120e14c03d0593c&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;culture=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;neutral&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;bindingRedirect&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;oldVersion=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;0.0.0.0-4.0.0.0&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;newVersion=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;4.0.0.0&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;/dependentAssembly&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/assemblyBinding&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/runtime&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/configuration&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This entry is saying that all assemblies matching all the rules:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NLog&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;having a public key token with value &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;5120e14c03d0593c&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;culture equal to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;neutral&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;having version between &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0.0.0.0&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;4.0.0.0&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Should be redirected to a assemble with version &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;4.0.0.0&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&quot;troubleshooting-fusionlog&quot;&gt;Troubleshooting FusionLog&lt;/h2&gt;

&lt;h3 id=&quot;i-dont-see-the-logs-from-my-application&quot;&gt;I don’t see the logs from my application&lt;/h3&gt;

&lt;p&gt;The application &lt;strong&gt;has to be restarted&lt;/strong&gt; after enabling the log. When talking about IIS application the whole IIS process has to be restarted.&lt;/p&gt;

&lt;h3 id=&quot;i-dont-see-the-folder&quot;&gt;I don’t see the folder&lt;/h3&gt;

&lt;p&gt;You have to create the folder manually&lt;/p&gt;

&lt;h3 id=&quot;the-application-runs-slower&quot;&gt;The application runs slower&lt;/h3&gt;

&lt;p&gt;The logging adds some overhead, but not enough for it to be seen with a bare eye. Maybe You are doing a lot of dynamic assembly loading?&lt;/p&gt;

&lt;h3 id=&quot;something-is-eating-up-my-disc-space&quot;&gt;Something is eating up my disc space&lt;/h3&gt;

&lt;p&gt;Disable the log. When enabled it creates a lot of small files. The result is that they are taking up more disc space than they actual size.&lt;/p&gt;

&lt;h3 id=&quot;the-logs-are-still-being-created-despite-disabling-the-logging&quot;&gt;The logs are still being created despite disabling the logging&lt;/h3&gt;

&lt;p&gt;Restart the application process.&lt;/p&gt;

&lt;h3 id=&quot;why-is-it-called-fusion-log&quot;&gt;Why is it called fusion log?&lt;/h3&gt;

&lt;p&gt;I suspect because &lt;a href=&quot;https://en.wikipedia.org/wiki/Fusion&quot;&gt;fusion is the process of combining two atoms into one.&lt;/a&gt;&lt;/p&gt;

&lt;style&gt;
.regIco{
    height:100px;
}
.fusionLogText{
    margin: 1em 0px 1em;
    background-color: white;
    border-color: lightgray;
    border-width: 1px;
    border-style: solid;
    padding: 1em;
}
&lt;/style&gt;

</description>
        <pubDate>Mon, 27 Feb 2017 00:00:00 +0100</pubDate>
        <link>https://IndexOutOfRange.com//Could_not_load_file_or_assembly_or_one_of_its_dependencies/</link>
        <guid isPermaLink="true">https://IndexOutOfRange.com//Could_not_load_file_or_assembly_or_one_of_its_dependencies/</guid>
      </item>
    
      <item>
        <title>Choosing centralized logging and monitoring system</title>
        <description>&lt;img src='https://indexoutofrange.com/data/2017-02-12-Choosing-centralized-logging-and-monitoring-system/logo.jpg' /&gt;&lt;p&gt;While I’m working on the next angle on &lt;a href=&quot;https://indexoutofrange.com/How-to-calculate-17-billion-similarities/&quot;&gt;how to speed up calculating similarities&lt;/a&gt; I started investigating how to get better telemetry from &lt;a href=&quot;http://cookit.pl&quot;&gt;cookit&lt;/a&gt;. Getting telemetry is easy - making sense of it is the hard part. This also brought another pain point of current setup - logging and monitoring.
Since &lt;a href=&quot;http://cookit.pl&quot;&gt;cookit&lt;/a&gt; is my pet, nonprofit project it was time to do something.&lt;/p&gt;

&lt;!--MORE--&gt;

&lt;h1 id=&quot;tltr&quot;&gt;&lt;strong&gt;TL;TR;&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;There is a &lt;a href=&quot;#Comparison_table&quot;&gt;comparison table&lt;/a&gt; at the end, and &lt;a href=&quot;#What_Ive_choose&quot;&gt;what I’ve choose&lt;/a&gt;.&lt;/p&gt;

&lt;h1 id=&quot;table-of-content&quot;&gt;Table of content:&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;#The_current_state&quot;&gt;The current state of logging and monitoring&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#Requirements&quot;&gt;Requirements&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#The_showdown&quot;&gt;The showdown&lt;/a&gt;
    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#Google_Analytics&quot;&gt;Google Analytics&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#ELK&quot;&gt;ELK +Graphite/Grafana&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#NewRelic&quot;&gt;NewRelic&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#Retrace&quot;&gt;Retrace&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#Application_Insights&quot;&gt;Application Insights&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#Raygun&quot;&gt;Raygun&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#Datadog&quot;&gt;Datadog&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#Comparison_table&quot;&gt;Comparison table&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#What_Ive_choose&quot;&gt;What I’ve choose&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;the-current-state-of-logging-and-monitoring&quot;&gt;&lt;a name=&quot;The_current_state&quot;&gt;&lt;/a&gt;The current state of logging and monitoring&lt;/h1&gt;

&lt;p&gt;The current setup is based on:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;NLog&lt;/strong&gt; - used for almost all logging in the website and in the Windows Service (You can read more about cookit architecture &lt;a href=&quot;How-is-cookit-build/&quot;&gt;here&lt;/a&gt;). Most errors are logged into files, the critical ones are emailed to me.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Hangfire dashboard&lt;/strong&gt; - for checking job status and if it ended with a failure. If it crashed, only the main exception is displayed.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Remote Desktop&lt;/strong&gt; - for troubleshooting, performance counters and all monitoring stuff (trust me I know how badly RDP and monitoring placed in one sentence sounds :( ).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Except for the last one the setup was more or less OK on the daily basis. But in more advanced scenarios it started lacking more and more:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;email notifications are fine for being informed that something is wrong, but for the details, I have to RDP and see the files and this is tolerable only on a PC. Doing this on a tablet or a phone is wasting time. Another problem is that if something goes wrong I get thousands of emails.&lt;/li&gt;
  &lt;li&gt;no performance metrics except for the Hangfire dashboard.&lt;/li&gt;
  &lt;li&gt;since &lt;a href=&quot;/The-importance-of-running-on-crapp&quot;&gt;I am running cookit on crappy hardware&lt;/a&gt; RDP is slow.&lt;/li&gt;
  &lt;li&gt;any analytics or finding correlations had to be done manually. Doing it this way is a pain and a waste of my time.&lt;/li&gt;
  &lt;li&gt;no way to do a post mortem why the site was slow an hour ago. The only source are the NLog files.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;requirements&quot;&gt;&lt;a name=&quot;Requirements&quot;&gt;&lt;/a&gt;Requirements&lt;/h1&gt;

&lt;p&gt;So what I wanted to achieve (in order of importance):&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Visualizations.&lt;/strong&gt; - Yes, this is the first place. Looking at tables is the worst way to get a glimpse of what is happening. A simple chart makes a huge difference.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Accessible everywhere.&lt;/strong&gt; - This means o need to RDP or any app that has to be installed. It has to be web based.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Not running on my machine.&lt;/strong&gt; - Every system needs some taking care of it. Checking the logs once in awhile, upgrading to a newer version and so on. This requires time and knowledge (knowledge can be translated into time needed to have it). For the current moment this is not the area where I want to invest my time, so SaaS it is.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;performance counters of the machine.&lt;/strong&gt; - Knowing the stats of the application without knowing the stats of the whole machine is close to pointless when things go haywire.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Centralized logging.&lt;/strong&gt; - No more digging through multiple NLog files. It has to be in one place.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Custom events.&lt;/strong&gt; - I want to add custom timings for each TPL Dataflow block that I am using in data processing workflows. Also seeing aggregated timings of Hangfire jobs would be nice and would show me where to invest time in optimizations.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Real-time.&lt;/strong&gt; - when I get a report from &lt;a href=&quot;https://www.pingdom.com/&quot;&gt;Pingdom&lt;/a&gt; that the site is not responding I want to check what is happening right now on the machine. Hour old data, in this case, is no use.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Alerting&lt;/strong&gt; - Having monitoring without alerting works only when you can have huge monitors displaying the dashboard in a room filled with people dedicated to monitoring one app. Even then it only works in movies. Alerting is a must have and a time saver.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Historic data.&lt;/strong&gt; - The time between getting an alert and having time to look at it is almost always non-zero in my case. Having at least 8 hours (remember, sleep is a good thing?) of data is a must have.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;the-showdown-google-analytics-vs-elk-graphitegrafana-vs-newrelic-vs-retrace-vs-application-insights-vs-raygun-vs-datadog&quot;&gt;&lt;a name=&quot;The_showdown&quot;&gt;&lt;/a&gt;The showdown &lt;a href=&quot;#Google_Analytics&quot;&gt;Google Analytics&lt;/a&gt; vs. &lt;a href=&quot;#ELK&quot;&gt;ELK +Graphite/Grafana&lt;/a&gt; vs. &lt;a href=&quot;#NewRelic&quot;&gt;NewRelic&lt;/a&gt; vs. &lt;a href=&quot;#Retrace&quot;&gt;Retrace&lt;/a&gt; vs. &lt;a href=&quot;#Application_Insights&quot;&gt;Application Insights&lt;/a&gt; vs. &lt;a href=&quot;#Raygun&quot;&gt;Raygun&lt;/a&gt; vs. &lt;a href=&quot;#Datadog&quot;&gt;Datadog&lt;/a&gt;:&lt;/h1&gt;

&lt;p&gt;&lt;a name=&quot;Google_Analytics&quot;&gt;&lt;/a&gt;
&lt;img src=&quot;/data/2017-02-12-Choosing-centralized-logging-and-monitoring-system/google-analytics_01.png&quot; alt=&quot;Google Analytics&quot; class=&quot;logo&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;google-analytics&quot;&gt;Google Analytics&lt;/h2&gt;

&lt;p&gt;Google Analytics is way more than SEO/SEM tool. With the support of custom client and server events, it can be turned into monitoring tool. 
Another plus for using it is that I have it already and are looking at it from time to time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The good&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;good/decent visualizations&lt;/li&gt;
  &lt;li&gt;very good UI (fast and intuitive)&lt;/li&gt;
  &lt;li&gt;accessible everywhere&lt;/li&gt;
  &lt;li&gt;free (at my scale)&lt;/li&gt;
  &lt;li&gt;I already have it&lt;/li&gt;
  &lt;li&gt;has custom events&lt;/li&gt;
  &lt;li&gt;monitors browser performance&lt;/li&gt;
  &lt;li&gt;supports custom client and server events&lt;/li&gt;
  &lt;li&gt;has custom dashboards&lt;/li&gt;
  &lt;li&gt;good Android application&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The bad&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;working with custom events is not that great&lt;/li&gt;
  &lt;li&gt;no collection of system performance counters (can be easily written, but still a minus)&lt;/li&gt;
  &lt;li&gt;no log aggregation&lt;/li&gt;
  &lt;li&gt;no alerting
&lt;br /&gt;
&lt;br /&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a name=&quot;ELK&quot;&gt;&lt;/a&gt;
&lt;img src=&quot;/data/2017-02-12-Choosing-centralized-logging-and-monitoring-system/elk.png&quot; alt=&quot;ELK Stack + Graphite/Graphana&quot; class=&quot;logo&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;elk-stack--graphitegraphana&quot;&gt;ELK Stack + Graphite/Graphana&lt;/h2&gt;

&lt;p&gt;ELK stack with Graphite and Grafana is the market standard for monitoring and central logging. This means that it is very easy to find Docker images, help and almost everything what is needed.
Viewing on mobile devices is possible, but far from being great, and this won’t change anytime soon judging from &lt;a href=&quot;https://github.com/elastic/kibana/issues/2563&quot;&gt;this Github issue&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Grafana panel:
&lt;img src=&quot;/data/2017-02-12-Choosing-centralized-logging-and-monitoring-system/Grafana_panel.png&quot; alt=&quot;Grafana panel&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Kibana panel:
&lt;img src=&quot;/data/2017-02-12-Choosing-centralized-logging-and-monitoring-system/Kibana_panel.png&quot; alt=&quot;Kibana panel&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The good&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;the market standard&lt;/li&gt;
  &lt;li&gt;great visualizations (both Grafana and Kibana)&lt;/li&gt;
  &lt;li&gt;great data crunching tools&lt;/li&gt;
  &lt;li&gt;there are some ELK SaaS providers.&lt;/li&gt;
  &lt;li&gt;great UI and visualization&lt;/li&gt;
  &lt;li&gt;web based&lt;/li&gt;
  &lt;li&gt;there are existing applications for server stats monitoring&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The bad&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;mostly Linux based and since I am running on a Windows Server this meant getting another Linux machine. Setting every&lt;/li&gt;
  &lt;li&gt;most providers are not free&lt;/li&gt;
  &lt;li&gt;a lot of stuff to manage on my own&lt;/li&gt;
  &lt;li&gt;no out of the box monitoring
&lt;br /&gt;
&lt;br /&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a name=&quot;New_Relic&quot;&gt;&lt;/a&gt;
&lt;img src=&quot;/data/2017-02-12-Choosing-centralized-logging-and-monitoring-system/newRelic.svg&quot; alt=&quot;New Relic&quot; class=&quot;logo&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;new-relic&quot;&gt;New Relic&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;http://newrelic.com&quot;&gt;New Relic&lt;/a&gt; is a power horse when it comes to features. It has almost everything, from APM (Application Performance Management) to log aggregation. It is a very interesting product since it is done in a way that will be readable to nontechnical people. It automatically sets up notifications for &lt;a href=&quot;https://en.wikipedia.org/wiki/Apdex&quot;&gt;apdex index&lt;/a&gt; violations, the UI is orientated into showing the main &lt;a href=&quot;https://en.wikipedia.org/wiki/Performance_indicator&quot;&gt;KPI&lt;/a&gt; for performance (like Google Analytics), not tech details like for example Azure Application Insights (next)&lt;/p&gt;

&lt;p&gt;The main dashboard:
&lt;img src=&quot;/data/2017-02-12-Choosing-centralized-logging-and-monitoring-system/newRelic_panel.png&quot; alt=&quot;NewRelic panel&quot; /&gt;&lt;/p&gt;

&lt;p&gt;I was quite impressed with how good New Relic inspects what went into each request. This is the Request monitoring page:
&lt;img src=&quot;/data/2017-02-12-Choosing-centralized-logging-and-monitoring-system/newRelic_requestDetails.png&quot; alt=&quot;NewRelic request details&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Another thing that is a nice feature, and very unique, is the Geo View. 
It shows how page speed differs for different geo locations. And as You can see I have a problem with Russia (I have no idea why):
&lt;img src=&quot;/data/2017-02-12-Choosing-centralized-logging-and-monitoring-system/NewRelic_geoPanel.png&quot; alt=&quot;NewRelic request details&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Installation is the easiest of all reviewed. All that is needed is to install the NewRelic Agent on the server. Dependencies detection, metering, even browser performance tracking works out of the box.&lt;/p&gt;

&lt;p&gt;One last thing to mention, &lt;strong&gt;and it may be subjective&lt;/strong&gt;. I had the impression that after installing the NewRelic’s agent on the server it slowed down a bit. I could be due to the fact that Application Insights was also running on it, or that my machine is just slow as it is. If someone else also has this impression ping me.&lt;/p&gt;

&lt;p&gt;To sum up - New Relic is a powerful beast with the looks that a manager can understand :)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The good&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;out of the box monitoring of .NET, Ruby, Node.js, PHP, Java, Python and Go applications&lt;/li&gt;
  &lt;li&gt;Supports web and non-web applications&lt;/li&gt;
  &lt;li&gt;Supports browser monitoring&lt;/li&gt;
  &lt;li&gt;fast and very good UI&lt;/li&gt;
  &lt;li&gt;Browser profiling works without the need to add a script (it is added automatically by the installed NewRelic agent)&lt;/li&gt;
  &lt;li&gt;very easy to install&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The bad&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;only paid version (I get why they have only a paid version. This is a minus for me when choosing for this use case. Remember this is a personal review).&lt;/li&gt;
  &lt;li&gt;it consists of multiple products, and even when in trial mode, enabling some of them requires contacting the sales department.&lt;/li&gt;
  &lt;li&gt;every sub-product is separately paid.&lt;/li&gt;
  &lt;li&gt;at registration(demo) requires the phone number, company name, company size, and role.&lt;/li&gt;
  &lt;li&gt;uninstalling requires a machine reboot.&lt;/li&gt;
  &lt;li&gt;expensive&lt;/li&gt;
  &lt;li&gt;confusing pricing
&lt;br /&gt;
&lt;br /&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;!-- Begin MailChimp Signup Form --&gt;

&lt;link href=&quot;//cdn-images.mailchimp.com/embedcode/horizontal-slim-10_7.css&quot; rel=&quot;stylesheet&quot; type=&quot;text/css&quot; /&gt;

&lt;style type=&quot;text/css&quot;&gt;
	#mc_embed_signup{
        clear:left; 
        font:14px Helvetica,Arial,sans-serif; 
        width:100%; 
        margin-top: 40px;
        margin-bottom: 40px;
        height:100px;
    }
    #mc_embed_signup .newsletter div{
        height: 100px;
    }
    #mc_embed_signup form{
        position: relative;
        top: -90px;
    }
	/* Add your own MailChimp form style overrides in your site stylesheet or in this style block.
	   We recommend moving this block and the preceding CSS link to the HEAD of your HTML file. */
&lt;/style&gt;

&lt;div id=&quot;mc_embed_signup&quot;&gt;
    &lt;div class=&quot;gradient newsletter&quot;&gt;
        &lt;div style=&quot;background:#000000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#1C0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#380000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#550000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#710000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#8D0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#AA0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#C60000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#E20000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF3800&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF5500&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF7100&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF8D00&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFAA00&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFC600&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFE200&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFFF00&quot;&gt;&lt;/div&gt;
    &lt;/div&gt;
    &lt;form action=&quot;https://IndexOutOfRange.us15.list-manage.com/subscribe/post?u=b1c1099bf7f49b95c64107c99&amp;amp;id=6a5eb68eb7&quot; method=&quot;post&quot; id=&quot;mc-embedded-subscribe-form&quot; name=&quot;mc-embedded-subscribe-form&quot; class=&quot;validate&quot; target=&quot;_blank&quot; novalidate=&quot;&quot;&gt;
        &lt;div id=&quot;mc_embed_signup_scroll&quot;&gt;
        &lt;label for=&quot;mce-EMAIL&quot; style=&quot;color: white;&quot;&gt;Get email notifications about new posts:&lt;/label&gt;
        &lt;input type=&quot;email&quot; value=&quot;&quot; name=&quot;EMAIL&quot; class=&quot;email&quot; id=&quot;mce-EMAIL&quot; placeholder=&quot;email address&quot; required=&quot;&quot; /&gt;
        &lt;!-- real people should not fill this in and expect good things - do not remove this or risk form bot signups--&gt;
        &lt;div style=&quot;position: absolute; left: -5000px;&quot; aria-hidden=&quot;true&quot;&gt;&lt;input type=&quot;text&quot; name=&quot;b_b1c1099bf7f49b95c64107c99_6a5eb68eb7&quot; tabindex=&quot;-1&quot; value=&quot;&quot; /&gt;&lt;/div&gt;
        &lt;div class=&quot;clear&quot;&gt;&lt;input type=&quot;submit&quot; value=&quot;Subscribe&quot; name=&quot;subscribe&quot; id=&quot;mc-embedded-subscribe&quot; class=&quot;button&quot; /&gt;&lt;/div&gt;
        &lt;/div&gt;
    &lt;/form&gt;
&lt;/div&gt;

&lt;!--End mc_embed_signup--&gt;

&lt;p&gt;&lt;a name=&quot;Retrace&quot;&gt;&lt;/a&gt;
&lt;img src=&quot;/data/2017-02-12-Choosing-centralized-logging-and-monitoring-system/retrace.png&quot; alt=&quot;Retrace&quot; class=&quot;logo&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;retrace-stackify&quot;&gt;Retrace (Stackify)&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://stackify.com/retrace/&quot;&gt;Retrace&lt;/a&gt; is a product from the same &lt;a href=&quot;https://stackify.com/about/&quot;&gt;guys (and girls)&lt;/a&gt; that developed &lt;a href=&quot;https://stackify.com/prefix/&quot;&gt;Prefix&lt;/a&gt; - a good local profiler. I must say I was impressed by the features and polish that this product has. The UI may not show it fully, but it is not that far away from the big players. In some features, it’s even way ahead.&lt;/p&gt;

&lt;p&gt;Retrace panel:
&lt;img src=&quot;/data/2017-02-12-Choosing-centralized-logging-and-monitoring-system/Retrace_panel.png&quot; alt=&quot;Retrace panel&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Retrace APM+ panel (from a demo application they provide. I was not able to get it working on my project):
&lt;img src=&quot;/data/2017-02-12-Choosing-centralized-logging-and-monitoring-system/Retrace_APM.png&quot; alt=&quot;Retrace APM+ panel&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The good&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;registration initially requires only Name, Surname and email are required 👍. Unfortunately, after email verification they want the rest 👎&lt;/li&gt;
  &lt;li&gt;what is being collected by the agent is controlled from the website. So after installing the agent on the server, no additional work on the server is required.&lt;/li&gt;
  &lt;li&gt;nice attention to details - when installing the NLog adapter we are prompted for the key.&lt;/li&gt;
  &lt;li&gt;the best out of the box alert triggers from them all. The only system monitoring disk queue length.&lt;/li&gt;
  &lt;li&gt;machine performance alerts are correlated with requests to the application.&lt;/li&gt;
  &lt;li&gt;fast full-text search and data analytics for logs&lt;/li&gt;
  &lt;li&gt;option to mark an error as “fixed”&lt;/li&gt;
  &lt;li&gt;quite fast UI&lt;/li&gt;
  &lt;li&gt;very good email alerts. They look good and are very informative.&lt;/li&gt;
  &lt;li&gt;very good customer service :) (emails and the comments)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The bad&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;after verification, they want a whole lot of info&lt;/li&gt;
  &lt;li&gt;I was not able to get any APM+ statistics. Everything looked properly configured, but it did not work. &lt;s&gt;I've emailed the support, but no answer (granted it was on the weekend)&lt;/s&gt; Support contacted me just after the weekend and is very helpful, but we were not able to get it working.&lt;/li&gt;
  &lt;li&gt;Dashboard page is in beta, so it doesn’t have that many features or great looking as Application Insights or New Relic.
&lt;br /&gt;
&lt;br /&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a name=&quot;Application_Insights&quot;&gt;&lt;/a&gt;
&lt;img src=&quot;/data/2017-02-12-Choosing-centralized-logging-and-monitoring-system/applicationInsights.png&quot; alt=&quot;Application Insights&quot; class=&quot;logo&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;application-insights&quot;&gt;Application Insights&lt;/h2&gt;

&lt;p&gt;Microsoft is investing heavily in its Azure cloud and it can be seen from the number of features they are rolling out every three months. They are investing more in the SaaS model and &lt;a href=&quot;https://azure.microsoft.com/en-us/services/application-insights/&quot;&gt;Application Insights&lt;/a&gt; fits quite good in this environment.
Application Insights feels a lot more developer orientated platform than New Relic. It can bee easily seen that they thought more about query capabilities (AND, OR operators), inner request details, features than in how to get the visualizations super nice.&lt;/p&gt;

&lt;p&gt;My customized main dashboard:
&lt;img src=&quot;/data/2017-02-12-Choosing-centralized-logging-and-monitoring-system/azure_panel.png&quot; alt=&quot;Azure dashboard&quot; /&gt;&lt;/p&gt;

&lt;p&gt;And the request details:
&lt;img src=&quot;/data/2017-02-12-Choosing-centralized-logging-and-monitoring-system/azure_requestDetails.png&quot; alt=&quot;Azure dashboard&quot; /&gt;
As you can see all dependencies were detected neatly.&lt;/p&gt;

&lt;p&gt;There is also one thing that strongly shows that Application Insights is targeted at IT specialists. By clicking Analyze in the top bar we can see the query behind every diagram, change it and use it for a custom report. The language used is very similar to F#. This means we have all the functional goodies like piping and support for data manipulation functions. As a person using F#, I must say “well done Microsoft”:)
&lt;img src=&quot;/data/2017-02-12-Choosing-centralized-logging-and-monitoring-system/azure_querryEditor.png&quot; alt=&quot;Azure dashboard&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The good&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;out of the box monitoring of sewer and browser (needs adding Google Analytics like script).&lt;/li&gt;
  &lt;li&gt;can be added without access to the code. This does not allow full capabilities (dependency tracking and performance monitoring is available), but most of them.&lt;/li&gt;
  &lt;li&gt;auto detected dependencies like HTTP requests and ADO(SQL) queries.&lt;/li&gt;
  &lt;li&gt;1 GB a month free.&lt;/li&gt;
  &lt;li&gt;has data limits.&lt;/li&gt;
  &lt;li&gt;has data sampling.&lt;/li&gt;
  &lt;li&gt;very good search build in Azure portal. It searches in products and instances of products. This is more important than one might think because the number of screens is massive. Even when counting only those in the Application Insights module.&lt;/li&gt;
  &lt;li&gt;customizable dashboard for every Azure offering (every panel can be moved to the main dashboard).&lt;/li&gt;
  &lt;li&gt;the top bar displays connected features. When you open the pricing window it displays a link to the data limit window.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The bad&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;detection of application map did not work that great with Oracle database (this may be a configuration issue, I haven’t had time to investigate)&lt;/li&gt;
  &lt;li&gt;UI can get sluggish sometimes.&lt;/li&gt;
  &lt;li&gt;UI sometimes refuses to open a window. A reload helps.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;Raygun&quot;&gt;&lt;/a&gt;
&lt;img src=&quot;/data/2017-02-12-Choosing-centralized-logging-and-monitoring-system/raygun.png&quot; alt=&quot;Raygun&quot; class=&quot;logo&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;raygun&quot;&gt;Raygun&lt;/h2&gt;

&lt;p&gt;I’ve decided to check &lt;a href=&quot;raygun.com&quot;&gt;Raygun&lt;/a&gt; mostly because of Scott Hanselman’s (it is even featured on the website) and  &lt;a href=&quot;https://www.troyhunt.com/error-logging-and-tracking-done-right/&quot;&gt;Troy Hunt’s&lt;/a&gt; recommendations.
Raygun, similar to New Relic, hides multiple services under its name. In this case, it’s &lt;strong&gt;Pulse&lt;/strong&gt; and &lt;strong&gt;Crash Report&lt;/strong&gt;.
&lt;strong&gt;Pulse&lt;/strong&gt; is available for: Android, iOS, maxOS, JavaScript, WordPress, Xamarin.Android and Xamarin.iOS. No .NET here so I will not be exploring this path.
&lt;strong&gt;Crash report&lt;/strong&gt; supports 27 options with most languages and platform covered(Ruby, Node, PHP, .NET, Go, ColdFusion and mobile).
After playing with it a bit I can say that Raygun is not a tool I was looking for because it is focused on logs and crash reports, not on monitoring. That said it does it very well and has its place as a tool. 
How it works is that it will notify You when an error occurs and gives the possibility to mark it as fixed, but not deployed to prod. This will halt notifications of this type of errors. A simple feature, but a quite valuable one then managing production health and prioritizing bug fixes.&lt;/p&gt;

&lt;p&gt;Raygun panel:
&lt;img src=&quot;/data/2017-02-12-Choosing-centralized-logging-and-monitoring-system/Raygun_panel.png&quot; alt=&quot;Raygun dashboard&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The good&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;the logo reminds me of an old game &lt;a href=&quot;https://en.wikipedia.org/wiki/Earthworm_Jim&quot;&gt;Earthworm Jim&lt;/a&gt;, oh the memories…:)&lt;/li&gt;
  &lt;li&gt;very carefully designed UI.&lt;/li&gt;
  &lt;li&gt;easy to setup (NuGet package + web config changes)&lt;/li&gt;
  &lt;li&gt;checking an error as fixed works good&lt;/li&gt;
  &lt;li&gt;the filtering won’t let You filter on non-existing values. This prevents from misspelling the browser type for example. Small, but useful feature.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The bad&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;at registration(demo) requires a phone number, company name, company size, and role.&lt;/li&gt;
  &lt;li&gt;it is only a log aggregating mechanism&lt;/li&gt;
  &lt;li&gt;the filtering has very little fields to work with
&lt;br /&gt;
&lt;br /&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a name=&quot;Datadog&quot;&gt;&lt;/a&gt;
&lt;img src=&quot;/data/2017-02-12-Choosing-centralized-logging-and-monitoring-system/Datadog.png&quot; alt=&quot;Application Insights&quot; class=&quot;logo&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;datadog&quot;&gt;Datadog&lt;/h2&gt;

&lt;p&gt;I’ve heard earlier about &lt;a href=&quot;https://www.Datadoghq.com&quot;&gt;Datadog&lt;/a&gt;, but never checked it before. The first impression was very good, but soon everything started going downhill (see the &lt;strong&gt;The bad&lt;/strong&gt; section).
It became clear quite fast that Datadog is targeted to administrators and people that need to have a big picture of servers and services that they have. This is a higher view than the application view I am looking for.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/data/2017-02-12-Choosing-centralized-logging-and-monitoring-system/Datadog_panel.png&quot; alt=&quot;Datadog dashboard&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The good&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;it can integrate with a huge number of systems (the only tool that could monitor Solr and Docker containers)&lt;/li&gt;
  &lt;li&gt;when I finally managed to find a dashboard it looked really good.&lt;/li&gt;
  &lt;li&gt;very customizable dashboard. Reminds me strongly of Grafana&lt;/li&gt;
  &lt;li&gt;it has infrastructure map&lt;/li&gt;
  &lt;li&gt;it has a free (with limited features) version up to 5 hosts.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The bad&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;agent installation is strange. It is done by running the command in the command window and after it nothing happens. The stats started appearing after few minutes (~10), so I was already googling if anyone had a similar problem.&lt;/li&gt;
  &lt;li&gt;agent after installation does the bare minimum. Its functionality can be extended by adding integrations on the website. This is the good part. What is not so nice is that adding a new feature requires changes the agent config, and other services, done manually on the server. This means a more configuration and no clean uninstall :( Retrace showed how to do it better.&lt;/li&gt;
  &lt;li&gt;the configuration file (which You have to edit manually) is tab sensitive (??!!)&lt;/li&gt;
  &lt;li&gt;no log aggregation&lt;/li&gt;
  &lt;li&gt;to add an integration You have to: save the config file (edited in the agent), enable the monitoring and restart the agent.&lt;/li&gt;
  &lt;li&gt;it took me way longer than I would wish for to get the SQL and IIS monitoring to work&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;-comparison-table&quot;&gt;&lt;a name=&quot;Comparison_table&quot;&gt;&lt;/a&gt; Comparison table&lt;/h1&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;Service&lt;/th&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;Google Analytics&lt;/th&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;ELK + Graphite/Graphana&lt;/th&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;NewRelic&lt;/th&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;Retrace&lt;/th&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;Application Insights&lt;/th&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;Raygun&lt;/th&gt;
      &lt;th&gt;Data dog&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;Logging&lt;/strong&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt; &lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt; &lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt; &lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt; &lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt; &lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt; &lt;/td&gt;
      &lt;td&gt; &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Centralized logging&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;N&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Y&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Y&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Y&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Y&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Y&lt;/td&gt;
      &lt;td&gt;N&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Log querying&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;N&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Y&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;S&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Y&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Y&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;N*9&lt;/td&gt;
      &lt;td&gt;N&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Custom log reports&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Y&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Y&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;S&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Y&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Y&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;N&lt;/td&gt;
      &lt;td&gt;N&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Browser error collection&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;N&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;CbI*4&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Y&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;N&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;a href=&quot;https://docs.microsoft.com/en-us/azure/application-insights/app-insights-javascript&quot;&gt;Y&lt;/a&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;N&lt;/td&gt;
      &lt;td&gt;N&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;APM&lt;/strong&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt; &lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt; &lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt; &lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt; &lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt; &lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt; &lt;/td&gt;
      &lt;td&gt; &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Server side performance&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;CbI&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Y&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Y&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Y&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Y&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;N&lt;/td&gt;
      &lt;td&gt;Y&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Browser side performance&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Y&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;CbI *4&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Y&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;N&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;a href=&quot;https://docs.microsoft.com/en-us/azure/application-insights/app-insights-javascript&quot;&gt;Y&lt;/a&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;N&lt;/td&gt;
      &lt;td&gt;N&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Environment performance&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;CbI&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;3rd party tools *5&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Y&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Y&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Y&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;N&lt;/td&gt;
      &lt;td&gt;N&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Custom metrics&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;CbI&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Y&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Y&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;a href=&quot;http://support.stackify.com/hc/en-us/articles/205419705-Custom-Metrics-Overview&quot;&gt;Y&lt;/a&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;a href=&quot;https://docs.microsoft.com/en-us/azure/application-insights/app-insights-search-diagnostic-logs&quot;&gt;Y*7&lt;/a&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;N&lt;/td&gt;
      &lt;td&gt;Y *10&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Alerts&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;N&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Y&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Y&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Y&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Y&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;N&lt;/td&gt;
      &lt;td&gt;Y&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Real time view&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Y&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Y&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Y&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Y&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Y&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;N&lt;/td&gt;
      &lt;td&gt;Y&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Custom perf. reports&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Y&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Y&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;a href=&quot;https://docs.newrelic.com/docs/apm/reports&quot;&gt;N&lt;/a&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;N&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;S&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;N&lt;/td&gt;
      &lt;td&gt;&lt;a href=&quot;https://www.Datadoghq.com/blog/learn-from-your-alerts-with-the-weekly-monitor-trend-report/&quot;&gt;Y&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Request dependencies details&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;N&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;N&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Y&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;N&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Y&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;N&lt;/td&gt;
      &lt;td&gt;N&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;Making life easier&lt;/strong&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt; &lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt; &lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt; &lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt; &lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt; &lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt; &lt;/td&gt;
      &lt;td&gt; &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Mobile access&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Y *13&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;3rd party*6&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Y *13&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;N&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Works *2&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Y&lt;/td&gt;
      &lt;td&gt;S&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;OAuth&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Y&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;N&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;N&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;N&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;N&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Y&lt;/td&gt;
      &lt;td&gt;N&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;Features&lt;/strong&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt; &lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt; &lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt; &lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt; &lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt; &lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt; &lt;/td&gt;
      &lt;td&gt; &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Application map&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;N&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;N&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Y&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;N&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Y&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;N&lt;/td&gt;
      &lt;td&gt;N*11&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Price&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;a href=&quot;(https://developers.google.com/analytics/devguides/collection/analyticsjs/limits-quotas)&quot;&gt;Free with limists&lt;/a&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;60$*14&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;150$*8&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;a href=&quot;https://stackify.com/retrace/&quot;&gt;300$&lt;/a&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Free*3&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;a href=&quot;https://raygun.com/pricing#crashreporting&quot;&gt;588$&lt;/a&gt;&lt;/td&gt;
      &lt;td&gt;&lt;a href=&quot;https://www.Datadoghq.com/pricing/&quot;&gt;Free*12&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;&lt;strong&gt;Legend:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;CbI - Can be implemented&lt;/li&gt;
  &lt;li&gt;S - Sort of. Not fully supported, or with very few features.&lt;/li&gt;
  &lt;li&gt;*2 - Azure portal is usable on mobile, but not a mobile first experience ;)&lt;/li&gt;
  &lt;li&gt;*3 - Application Insights is &lt;a href=&quot;https://azure.microsoft.com/en-us/pricing/details/application-insights/&quot;&gt;free up to 1 GB per month&lt;/a&gt;. There is also a data cap and data sampling option, so staying in the limit is realistic.&lt;/li&gt;
  &lt;li&gt;*4 - You have to implement the browser side and the proxy&lt;/li&gt;
  &lt;li&gt;*5 - There are 3rd party tool available, although quality varies.&lt;/li&gt;
  &lt;li&gt;*6 - there is An Android app &lt;a href=&quot;https://play.google.com/store/apps/details?id=com.tnc.android.graphite&amp;amp;hl=en&quot;&gt;Graphitoid&lt;/a&gt; for watching Graphite (did not try it). Kibana seems &lt;a href=&quot;https://discuss.elastic.co/t/kibana-charts-dashboards-not-rendering-on-mobile/48614&quot;&gt;not to work on mobile&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;*7 - Application Insights has three types of events: event (something happened), metric (something took x amount of time) and dependency (if auto detection didn’t see this one. Can also log time)&lt;/li&gt;
  &lt;li&gt;*8 - New Relic’s pricing is not that straight forward. It is based on the type of a machine instance and hours it will run. This is the cheapest option I could find.&lt;/li&gt;
  &lt;li&gt;*9 - it supports basic queries but doesn’t allow filtering on error text, so for me, it is a NO.&lt;/li&gt;
  &lt;li&gt;*10 - if You log this metric as a performance counter Datadog can read it.&lt;/li&gt;
  &lt;li&gt;*11 - there is only an infrastructure map.&lt;/li&gt;
  &lt;li&gt;*12 - the free version doesn’t include alerts.&lt;/li&gt;
  &lt;li&gt;*13 - dedicated app&lt;/li&gt;
  &lt;li&gt;*14 - Kibana and Graphite is free, bit since I don’t want to install it on my server I have to fing a SaaS(hosted) offering. The cheapest I could find was &lt;a href=&quot;https://www.digitalocean.com/pricing/#droplet&quot;&gt;Digital Ocean&lt;/a&gt;. Also, logz.io have a free offering up to 1GB&lt;s&gt;, but no [pricing](http://logz.io/pricing/) (?)&lt;/s&gt; the pricing widget appears on Edge and after disabling all add blockers and similar extensions.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;what-ive-choose&quot;&gt;&lt;a name=&quot;What_Ive_choose&quot;&gt;&lt;/a&gt;What I’ve choose?&lt;/h1&gt;

&lt;p&gt;Remember I am looking for a tool that will be used in my side project. This means I will be spending my own money, and I don’t like to spend too much of it. The dislike for overspending is one of the main reasons &lt;a href=&quot;/The-importance-of-running-on-crapp&quot;&gt;I am running on crapp&lt;/a&gt; (it costs me ~320$ a year). So price will be important.&lt;/p&gt;

&lt;p&gt;This said I will admit I have been blown away but what &lt;strong&gt;Application Insights&lt;/strong&gt; offers and the pricing. I like that it is targeted to developers, still being very accessible. The pricing model is the best fitting for me since I can easily control if I want to pay and how much. There are still some things that would make me happier:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Login with Google.&lt;/strong&gt; This is the most popular OAuth account on the web and would make my life a bit easier. I get why this is not the option, but still.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Faster UI.&lt;/strong&gt; I don’t get the SPA idea in the portal. It is great when moving in scope of one module, but I would not mind a reload when going from the dashboard to AI&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;More stable UI.&lt;/strong&gt; Some windows open full screen, some open as a blade (internal Azure name). Sometimes they don’t open.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The second place goes to &lt;strong&gt;New Relic&lt;/strong&gt;. It is expensive and not exactly what I am looking for, but if I had to report performance to nontechnical people this would be the service I choose. It is easy, nice looking (this is more important than You think) and yet manages to deliver just enough information to get a glimpse what is happening.&lt;/p&gt;

&lt;p&gt;The third place goes to &lt;strong&gt;Retrace from Stackify&lt;/strong&gt;. It has better alerts than the top two, but no single request analytics and that was the reason why it took the third place. Still, it is a very good tool. Another plus is that it has the option to mute an error similar to Raygun.&lt;/p&gt;

&lt;p&gt;In the next entry - Application Insights configuration and architecture.&lt;/p&gt;

&lt;style&gt;
div.entry-content .logo{
    height:150px;
}
table tr:nth-child(even) {background: #DDD}
table tr:nth-child(odd) {background: #FFF}
&lt;/style&gt;

</description>
        <pubDate>Sun, 12 Feb 2017 00:00:00 +0100</pubDate>
        <link>https://IndexOutOfRange.com//Choosing-centralized-logging-and-monitoring-system/</link>
        <guid isPermaLink="true">https://IndexOutOfRange.com//Choosing-centralized-logging-and-monitoring-system/</guid>
      </item>
    
      <item>
        <title>Understanding OutOfMemoryException</title>
        <description>&lt;img src='https://indexoutofrange.com/data/2017-01-02-Understanding-OutOfMemoryException/logo.jpg' /&gt;&lt;p&gt;In my &lt;a href=&quot;/tags/#similarity&quot;&gt;ongoing series on calculating similarities&lt;/a&gt; one angle always seemed worth trying, and was pointed out many times on Reddit - use C++ and matrix manipulations. Similarity calculation fits very nicely into matrix representation, and there are algorithms targeting sparse matrix manipulation. So why did I delay it for so long? Because I had other angles I wanted to try and, from the looks of it required significant changes in the existing code base. But since &lt;a href=&quot;/Divide-and-conquer-bits-for-performance/&quot;&gt;last optimizations didn’t bring the time cuts I’ve expected&lt;/a&gt;, the time has come. Brace yourself.&lt;/p&gt;

&lt;!--MORE--&gt;

&lt;h2 id=&quot;use-matrixes&quot;&gt;Use matrixes&lt;/h2&gt;

&lt;p&gt;After some refactoring, I’ve managed to create a place where I could swap the existing implementation for the new one.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;It took ~30 minutes of thinking, going back and fourth, but in the end, I’ve maneged to fit in without adding changes to the external code only for this implementation. So think, think, think and then code. Not the other way around. It is faster that way.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The function signature is this:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&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;n&quot;&gt;Dictionary&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;,&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;n&quot;&gt;RecipeSimilarityLight&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;calculateSimilarityMapForAll&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&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;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IngredientWeightsVector&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;recipeIngredientVector&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ILogger&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;logger&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;/div&gt;

&lt;p&gt;where:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Dictionary&amp;lt;int, IngredientWeightsVector&amp;gt; vectorMap&lt;/code&gt; is a dictionary where the key is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RecipeId&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IngredientWeightsVector&lt;/code&gt; is a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IDictionary&lt;/code&gt; containing the owned ingredients and weights.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I first wanted to try the most brute force approach possible - using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;float[][]&lt;/code&gt; without any fancy algorithms. Just to have a reference point. So here it is:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&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;n&quot;&gt;Dictionary&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;,&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;n&quot;&gt;RecipeSimilarityLight&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;calculateSimilarityMapForAll&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&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;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IngredientWeightsVector&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vectorMap&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;NLog&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Logger&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;logger&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;//similarity calculations&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;matrix&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;CreateRecipeMatrix&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vectorMap&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;transposeMatrix&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Transpose&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;matrix&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;multiplyed&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Multiply&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;matrix&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;transposeMatrix&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;vectorsLength&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ComputeVectorsLength&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vectorMap&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;resultMatrix&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Normalize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;matrix&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vectorsLength&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;//finding the most similar recipes&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dict&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;initSimilarityMap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;allRecipes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;resultMatrix&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&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;index&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;500&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;logger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Info&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Calculated: &quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot; from: &quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;allRecipes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Count&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;recipeId&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;allRecipes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;resultMatrix&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&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;secondRecipeId&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;allRecipes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;j&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;similarity&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;resultMatrix&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
            &lt;span class=&quot;nf&quot;&gt;addSimilarityIfGoodEnough&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dict&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;recipeId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;recipeId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;secondRecipeId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;similarity&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;return&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;dict&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ToDictionary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&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;nf&quot;&gt;ToList&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;/div&gt;

&lt;p&gt;After clicking run I saw this:&lt;/p&gt;

&lt;div class=&quot;language-console highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;go&quot;&gt;Unhandled Exception: OutOfMemoryException.
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;and soon after, this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/data/2017-01-02-Understanding-OutOfMemoryException/your-computer-is-low-on-memory.png&quot; alt=&quot;Your computer is low on memory.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;So without terminating the application I fired up Task Manager and saw this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/data/2017-01-02-Understanding-OutOfMemoryException/TaskManager.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;So what is going on here? I have 16 Gigs of RAM and I get OutOfMemoryException from a process holding less than one?&lt;/p&gt;

&lt;p&gt;Since there are many ways to look at one problem I fired up something more advanced - &lt;a href=&quot;https://technet.microsoft.com/en-us/sysinternals/processexplorer.aspx&quot;&gt;Process Explorer&lt;/a&gt; from Microsoft.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Process Explorer is a part of &lt;a href=&quot;https://technet.microsoft.com/en-us/sysinternals/bb842062.aspx&quot;&gt;SysInternals Suite&lt;/a&gt; and it is a MUST HAVE for anyone using Windows environment. It requires no installation, just copy and paste.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Process Explorer showed the same and &lt;a href=&quot;https://www.youtube.com/watch?v=FGK8IC-bGnU&quot; target=&quot;_blank&quot;&gt;something completely different&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/data/2017-01-02-Understanding-OutOfMemoryException/ProcessExplorer.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;One number is the same (there is a slight difference due to my computer crashing because of low memory), but the other number is a bit, to say it politely, different. And it is huge - &lt;strong&gt;35 gigabytes&lt;/strong&gt;. So what are those two categories and why is Task Manager showing one, and not the other?&lt;/p&gt;

&lt;p&gt;To fully understand why did I get &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OutOfMemoryException&lt;/code&gt; while still having much RAM memory free we will have to understand, at least a bit, memory allocation in Windows and .NET Framework.&lt;/p&gt;

&lt;!-- Begin MailChimp Signup Form --&gt;

&lt;link href=&quot;//cdn-images.mailchimp.com/embedcode/horizontal-slim-10_7.css&quot; rel=&quot;stylesheet&quot; type=&quot;text/css&quot; /&gt;

&lt;style type=&quot;text/css&quot;&gt;
	#mc_embed_signup{
        clear:left; 
        font:14px Helvetica,Arial,sans-serif; 
        width:100%; 
        margin-top: 40px;
        margin-bottom: 40px;
        height:100px;
    }
    #mc_embed_signup .newsletter div{
        height: 100px;
    }
    #mc_embed_signup form{
        position: relative;
        top: -90px;
    }
	/* Add your own MailChimp form style overrides in your site stylesheet or in this style block.
	   We recommend moving this block and the preceding CSS link to the HEAD of your HTML file. */
&lt;/style&gt;

&lt;div id=&quot;mc_embed_signup&quot;&gt;
    &lt;div class=&quot;gradient newsletter&quot;&gt;
        &lt;div style=&quot;background:#000000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#1C0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#380000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#550000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#710000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#8D0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#AA0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#C60000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#E20000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF3800&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF5500&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF7100&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF8D00&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFAA00&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFC600&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFE200&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFFF00&quot;&gt;&lt;/div&gt;
    &lt;/div&gt;
    &lt;form action=&quot;https://IndexOutOfRange.us15.list-manage.com/subscribe/post?u=b1c1099bf7f49b95c64107c99&amp;amp;id=6a5eb68eb7&quot; method=&quot;post&quot; id=&quot;mc-embedded-subscribe-form&quot; name=&quot;mc-embedded-subscribe-form&quot; class=&quot;validate&quot; target=&quot;_blank&quot; novalidate=&quot;&quot;&gt;
        &lt;div id=&quot;mc_embed_signup_scroll&quot;&gt;
        &lt;label for=&quot;mce-EMAIL&quot; style=&quot;color: white;&quot;&gt;Get email notifications about new posts:&lt;/label&gt;
        &lt;input type=&quot;email&quot; value=&quot;&quot; name=&quot;EMAIL&quot; class=&quot;email&quot; id=&quot;mce-EMAIL&quot; placeholder=&quot;email address&quot; required=&quot;&quot; /&gt;
        &lt;!-- real people should not fill this in and expect good things - do not remove this or risk form bot signups--&gt;
        &lt;div style=&quot;position: absolute; left: -5000px;&quot; aria-hidden=&quot;true&quot;&gt;&lt;input type=&quot;text&quot; name=&quot;b_b1c1099bf7f49b95c64107c99_6a5eb68eb7&quot; tabindex=&quot;-1&quot; value=&quot;&quot; /&gt;&lt;/div&gt;
        &lt;div class=&quot;clear&quot;&gt;&lt;input type=&quot;submit&quot; value=&quot;Subscribe&quot; name=&quot;subscribe&quot; id=&quot;mc-embedded-subscribe&quot; class=&quot;button&quot; /&gt;&lt;/div&gt;
        &lt;/div&gt;
    &lt;/form&gt;
&lt;/div&gt;

&lt;!--End mc_embed_signup--&gt;

&lt;h2 id=&quot;windows-memory-allocation-and-net-framework&quot;&gt;Windows, memory allocation and .NET Framework&lt;/h2&gt;

&lt;p&gt;So how I ended up with ~800MB &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Working Set&lt;/code&gt;, ~45 times larger &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Private Byes&lt;/code&gt; an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OutOfMemoryException&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Your system is low on memory&lt;/code&gt; message from Windows? This has to do with the way .NET Framework behaves.&lt;/p&gt;

&lt;p&gt;Windows has a few used memory measurement, but I will concentrate on two of them:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Private Bytes also called the Private Set&lt;/li&gt;
  &lt;li&gt;Working Set&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What is the difference?&lt;/p&gt;

&lt;p&gt;Before I continue one note:
There is a lot more to Windows and .NET memory management. I’ve taken only the parts needed for this problem. Go and read the linked articles for more in depth knowledge.&lt;/p&gt;

&lt;h3 id=&quot;working-set&quot;&gt;Working Set&lt;/h3&gt;

&lt;p&gt;A simple explanation:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Working set is the &lt;strong&gt;RAM&lt;/strong&gt; memory that the process is currently using. 
Touching memory fragment for the first time moves it from &lt;em&gt;Private Bytes&lt;/em&gt; to &lt;em&gt;Working Set&lt;/em&gt;[&lt;a href=&quot;https://blogs.msdn.microsoft.com/tims/2010/10/29/pdc10-mysteries-of-windows-memory-management-revealed-part-two/&quot;&gt;source&lt;/a&gt;]&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Precise one:
This is the memory that the process can is currently using. Here are all variables and mapped files.&lt;/p&gt;

&lt;h3 id=&quot;private-bytes&quot;&gt;Private Bytes&lt;/h3&gt;

&lt;p&gt;To put it simple:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;Private Bytes&lt;/strong&gt; is the memory that the process &lt;strong&gt;might need&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A more precise:
This is the amount of memory that the OS thinks the process will need in the near future. To be even more precise it is the &lt;em&gt;amount of space that has been allocated in the swap file to hold the contents of the private memory in the event that it is swapped out&lt;/em&gt; [&lt;a href=&quot;https://blogs.msdn.microsoft.com/ricom/2005/08/01/private-bytes-performance-counter-beware/&quot;&gt;source&lt;/a&gt;]. As mentioned by the cited article this value may, and very often is, overestimated by the OS.&lt;/p&gt;

&lt;p&gt;So why is the OS thinking I will need 35 gigabytes of memory? It must be the .NET Framework.&lt;/p&gt;

&lt;h3 id=&quot;net-framework-memory-allocation&quot;&gt;.NET Framework memory allocation&lt;/h3&gt;

&lt;p&gt;When running managed code .NET Framework is taking care of memory allocation and collection. It is allocating memory in bigger chunks from the OS, so that when creating a variable, so allocating memory for it, we are not communicating with the underlying system, but only with the runtime. Why .NET is doing it? For several reasons:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;To keep track of the allocated objects so it can garbage collect them.&lt;/li&gt;
  &lt;li&gt;For performance. Allocating a 20 MB chunk with one call will faster than doing it with 2000 100KB calls.&lt;/li&gt;
  &lt;li&gt;Memory fragmentation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The last one needs a it more clarification:
This is the situation when where is no continuous block of free memory of requested size, but the sum of free memory is bigger than requested. Because one ASCI art says more than 1000 words here it is:&lt;/p&gt;

&lt;div class=&quot;language-console highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;go&quot;&gt;Our memory:
|oo_o_ooo__o_o_o|
where:
- o - allocated
- _ - free
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;In this situation, although we have 6 slots of free memory we can’t allocate a 3 slot object. 
How is .NET different from the OS in this subject? .NET can change the physical address of the object in the &lt;a href=&quot;https://msdn.microsoft.com/en-us/library/ee787088(v=vs.110).aspx&quot;&gt;compaction phase of the garbage collection&lt;/a&gt; as long as it is not pinned using &lt;a href=&quot;https://msdn.microsoft.com/en-us/library/f58wzh21.aspx&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fixed&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;So .NET Framework is over allocating, and then Windows is also over allocating and this ends up in the system running out of memory and crashing my application? This means that the framework AND the operating system is broken?&lt;/p&gt;

&lt;p&gt;It is best not to assume that step back, have a break and look at the code once again in few minutes.&lt;/p&gt;

&lt;h2 id=&quot;the-mystery&quot;&gt;The mystery&lt;/h2&gt;

&lt;p&gt;I finally figured it out and it was so obvious that I felt stupid. Can You guess why did I run out of memory? To make it easier:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;the framework is not broken&lt;/li&gt;
  &lt;li&gt;Windows is not broken (at least in this case)&lt;/li&gt;
  &lt;li&gt;read the &lt;a href=&quot;/How_I_calculate_similarities_in_cookit/&quot;&gt;first&lt;/a&gt; and the &lt;a href=&quot;/How-to-calculate-17-billion-similarities/&quot;&gt;second&lt;/a&gt; post.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are no awards, but I will try to highlight those who get it.&lt;/p&gt;
</description>
        <pubDate>Mon, 02 Jan 2017 00:00:00 +0100</pubDate>
        <link>https://IndexOutOfRange.com//Understanding-OutOfMemoryException/</link>
        <guid isPermaLink="true">https://IndexOutOfRange.com//Understanding-OutOfMemoryException/</guid>
      </item>
    
      <item>
        <title>Dividing a bit in two for performance</title>
        <description>&lt;img src='https://indexoutofrange.com/data/2016-12-22-Dividing-a-bit-in-two-for-performance/logo.jpg' /&gt;&lt;p&gt;This post is an analysis of a very interesting optimization proposed by Nicholas Frechette in the comments under the &lt;a href=&quot;/Making-bits-faster/&quot;&gt;previous post&lt;/a&gt; and t0rakka &lt;a href=&quot;https://www.reddit.com/r/programming/comments/5i2x5r/using_bit_masks_for_highperformance_calculations/db55nz6/&quot;&gt;on Reddit&lt;/a&gt;.
They proposed to use one of the oldest tricks in performance cookbook - &lt;a href=&quot;https://en.wikipedia.org/wiki/Divide_and_conquer_algorithms&quot;&gt;divide and conquer&lt;/a&gt;. Well, it did not turn out as I expected.&lt;/p&gt;

&lt;!--MORE--&gt;

&lt;h2 id=&quot;recap&quot;&gt;Recap&lt;/h2&gt;

&lt;p&gt;The last implementation of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GetNonZeroIndexes&lt;/code&gt; looked like this:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;        &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IList&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;nf&quot;&gt;GetNonZeroIndexes&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;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;ret&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;k&quot;&gt;for&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;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&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;a&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&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;a&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0U&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;L&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;a&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1U&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;L&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;m&quot;&gt;0U&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;64&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&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;a&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;2U&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;L&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;m&quot;&gt;0U&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;64&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;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;4U&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;L&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;m&quot;&gt;0U&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;64&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;2&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;a&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;8U&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;L&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;m&quot;&gt;0U&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;64&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;3&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;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;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1152921504606846976U&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;L&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;m&quot;&gt;0U&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;64&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;60&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;a&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;2305843009213693952U&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;L&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;m&quot;&gt;0U&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;64&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;61&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;a&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;4611686018427387904U&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;L&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;m&quot;&gt;0U&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;64&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;62&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;a&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;9223372036854775808U&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;L&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;m&quot;&gt;0U&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;64&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;63&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;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ret&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;/div&gt;

&lt;p&gt;How can this get better?&lt;/p&gt;

&lt;h2 id=&quot;divide-and-conquer&quot;&gt;Divide and conquer&lt;/h2&gt;

&lt;h3 id=&quot;theory&quot;&gt;Theory&lt;/h3&gt;
&lt;p&gt;The above approach is a brute force approach. Why? I am iterating over the long and checking for every bit if it is set. This is wasteful since most of them are not set (remember those are &lt;a href=&quot;/Using-bit-operations-for-performance-optimizations&quot;&gt;sparse arrays&lt;/a&gt;). The better approach would be to test multiple bits at once. How? Bit masks - as always :)&lt;/p&gt;

&lt;p&gt;Using bit masks and the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AND&lt;/code&gt; operation I could check the first 32 bits (from 64 that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ulong&lt;/code&gt; has):&lt;/p&gt;

&lt;div class=&quot;language-console highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;go&quot;&gt;0000000011111111 &amp;lt;- masc
0001100110001001 &amp;lt;- value

0000000010001001 &amp;lt;- after AND
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If any bit in this range is set then the result will be greater than zero. Simple as that.&lt;br /&gt;&lt;/p&gt;

&lt;h3 id=&quot;implementation&quot;&gt;Implementation&lt;/h3&gt;

&lt;p&gt;I could replace &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GetNonZeroIndexes&lt;/code&gt; with this code:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IList&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;nf&quot;&gt;GetNonZeroIndexes&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;ret&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;k&quot;&gt;for&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;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&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;a&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&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;a&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0U&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;//is any bit set?&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;a&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;BitVectorMaskConsts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_0_32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;//is any of the 32 least significant bits set?&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;a&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;BitVectorMaskConsts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_0_16&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;//is any of the 16 least significant bits set?&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;a&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;BitVectorMaskConsts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_0_8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;//is any of the 8 least significant bits set?&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;a&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;BitVectorMaskConsts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_0_4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;//is any of the 4 least significant bits set?&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;a&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1U&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;L&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;m&quot;&gt;0U&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;64&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&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;a&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;2U&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;L&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;m&quot;&gt;0U&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;64&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;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;4U&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;L&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;m&quot;&gt;0U&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;64&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;2&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;a&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;8U&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;L&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;m&quot;&gt;0U&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;64&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;3&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;a&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;BitVectorMaskConsts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_4_8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&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;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;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;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ret&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;/div&gt;

&lt;h3 id=&quot;complexity&quot;&gt;Complexity&lt;/h3&gt;

&lt;p&gt;What divide and conquer is doing is simulating a &lt;a href=&quot;https://en.wikipedia.org/wiki/Binary_tree&quot;&gt;binary tree&lt;/a&gt; consisting of 64 nodes.&lt;/p&gt;

&lt;p&gt;Since my tree is fully balanced (equal number of nodes on the left and right) its max depth is equal to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;log n&lt;/code&gt;. With &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;n&lt;/code&gt; equal to a number of leafs in the tree. I am doing a brute force iteration over the last 4 elements so my number of leafs is 64/4 = 16. This means that I’ll be doing &lt;strong&gt;from 5 to 9 checks&lt;/strong&gt; in the worst case. Looks promising.&lt;/p&gt;

&lt;!-- Begin MailChimp Signup Form --&gt;

&lt;link href=&quot;//cdn-images.mailchimp.com/embedcode/horizontal-slim-10_7.css&quot; rel=&quot;stylesheet&quot; type=&quot;text/css&quot; /&gt;

&lt;style type=&quot;text/css&quot;&gt;
	#mc_embed_signup{
        clear:left; 
        font:14px Helvetica,Arial,sans-serif; 
        width:100%; 
        margin-top: 40px;
        margin-bottom: 40px;
        height:100px;
    }
    #mc_embed_signup .newsletter div{
        height: 100px;
    }
    #mc_embed_signup form{
        position: relative;
        top: -90px;
    }
	/* Add your own MailChimp form style overrides in your site stylesheet or in this style block.
	   We recommend moving this block and the preceding CSS link to the HEAD of your HTML file. */
&lt;/style&gt;

&lt;div id=&quot;mc_embed_signup&quot;&gt;
    &lt;div class=&quot;gradient newsletter&quot;&gt;
        &lt;div style=&quot;background:#000000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#1C0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#380000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#550000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#710000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#8D0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#AA0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#C60000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#E20000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF3800&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF5500&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF7100&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF8D00&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFAA00&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFC600&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFE200&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFFF00&quot;&gt;&lt;/div&gt;
    &lt;/div&gt;
    &lt;form action=&quot;https://IndexOutOfRange.us15.list-manage.com/subscribe/post?u=b1c1099bf7f49b95c64107c99&amp;amp;id=6a5eb68eb7&quot; method=&quot;post&quot; id=&quot;mc-embedded-subscribe-form&quot; name=&quot;mc-embedded-subscribe-form&quot; class=&quot;validate&quot; target=&quot;_blank&quot; novalidate=&quot;&quot;&gt;
        &lt;div id=&quot;mc_embed_signup_scroll&quot;&gt;
        &lt;label for=&quot;mce-EMAIL&quot; style=&quot;color: white;&quot;&gt;Get email notifications about new posts:&lt;/label&gt;
        &lt;input type=&quot;email&quot; value=&quot;&quot; name=&quot;EMAIL&quot; class=&quot;email&quot; id=&quot;mce-EMAIL&quot; placeholder=&quot;email address&quot; required=&quot;&quot; /&gt;
        &lt;!-- real people should not fill this in and expect good things - do not remove this or risk form bot signups--&gt;
        &lt;div style=&quot;position: absolute; left: -5000px;&quot; aria-hidden=&quot;true&quot;&gt;&lt;input type=&quot;text&quot; name=&quot;b_b1c1099bf7f49b95c64107c99_6a5eb68eb7&quot; tabindex=&quot;-1&quot; value=&quot;&quot; /&gt;&lt;/div&gt;
        &lt;div class=&quot;clear&quot;&gt;&lt;input type=&quot;submit&quot; value=&quot;Subscribe&quot; name=&quot;subscribe&quot; id=&quot;mc-embedded-subscribe&quot; class=&quot;button&quot; /&gt;&lt;/div&gt;
        &lt;/div&gt;
    &lt;/form&gt;
&lt;/div&gt;

&lt;!--End mc_embed_signup--&gt;

&lt;h2 id=&quot;performance-results&quot;&gt;Performance results&lt;/h2&gt;

&lt;p&gt;How did it affect performance? The &lt;a href=&quot;/Making-bits-faster/&quot;&gt;last best sample run&lt;/a&gt; took &lt;strong&gt;297 seconds&lt;/strong&gt;. With divide and conquer it takes &lt;strong&gt;283 seconds&lt;/strong&gt;. This translates to:&lt;/p&gt;

&lt;div class=&quot;language-console highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;go&quot;&gt;(283 / 2199) * 182184 ~ 6,5 hours (starting from 34 hours, and 6,8 in the best run)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;So I am doing even an order of magnitude fewer operations than before and all I get is 15 seconds? Maybe if I go to leaf size of 2 it will be better? I will be doing less so it should be faster? Even more, let’s plot how execution time is dependent on leaf size&lt;/p&gt;

&lt;h3 id=&quot;leaf-size-vs-time&quot;&gt;Leaf size vs. time&lt;/h3&gt;

&lt;p&gt;Below is a table comparing leaf size to execution time (they are an average of 3 runs).&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;Size of the chunk&lt;/th&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;Execution time&lt;/th&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;St.dev&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;64&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;299 seconds&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;2.3&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;32&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;277 seconds&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;3.5&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;16&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;296 seconds&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;3.5&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;8&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;293 seconds&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;2.3&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;4&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;283 seconds&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;6.5&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;2&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;297 seconds&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;4.3&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;&lt;img src=&quot;/data/2016-12-22-Dividing-a-bit-in-two-for-performance/LeafSizevsTime.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;making-sense-of-it-all&quot;&gt;Making sense of it all&lt;/h2&gt;

&lt;p&gt;Why did my execution time not go down as expected? Couple reasons:&lt;/p&gt;

&lt;h2 id=&quot;things-changed&quot;&gt;Things changed&lt;/h2&gt;

&lt;p&gt;I’ve started from 968 seconds for the test run, and most of this time was spend in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Similarity&lt;/code&gt;. Now if I look at the profiler:
&lt;img src=&quot;/data/2016-12-22-Dividing-a-bit-in-two-for-performance/Profiler.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Similarity&lt;/code&gt; is still using the most CPU, but it is not the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GetNonZeroIndexes&lt;/code&gt; that is the hogger. I’m just slowly getting closer and closer to the minimum execution time.&lt;/p&gt;

&lt;h2 id=&quot;why-leaf-size-of-2-is-slower-than-leaf-size-of-4&quot;&gt;Why leaf size of 2 is slower than leaf size of 4?&lt;/h2&gt;

&lt;p&gt;Execution in current processors in not linear. They execute instructions in advance hoping that they will guess the flow. When they are right it is very fast, when it is a miss performance suffers greatly. It is called &lt;a href=&quot;https://en.wikipedia.org/wiki/Branch_predictor&quot;&gt;branch prediction&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This situation leads to the fact that &lt;a href=&quot;http://stackoverflow.com/questions/11227809/why-is-it-faster-to-process-a-sorted-array-than-an-unsorted-array&quot;&gt;sorting and then processing the array may be faster then just processing&lt;/a&gt;, or &lt;a href=&quot;http://aakinshin.net/en/blog/dotnet/perfex-min/&quot;&gt;calculating the minimum of two numbers is faster using bit operations then using if&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;My guess is that two and four leaf implementation suffers mostly from that.&lt;/p&gt;

&lt;style&gt;
table{
    width:300px !important;
}
&lt;/style&gt;

</description>
        <pubDate>Tue, 20 Dec 2016 00:00:00 +0100</pubDate>
        <link>https://IndexOutOfRange.com//Divide-and-conquer-bits-for-performance/</link>
        <guid isPermaLink="true">https://IndexOutOfRange.com//Divide-and-conquer-bits-for-performance/</guid>
      </item>
    
      <item>
        <title>Making bits faster</title>
        <description>&lt;img src='https://indexoutofrange.com/data/2016-12-19-Making-bits-faster/logo.jpg' /&gt;&lt;p&gt;This post was inspired by a &lt;a href=&quot;https://www.reddit.com/r/programming/comments/5i2x5r/using_bit_masks_for_highperformance_calculations/&quot;&gt;discussion on Reddit&lt;/a&gt; that followed my &lt;a href=&quot;http://indexoutofrange.com/Using-bit-operations-for-performance-optimizations/&quot;&gt;previous post&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this post, I will cover a &lt;a href=&quot;https://www.reddit.com/r/programming/comments/5i2x5r/using_bit_masks_for_highperformance_calculations/db5ujwc/&quot;&gt;suggestion&lt;/a&gt; by &lt;a href=&quot;https://www.reddit.com/user/BelowAverageITGuy&quot;&gt;BelowAverageITGuy&lt;/a&gt; that cut down the total execution time by almost one hour.
&lt;!--MORE--&gt;&lt;/p&gt;

&lt;h2 id=&quot;recap&quot;&gt;Recap&lt;/h2&gt;

&lt;p&gt;The last implementation of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GetNonZeroIndexes&lt;/code&gt; looked like this:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IList&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;nf&quot;&gt;GetNonZeroIndexes&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;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;ret&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;k&quot;&gt;for&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;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&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;_array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&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;m&quot;&gt;0L&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;// this one check saves me 64 ones&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;nf&quot;&gt;IsBitSet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;64&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&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;nf&quot;&gt;IsBitSet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&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;n&quot;&gt;ret&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;64&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;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;IsBitSet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;64&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;2&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;nf&quot;&gt;IsBitSet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;64&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;3&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;p&quot;&gt;.&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;//You get the idea&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;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;IsBitSet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;61&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;64&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;61&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;nf&quot;&gt;IsBitSet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;62&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;64&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;62&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;nf&quot;&gt;IsBitSet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;63&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;64&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;63&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;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ret&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;/div&gt;

&lt;p&gt;With &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IsBitSet&lt;/code&gt; looking like this:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;MethodImpl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MethodImplOptions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AggressiveInlining&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;IsBitSet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pos&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;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1L&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pos&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;m&quot;&gt;0&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;/div&gt;

&lt;p&gt;It is using bit operations that are very fast, so what can be done better?&lt;/p&gt;

&lt;!-- Begin MailChimp Signup Form --&gt;

&lt;link href=&quot;//cdn-images.mailchimp.com/embedcode/horizontal-slim-10_7.css&quot; rel=&quot;stylesheet&quot; type=&quot;text/css&quot; /&gt;

&lt;style type=&quot;text/css&quot;&gt;
	#mc_embed_signup{
        clear:left; 
        font:14px Helvetica,Arial,sans-serif; 
        width:100%; 
        margin-top: 40px;
        margin-bottom: 40px;
        height:100px;
    }
    #mc_embed_signup .newsletter div{
        height: 100px;
    }
    #mc_embed_signup form{
        position: relative;
        top: -90px;
    }
	/* Add your own MailChimp form style overrides in your site stylesheet or in this style block.
	   We recommend moving this block and the preceding CSS link to the HEAD of your HTML file. */
&lt;/style&gt;

&lt;div id=&quot;mc_embed_signup&quot;&gt;
    &lt;div class=&quot;gradient newsletter&quot;&gt;
        &lt;div style=&quot;background:#000000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#1C0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#380000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#550000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#710000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#8D0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#AA0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#C60000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#E20000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF3800&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF5500&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF7100&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF8D00&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFAA00&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFC600&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFE200&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFFF00&quot;&gt;&lt;/div&gt;
    &lt;/div&gt;
    &lt;form action=&quot;https://IndexOutOfRange.us15.list-manage.com/subscribe/post?u=b1c1099bf7f49b95c64107c99&amp;amp;id=6a5eb68eb7&quot; method=&quot;post&quot; id=&quot;mc-embedded-subscribe-form&quot; name=&quot;mc-embedded-subscribe-form&quot; class=&quot;validate&quot; target=&quot;_blank&quot; novalidate=&quot;&quot;&gt;
        &lt;div id=&quot;mc_embed_signup_scroll&quot;&gt;
        &lt;label for=&quot;mce-EMAIL&quot; style=&quot;color: white;&quot;&gt;Get email notifications about new posts:&lt;/label&gt;
        &lt;input type=&quot;email&quot; value=&quot;&quot; name=&quot;EMAIL&quot; class=&quot;email&quot; id=&quot;mce-EMAIL&quot; placeholder=&quot;email address&quot; required=&quot;&quot; /&gt;
        &lt;!-- real people should not fill this in and expect good things - do not remove this or risk form bot signups--&gt;
        &lt;div style=&quot;position: absolute; left: -5000px;&quot; aria-hidden=&quot;true&quot;&gt;&lt;input type=&quot;text&quot; name=&quot;b_b1c1099bf7f49b95c64107c99_6a5eb68eb7&quot; tabindex=&quot;-1&quot; value=&quot;&quot; /&gt;&lt;/div&gt;
        &lt;div class=&quot;clear&quot;&gt;&lt;input type=&quot;submit&quot; value=&quot;Subscribe&quot; name=&quot;subscribe&quot; id=&quot;mc-embedded-subscribe&quot; class=&quot;button&quot; /&gt;&lt;/div&gt;
        &lt;/div&gt;
    &lt;/form&gt;
&lt;/div&gt;

&lt;!--End mc_embed_signup--&gt;

&lt;h2 id=&quot;bit-mask-precalculation&quot;&gt;Bit mask precalculation&lt;/h2&gt;

&lt;p&gt;His suggestion was to get rid of bit shifting and have the mask ready. This way I will get rid of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IsBitSet&lt;/code&gt; and end up with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GetNonZeroIndexes&lt;/code&gt; looking like this:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;        &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IList&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;nf&quot;&gt;GetNonZeroIndexes&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;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;ret&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;k&quot;&gt;for&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;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&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;a&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&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;a&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0U&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;L&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;a&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1U&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;L&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;m&quot;&gt;0U&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;64&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&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;a&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;2U&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;L&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;m&quot;&gt;0U&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;64&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;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;4U&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;L&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;m&quot;&gt;0U&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;64&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;2&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;a&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;8U&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;L&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;m&quot;&gt;0U&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;64&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;3&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;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;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1152921504606846976U&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;L&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;m&quot;&gt;0U&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;64&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;60&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;a&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;2305843009213693952U&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;L&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;m&quot;&gt;0U&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;64&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;61&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;a&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;4611686018427387904U&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;L&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;m&quot;&gt;0U&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;64&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;62&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;a&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;9223372036854775808U&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;L&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;m&quot;&gt;0U&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;64&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;63&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;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ret&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;/div&gt;

&lt;h2 id=&quot;excel&quot;&gt;Excel&lt;/h2&gt;

&lt;p&gt;I generate this code in Excel and after generating all the if statemenent the program started to crash. i wonder if You can spot the error:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;Power of 2&lt;/th&gt;
      &lt;th style=&quot;text-align: right&quot;&gt;Value&lt;/th&gt;
      &lt;th&gt; &lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;49&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;140 737 488 355 328&lt;/td&gt;
      &lt;td&gt; &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;50&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;281 474 976 710 656&lt;/td&gt;
      &lt;td&gt; &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;51&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;562 949 953 421 312&lt;/td&gt;
      &lt;td&gt; &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;52&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;1 125 899 906 842 620&lt;/td&gt;
      &lt;td&gt; &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;53&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;2 251 799 813 685 250&lt;/td&gt;
      &lt;td&gt; &lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;See it?&lt;br /&gt;
I’ve hit Excel (and Google docs for that matter) precision and in the 52th power of 2, it was rounded in a strange way. So instead of getting &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1 125 899 906 842 624&lt;/code&gt; I’ve got &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1 125 899 906 842 620&lt;/code&gt; :| There goes two hours lost on debugging the applications.&lt;/p&gt;

&lt;h2 id=&quot;results&quot;&gt;Results&lt;/h2&gt;

&lt;p&gt;How did it impact performance? It allowed the sample execution time to go down to 308.22 seconds. For all recipes I  get:&lt;/p&gt;

&lt;div class=&quot;language-console highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;go&quot;&gt;(297 / 2199) * 182184 ~ 6,8 hours (starting from 34 hours)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This shaved off almost 1 hour(!) from the best time. It also shows that even things as fast as bit shifts can be made faster.&lt;/p&gt;

&lt;style&gt;
table{
    width:300px !important;
}
&lt;/style&gt;

</description>
        <pubDate>Mon, 19 Dec 2016 00:00:00 +0100</pubDate>
        <link>https://IndexOutOfRange.com//Making-bits-faster/</link>
        <guid isPermaLink="true">https://IndexOutOfRange.com//Making-bits-faster/</guid>
      </item>
    
      <item>
        <title>Using bit masks for high-performance calculations</title>
        <description>&lt;img src='https://indexoutofrange.com/data/2016-12-13-Using-bit-masks-for-high-performance-calculations/logo.jpg' /&gt;&lt;p&gt;&lt;a href=&quot;/How-to-calculate-17-billion-similarities/&quot;&gt;Last time&lt;/a&gt; I’ve shown how I’ve gone from 34 hours to 11. 
This time we go faster. To go faster I have to do less.&lt;/p&gt;

&lt;p&gt;The current implementation of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Similarity&lt;/code&gt; iterates over one vector and checks if that ingredient exists in the second one. Since those vectors are sparse the chance of a miss is big. This means that I am losing computational power on iterating and calling &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TryGetValue&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;How to iterate only over the mutually owned ones and do it fast? 
&lt;!--MORE--&gt;&lt;/p&gt;

&lt;h2 id=&quot;bit-masks&quot;&gt;Bit masks&lt;/h2&gt;

&lt;p&gt;The fastest and least memory consuming way is to use an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;int&lt;/code&gt; or a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;long&lt;/code&gt; and set their bits individually. There is one problem with this. I need a mask for 1800 values, so my number would have to be 1800 bit… 
But before I go further why not use an array of bools? The memory overhead would be minimal (~1MB), but the cost of iterating would be significant. Don’t trust me? Keep on reading :)&lt;/p&gt;

&lt;h3 id=&quot;nets-bitarray&quot;&gt;.NET’s BitArray&lt;/h3&gt;

&lt;p&gt;Luckily .NET has &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BitArray&lt;/code&gt; class and it implements the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AND&lt;/code&gt; operation, so let’s give it a try:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Similarity&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IngredientWeightsVector&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;otherVector&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;andMask&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_ingredientMask&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;And&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;otherVector&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IngredientMask&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;//find only the commonly found ingredients &lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nonZeros&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;GetNonZeroIndexes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;andMask&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// get the indexes of the ingredients&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;num&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nonZeros&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Sum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;otherVector&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IngredientWeights&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IngredientWeights&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t&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;denom&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;otherVector&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Length&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;num&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;denom&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;private&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;nf&quot;&gt;GetNonZeroIndexes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BitArray&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ba&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;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;ret&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;m&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&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;bool&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ba&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;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;index&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;ret&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;/div&gt;

&lt;p&gt;Lets walk through what is happening here.&lt;br /&gt;
I calculate the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AND&lt;/code&gt; between the masks of both vectors. This gives me the mask of ingredients present in both recipes. Then, since I need the weights for those ingredients, I iterate over the mask and find indexes (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GetNonZeroIndexes&lt;/code&gt; takes care of it). With them, I can get the weights from both recipes vectors. Having those weights I can finally calculate the &lt;a href=&quot;http://indexoutofrange.com/How_I_calculate_similarities_in_cookit/&quot;&gt;dot product&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The code is ready, so let’s fire it up!&lt;/p&gt;

&lt;p&gt;Sadly I won’t give you the numbers because I’ve decided to terminate the calculation when it passed the point when it became clear that it will be way slower than the first &lt;a href=&quot;/How_I_calculate_similarities_in_cookit&quot;&gt;implementation&lt;/a&gt;. So let’s fire up the profiler and see what is happening:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/data/2016-12-13-Using-bit-masks-for-high-performance-calculations/Profiler1.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;As I saw earlier when optimizing this problem - iteration is not something free :( &lt;br /&gt;
Maybe it’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;foreach&lt;/code&gt; fault and a simple &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;for&lt;/code&gt; will be OK? Let’s check:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/data/2016-12-13-Using-bit-masks-for-high-performance-calculations/Profiler2.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Get&lt;/code&gt; is the function called on the indexer. So is this a dead end? Before taking this decision lets look at the code of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Get&lt;/code&gt; in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BitArray&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;index&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;index&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Length&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;throw&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ArgumentOutOfRangeException&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;nameof&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ArgumentOutOfRange_Index&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;Contract&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;EndContractBlock&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;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m_array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;amp;&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;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;32&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;m&quot;&gt;0&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;/div&gt;

&lt;p&gt;What can I improve there?&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;remove the ifs at the start, because I like my performance unchecked ;)&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BitArray&lt;/code&gt; is using array of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;int&lt;/code&gt; as storage and I think using a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;long&lt;/code&gt; be a bit faster&lt;/li&gt;
&lt;/ul&gt;

&lt;!-- Begin MailChimp Signup Form --&gt;

&lt;link href=&quot;//cdn-images.mailchimp.com/embedcode/horizontal-slim-10_7.css&quot; rel=&quot;stylesheet&quot; type=&quot;text/css&quot; /&gt;

&lt;style type=&quot;text/css&quot;&gt;
	#mc_embed_signup{
        clear:left; 
        font:14px Helvetica,Arial,sans-serif; 
        width:100%; 
        margin-top: 40px;
        margin-bottom: 40px;
        height:100px;
    }
    #mc_embed_signup .newsletter div{
        height: 100px;
    }
    #mc_embed_signup form{
        position: relative;
        top: -90px;
    }
	/* Add your own MailChimp form style overrides in your site stylesheet or in this style block.
	   We recommend moving this block and the preceding CSS link to the HEAD of your HTML file. */
&lt;/style&gt;

&lt;div id=&quot;mc_embed_signup&quot;&gt;
    &lt;div class=&quot;gradient newsletter&quot;&gt;
        &lt;div style=&quot;background:#000000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#1C0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#380000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#550000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#710000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#8D0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#AA0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#C60000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#E20000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF3800&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF5500&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF7100&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF8D00&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFAA00&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFC600&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFE200&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFFF00&quot;&gt;&lt;/div&gt;
    &lt;/div&gt;
    &lt;form action=&quot;https://IndexOutOfRange.us15.list-manage.com/subscribe/post?u=b1c1099bf7f49b95c64107c99&amp;amp;id=6a5eb68eb7&quot; method=&quot;post&quot; id=&quot;mc-embedded-subscribe-form&quot; name=&quot;mc-embedded-subscribe-form&quot; class=&quot;validate&quot; target=&quot;_blank&quot; novalidate=&quot;&quot;&gt;
        &lt;div id=&quot;mc_embed_signup_scroll&quot;&gt;
        &lt;label for=&quot;mce-EMAIL&quot; style=&quot;color: white;&quot;&gt;Get email notifications about new posts:&lt;/label&gt;
        &lt;input type=&quot;email&quot; value=&quot;&quot; name=&quot;EMAIL&quot; class=&quot;email&quot; id=&quot;mce-EMAIL&quot; placeholder=&quot;email address&quot; required=&quot;&quot; /&gt;
        &lt;!-- real people should not fill this in and expect good things - do not remove this or risk form bot signups--&gt;
        &lt;div style=&quot;position: absolute; left: -5000px;&quot; aria-hidden=&quot;true&quot;&gt;&lt;input type=&quot;text&quot; name=&quot;b_b1c1099bf7f49b95c64107c99_6a5eb68eb7&quot; tabindex=&quot;-1&quot; value=&quot;&quot; /&gt;&lt;/div&gt;
        &lt;div class=&quot;clear&quot;&gt;&lt;input type=&quot;submit&quot; value=&quot;Subscribe&quot; name=&quot;subscribe&quot; id=&quot;mc-embedded-subscribe&quot; class=&quot;button&quot; /&gt;&lt;/div&gt;
        &lt;/div&gt;
    &lt;/form&gt;
&lt;/div&gt;

&lt;!--End mc_embed_signup--&gt;

&lt;h3 id=&quot;custom-bitarray-implementation&quot;&gt;Custom BitArray implementation&lt;/h3&gt;

&lt;p&gt;Lets try with a custom implementation:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;System.Collections&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;System.Collections.Generic&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;System.Runtime.CompilerServices&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Cookit.Utils.Lib.CSharp.RecipeSimilaritiesCalculator&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;MyBitArray&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;readonly&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_array&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;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Length&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;MyBitArray&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;size&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;Length&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;size&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;numberOfLongs&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;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Math&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Ceiling&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(((&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)/&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;_array&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;kt&quot;&gt;long&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;numberOfLongs&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;nf&quot;&gt;MethodImpl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MethodImplOptions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AggressiveInlining&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;CalcIndex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;index&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;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;longIndex&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;kt&quot;&gt;long&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;masc&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;longIndex&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;GetLongIndex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&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;rest&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;longIndex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;masc&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;GetMask&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;true&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;nf&quot;&gt;MethodImpl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MethodImplOptions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AggressiveInlining&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;GetLongIndex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;index&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;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;64&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;nf&quot;&gt;MethodImpl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MethodImplOptions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AggressiveInlining&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;internal&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;GetMask&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bitnum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;val&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;val&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;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1L&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bitnum&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;p&quot;&gt;~(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1L&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bitnum&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;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;k&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;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;longIndex&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;longMasc&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;nf&quot;&gt;CalcIndex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&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;longIndex&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;longMasc&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;currentValue&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;longIndex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;currentValue&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;currentValue&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;longMasc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;_array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;longIndex&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;currentValue&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;BitVectorMask&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;And&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BitVectorMask&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;other&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;ret&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;nf&quot;&gt;BitVectorMask&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;other&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;for&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;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&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;ret&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&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;_array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;other&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&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;ret&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;IList&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;nf&quot;&gt;GetNonZeroIndexes&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;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;ret&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;k&quot;&gt;for&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;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&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;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&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;nf&quot;&gt;IsBitSet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
                        &lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;64&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&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;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ret&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;nf&quot;&gt;MethodImpl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MethodImplOptions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AggressiveInlining&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;IsBitSet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pos&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;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1L&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pos&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;m&quot;&gt;0&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;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Test run for the sample took 2509 sec, so the full run will take:&lt;/p&gt;

&lt;div class=&quot;language-console highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;go&quot;&gt;(2509 / 2199) * 182184 ~ 57,7 hours (starting from 34 hours)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;table&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;So I am getting slower :&lt;/td&gt;
      &lt;td&gt;Why was it so slow? Hopefully, dotTrace will tell the truth:&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;&lt;img src=&quot;/data/2016-12-13-Using-bit-masks-for-high-performance-calculations/Profiler3.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;If we look at the profiler result &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GetNonZeroIndexes&lt;/code&gt; is the most expensive function, but there is almost nothing in it to blame. The time is hidden in native functions such as iterating, multiplication and soo on, and I am doing a lot of them here. How to simplify?&lt;/p&gt;

&lt;h2 id=&quot;loop-unwinding&quot;&gt;Loop unwinding&lt;/h2&gt;

&lt;p&gt;The concept is: Why to waste time on looping when I can unwind the code. Will it make that of a difference? Let’s see:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IList&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;nf&quot;&gt;GetNonZeroIndexes&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;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;ret&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;k&quot;&gt;for&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;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&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;_array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&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;m&quot;&gt;0L&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;// this one check saves me 64 ones&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;nf&quot;&gt;IsBitSet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;64&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&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;nf&quot;&gt;IsBitSet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&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;n&quot;&gt;ret&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;64&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;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;IsBitSet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;64&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;2&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;nf&quot;&gt;IsBitSet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;64&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;3&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;c1&quot;&gt;//You get the idea&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;nf&quot;&gt;IsBitSet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;61&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;64&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;61&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;nf&quot;&gt;IsBitSet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;62&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;64&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;62&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;nf&quot;&gt;IsBitSet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;63&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;64&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;63&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;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ret&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;/div&gt;

&lt;p&gt;This brings down the sample time to &lt;strong&gt;395 seconds&lt;/strong&gt; and the total time:&lt;/p&gt;

&lt;div class=&quot;language-console highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;go&quot;&gt;(395 / 2199) * 182184 ~ 9 hours (starting from 34 hours)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;For the first time in this post it is faster than the best time from the &lt;a href=&quot;/How-to-calculate-17-billion-similarities/&quot;&gt;previous post&lt;/a&gt; (484 seconds).&lt;/p&gt;

&lt;p&gt;But it still can go faster. A reminder here is how &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Similarity&lt;/code&gt; looks like:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Similarity&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IngredientWeightsVector&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;otherVector&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;andMask&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_ingredientMask&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;And&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;otherVector&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_ingredientMask&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;num&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&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;nonZeros&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;andMask&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetNonZeroIndexes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&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;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nonZeros&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&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;num&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;otherVector&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IngredientWeights&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;nonZeros&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&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;IngredientWeights&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;nonZeros&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&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;denom&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;otherVector&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Length&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;num&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;denom&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;/div&gt;

&lt;p&gt;What else can be optimized?&lt;/p&gt;

&lt;h3 id=&quot;exit-early&quot;&gt;Exit early&lt;/h3&gt;

&lt;p&gt;If the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;andMask&lt;/code&gt; doesn’t contain any ones I am still doing some calculations, allocations and so on. Granted, not much but still. A simple check in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BitVectorMask&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;IsZero&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;for&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;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&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;_array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&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;m&quot;&gt;0L&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;k&quot;&gt;false&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;k&quot;&gt;true&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;/div&gt;

&lt;p&gt;and a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;if&lt;/code&gt; in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Similarity&lt;/code&gt; function:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Similarity&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IngredientWeightsVector&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;otherVector&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;andMask&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_ingredientMask&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;And&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;otherVector&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_ingredientMask&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;andMask&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;IsZero&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;//this was added&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;num&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&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;nonZeros&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;andMask&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetNonZeroIndexes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&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;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nonZeros&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&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;num&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;otherVector&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IngredientWeights&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;nonZeros&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&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;IngredientWeights&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;nonZeros&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&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;denom&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;otherVector&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Length&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;num&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;denom&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;/div&gt;

&lt;p&gt;With those modifications the sample run finished in &lt;strong&gt;334 seconds&lt;/strong&gt;. 
This gives:&lt;/p&gt;

&lt;div class=&quot;language-console highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;go&quot;&gt;(334 / 2199) * 182184 ~ 7,6 hours (starting from 34 hours)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Can it still be improved significantly or am I looking at marginal gains here? This problem can still astound you, but this will be unveiled next week.&lt;/p&gt;

&lt;h3 id=&quot;update&quot;&gt;Update&lt;/h3&gt;

&lt;p&gt;This post &lt;a href=&quot;https://www.reddit.com/r/programming/comments/5i2x5r/using_bit_masks_for_highperformance_calculations/&quot;&gt;sprung a very interesting conversation on Reddit&lt;/a&gt; with 104 comments as of writing this update.&lt;/p&gt;
</description>
        <pubDate>Tue, 13 Dec 2016 00:00:00 +0100</pubDate>
        <link>https://IndexOutOfRange.com//Using-bit-operations-for-performance-optimizations/</link>
        <guid isPermaLink="true">https://IndexOutOfRange.com//Using-bit-operations-for-performance-optimizations/</guid>
      </item>
    
      <item>
        <title>Independent code in performance optimizations</title>
        <description>&lt;img src='https://indexoutofrange.com/data/2016-12-12-Independent-code-in-performance-optimizations/logo.jpg' /&gt;&lt;p&gt;This will be a fast errata to the &lt;a href=&quot;/How-to-calculate-17-billion-similarities/&quot;&gt;previous one&lt;/a&gt;. This time I will expand the oldest performance mantra:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;The fastest code is the one that doesn’t execute. Second to that is the one that executes once&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Last time I’ve forgot to mention one very important optimization. It was one of two steps that allowed me to go &lt;a href=&quot;/How-to-calculate-17-billion-similarities/&quot;&gt;from 1530 to 484 seconds&lt;/a&gt; in the sample run.&lt;/p&gt;

&lt;!--MORE--&gt;

&lt;p&gt;Let’s look once more at the code:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Similarity&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IDictionary&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;,&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;otherVector&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;num&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;nf&quot;&gt;Sum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ingredient&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;float&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&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;otherVector&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;TryGetValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ingredient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Key&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;k&quot;&gt;value&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;ingredient&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;k&quot;&gt;value&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;m&quot;&gt;0&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;denom&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Lengh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;otherVector&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Length&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;num&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;denom&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;/div&gt;
&lt;p&gt;and Length looking like this:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Vector&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&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;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Math&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Sqrt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Sum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;k&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Similarity&lt;/code&gt; will be called for every pair of recipes and that means a lot:&lt;/p&gt;

&lt;div class=&quot;language-console highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;go&quot;&gt;(182184*182184)/2 = 16 595 504 928 times 
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;But there is one fragment that doesn’t change depending on input parameters, so it means i can calculate it less often.&lt;br /&gt;
Can You spot it?&lt;/p&gt;

&lt;p&gt;It’s Length.&lt;/p&gt;

&lt;p&gt;Changing it’s code to this:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Length&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;_wasIngredientWeightsChanged&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;_len&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;float&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Math&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Sqrt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_ingredientWeightsInternal&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;nf&quot;&gt;Sum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;_wasIngredientWeightsChanged&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;false&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;_len&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;/div&gt;

&lt;p&gt;Allowed me to go from 968 seconds to 745 seconds for the sample. Scaling it to all recipes gives:&lt;/p&gt;

&lt;div class=&quot;language-console highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;go&quot;&gt;(745 / 2199) * 182184 ~ 17 hours (starting from 34 hours)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;conslusion&quot;&gt;Conslusion&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;“Can I make it faster”&lt;/em&gt; is not the only question to ask when optimizing. Sometimes asking &lt;em&gt;“does it have to execute this often?”&lt;/em&gt; is also a very valid question.&lt;/p&gt;
</description>
        <pubDate>Mon, 12 Dec 2016 00:00:00 +0100</pubDate>
        <link>https://IndexOutOfRange.com//Independent-code-in-performance-optimizations/</link>
        <guid isPermaLink="true">https://IndexOutOfRange.com//Independent-code-in-performance-optimizations/</guid>
      </item>
    
      <item>
        <title>How to calculate 17 billion similarities</title>
        <description>&lt;img src='https://indexoutofrange.com/data/2016-12-05-How-to-calculate-17-billion-similarities/logo.jpg' /&gt;&lt;p&gt;The &lt;a href=&quot;/How_I_calculate_similarities_in_cookit/&quot;&gt;previous post&lt;/a&gt; described the methodology I’ve used to calculate similarities between recipes in &lt;a href=&quot;http://cookit.pl&quot;&gt;cookit&lt;/a&gt;. If you haven’t read it I’ll give it 4 minutes because it will make understanding this post easier. Go one, I’ll wait.&lt;/p&gt;

&lt;p&gt;It ended on a happy note and everything seemed to be downhill from there on. It was until I tried to run it. It took long. Very long. How long? I don’t know because I’ve canceled it after about one hour. Going with a famous quote (probably from Einstein, but there &lt;a href=&quot;https://www.quora.com/Did-Einstein-really-define-insanity-as-doing-the-same-thing-over-and-over-again-and-expecting-different-results&quot;&gt;are some ambiguities in this subject&lt;/a&gt;)&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Doing the same thing over and over again and expecting different results&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I’ve decided to, once again, use math to assess how long the calculation will take. &lt;br /&gt;
&lt;!--MORE--&gt;&lt;/p&gt;

&lt;h3 id=&quot;reminder---how-similarities-are-calculated&quot;&gt;Reminder - how similarities are calculated&lt;/h3&gt;

&lt;p&gt;In the &lt;a href=&quot;/How_I_calculate_similarities_in_cookit/&quot;&gt;previous post&lt;/a&gt; I’ve decided to calculate similarity by calculating the dot product between recipe ingredient vectors. In C# it will look more or less like this:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Similarity&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Vector&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Vector&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&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;float&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;accumulator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&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;accumulator&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&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;denom&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)*&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;//convertion to absolute &lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;accumulator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;denom&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;         &lt;span class=&quot;c1&quot;&gt;//convertion to absolute    &lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;    
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;where &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Length&lt;/code&gt; looks like this:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Vector&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&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;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Math&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Sqrt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Sum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;k&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;complexity&quot;&gt;Complexity&lt;/h2&gt;

&lt;p&gt;To give you some scale. Cookit currently has:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;182 184 recipes&lt;/li&gt;
  &lt;li&gt;2936 ingredients&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As a consequence of the way I model similarities, I will need to create for each recipe a 2936 dimensional array representing ingredients. There are two things I should estimate: memory and number of calculations.&lt;br /&gt;
First the memory:&lt;/p&gt;

&lt;div class=&quot;language-console highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;go&quot;&gt;182184(number of recipes) * 2936 = 534 892 224 floats 
534 892 224 * 4(the size of float) ~ 2.14 Gig counting only space needed for floats
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And if I will want to calculate the similarities for all recipes I will have to do:&lt;/p&gt;

&lt;div class=&quot;language-console highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;go&quot;&gt;((182184 * 2936)^2) /2 = 143 054 845 647 833 100 floating point multiplications
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Is it much? Yes. Is it a lot for modern processors? &lt;a href=&quot;http://ithare.com/infographics-operation-costs-in-cpu-clock-cycles/&quot;&gt;IT Hare&lt;/a&gt; had a good article about the cost of each operation in the CPU. 
One note before we go further. Those calculations will be more for fun than actual time estimates. Even as IT Hate points out, trying to calculate the actual execution time in modern CPUs is hard enough to be pointless. But here we go:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;143 054 845 647 833 100 * 5 (number of cycles for floating point operations) / 2 130 000 000 (this is what 2,13 GHz translates to - 2,13 billion operations per second)
This gives us ~ 335809496 seconds ~ 93280 hours ~ 3886 days  
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Once again it is more for fun than anything else, but it appears that, citing &lt;a href=&quot;https://en.wikipedia.org/wiki/The_Martian_(Weir_novel)&quot;&gt;Mark Watney&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;I will have to science the sh** out of it [&lt;a href=&quot;https://www.youtube.com/watch?v=d6lYeTWdYLw&quot;&gt;youtube&lt;/a&gt;]&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;assessing-total-time&quot;&gt;Assessing total time&lt;/h2&gt;

&lt;p&gt;To get a more real assessment how long will it take I’ve decided to do a test run on a small subset of recipes. Recipes are selected by selecting websites they are from, so my subset ended up being an unround 2199 recipes. Then I’ve made 3 test runs (&lt;a href=&quot;http://indexoutofrange.com/LocalOptimizationsDontAddUp/&quot;&gt;I’ve learned the hard way that one test run doesn’t mean anything&lt;/a&gt;) and in average of &lt;strong&gt;1530 seconds&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Now how to go from time of the subset to the time needed for all recipes? I can’t use it to assess the total execution time because it consists of two parts:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;calculating ingredient vector for all recipes.&lt;/li&gt;
  &lt;li&gt;finding similar recipes for only 2199 one of them. The similarity is found by calculating one vector by all the others. So in this case I’ve done&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;182184*2199 = 400 622 616 vector multiplications
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The first part is constant regardless how many similarities I will have to calculate.&lt;br /&gt;
The second part is directly proportional to the number of recipes for which I will calculate similarities.&lt;/p&gt;

&lt;p&gt;The last missing piece for assessing the time of calculation for all recipes is the proportion of those two operations. So let’s fire up the profiler (&lt;a href=&quot;https://www.jetbrains.com/profiler/&quot;&gt;dotTrace&lt;/a&gt; by choice) in sampling mode:
&lt;img src=&quot;/data/2016-12-05-How-to-calculate-17-billion-similarities/Profiler01.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Well, bummer to put it lightly. Almost all time went into calculating the dot product (named here Similarity). From this I know that I can calculate the total time as a linear function from number of recipes without making to big of an error:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;(1530 / 2199) * 182184 ~ 34 hours

where:
- 1530 - number of seconds it took
- 2199 - number of ingredients
- 182184 - number of recipes 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;So the next step will be:&lt;/p&gt;

&lt;!-- Begin MailChimp Signup Form --&gt;

&lt;link href=&quot;//cdn-images.mailchimp.com/embedcode/horizontal-slim-10_7.css&quot; rel=&quot;stylesheet&quot; type=&quot;text/css&quot; /&gt;

&lt;style type=&quot;text/css&quot;&gt;
	#mc_embed_signup{
        clear:left; 
        font:14px Helvetica,Arial,sans-serif; 
        width:100%; 
        margin-top: 40px;
        margin-bottom: 40px;
        height:100px;
    }
    #mc_embed_signup .newsletter div{
        height: 100px;
    }
    #mc_embed_signup form{
        position: relative;
        top: -90px;
    }
	/* Add your own MailChimp form style overrides in your site stylesheet or in this style block.
	   We recommend moving this block and the preceding CSS link to the HEAD of your HTML file. */
&lt;/style&gt;

&lt;div id=&quot;mc_embed_signup&quot;&gt;
    &lt;div class=&quot;gradient newsletter&quot;&gt;
        &lt;div style=&quot;background:#000000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#1C0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#380000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#550000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#710000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#8D0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#AA0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#C60000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#E20000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF3800&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF5500&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF7100&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF8D00&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFAA00&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFC600&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFE200&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFFF00&quot;&gt;&lt;/div&gt;
    &lt;/div&gt;
    &lt;form action=&quot;https://IndexOutOfRange.us15.list-manage.com/subscribe/post?u=b1c1099bf7f49b95c64107c99&amp;amp;id=6a5eb68eb7&quot; method=&quot;post&quot; id=&quot;mc-embedded-subscribe-form&quot; name=&quot;mc-embedded-subscribe-form&quot; class=&quot;validate&quot; target=&quot;_blank&quot; novalidate=&quot;&quot;&gt;
        &lt;div id=&quot;mc_embed_signup_scroll&quot;&gt;
        &lt;label for=&quot;mce-EMAIL&quot; style=&quot;color: white;&quot;&gt;Get email notifications about new posts:&lt;/label&gt;
        &lt;input type=&quot;email&quot; value=&quot;&quot; name=&quot;EMAIL&quot; class=&quot;email&quot; id=&quot;mce-EMAIL&quot; placeholder=&quot;email address&quot; required=&quot;&quot; /&gt;
        &lt;!-- real people should not fill this in and expect good things - do not remove this or risk form bot signups--&gt;
        &lt;div style=&quot;position: absolute; left: -5000px;&quot; aria-hidden=&quot;true&quot;&gt;&lt;input type=&quot;text&quot; name=&quot;b_b1c1099bf7f49b95c64107c99_6a5eb68eb7&quot; tabindex=&quot;-1&quot; value=&quot;&quot; /&gt;&lt;/div&gt;
        &lt;div class=&quot;clear&quot;&gt;&lt;input type=&quot;submit&quot; value=&quot;Subscribe&quot; name=&quot;subscribe&quot; id=&quot;mc-embedded-subscribe&quot; class=&quot;button&quot; /&gt;&lt;/div&gt;
        &lt;/div&gt;
    &lt;/form&gt;
&lt;/div&gt;

&lt;!--End mc_embed_signup--&gt;

&lt;h2 id=&quot;optimising&quot;&gt;Optimising&lt;/h2&gt;

&lt;h3 id=&quot;less-means-faster&quot;&gt;Less means faster&lt;/h3&gt;

&lt;blockquote&gt;
  &lt;p&gt;The fastest code is the code that never runs&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Following this mantra I removed the ingredients that are not used in any recipe.&lt;/p&gt;

&lt;p&gt;This reduced the length of the vector to 1709 and the sample time be a whopping 562 seconds to 968 seconds.
With some simple math:&lt;/p&gt;

&lt;div class=&quot;language-console highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;go&quot;&gt;(968 / 2199) * 182184 ~ 22,3 hours (starting from 34 hours)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This is a &lt;strong&gt;34% improvement&lt;/strong&gt;. Nice :)&lt;/p&gt;

&lt;p&gt;So case closed? No. I believe I can do better. To have an idea let’s have a look with a profiler:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/data/2016-12-05-How-to-calculate-17-billion-similarities/Profiler02.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;There did all the time go? Let’s have a look at another view:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/data/2016-12-05-How-to-calculate-17-billion-similarities/Profiler03.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;This shows that most of the time went into native code meaning in my case multiplying floats and iterating over the array. This means that this idea is a dead end. Let’s change the angle and use domain knowledge to optimize a bit more.&lt;/p&gt;

&lt;h3 id=&quot;using-domain-knowledge-for-optimization&quot;&gt;Using domain knowledge for optimization&lt;/h3&gt;

&lt;p&gt;I know that vectors are very &lt;a href=&quot;https://en.wikipedia.org/wiki/Sparse_array&quot;&gt;sparse&lt;/a&gt;. In average one recipe has ~150 non-zero values in an almost 2.2k long array. This means I am wasting time multiplying zero. Let’s remove them.&lt;/p&gt;

&lt;h3 id=&quot;use-a-dictionary&quot;&gt;Use a dictionary&lt;/h3&gt;

&lt;p&gt;Instead of using an array I will use a dictionary. The idea behind this take is this:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;it will allow me to store only those ingredients that the recipe has. This way the vector will shrink by an order of magnitude and as a side effect I will also shrink memory usage (although not that much since dictionary in .NET is a memory heavy structure)&lt;/li&gt;
  &lt;li&gt;since I shrunk the vector I don’t need to enumerate over all the ingredients, but only over those from one of the vectors&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So let’s put it into code:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Similarity&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IDictionary&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;,&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;otherVector&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;num&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;nf&quot;&gt;Sum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ingredient&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;float&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&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;otherVector&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;TryGetValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ingredient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Key&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;k&quot;&gt;value&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;ingredient&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;k&quot;&gt;value&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;m&quot;&gt;0&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;denom&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;otherVector&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Length&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;num&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;denom&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;/div&gt;
&lt;p&gt;With this change the calculation took 484 seconds. Scaling it to the full data set I get:&lt;/p&gt;

&lt;div class=&quot;language-console highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;go&quot;&gt;(484 / 2199) * 182184 ~ 11 hours (starting from 34 hours)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This means a &lt;strong&gt;67% improvement&lt;/strong&gt; over the starting value. So case closed? No. But this will be the topic for the next post since this one is getting to long.&lt;/p&gt;
</description>
        <pubDate>Mon, 05 Dec 2016 00:00:00 +0100</pubDate>
        <link>https://IndexOutOfRange.com//How-to-calculate-17-billion-similarities/</link>
        <guid isPermaLink="true">https://IndexOutOfRange.com//How-to-calculate-17-billion-similarities/</guid>
      </item>
    
      <item>
        <title>How I calculate similarities in cookit?</title>
        <description>&lt;img src='https://indexoutofrange.com/data/2016-11-28-How_I_calculate_similarities_in_cookit/logo.jpg' /&gt;&lt;blockquote&gt;
  &lt;p&gt;Warning this post contains some math. Better still, it shows how to use it to solve real-life problems.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This post describes how I calculate similarity between recipes in my pet project &lt;a href=&quot;http://cookit.pl&quot;&gt;cookit.pl&lt;/a&gt;. For those not familiar with it, cookit is a search engine for recipes. It crawls websites extracting recipes, then parses them and tries to create a precise ingredient list replete with amounts and units.&lt;/p&gt;

&lt;p&gt;By the time of writing it had:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;182 184 recipes&lt;/li&gt;
  &lt;li&gt;2936 ingredients&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This scale may not seem huge, but trust me - It’s enough to bring a slew of problems to light. And that &lt;a href=&quot;http://indexoutofrange.com/The-importance-of-running-on-crapp/&quot;&gt;cookit runs on a crappy server&lt;/a&gt;, partly by choice, can make things all the more complicated.
&lt;!--MORE--&gt;&lt;/p&gt;

&lt;p&gt;Before turning to those problems, lets first answer this question:&lt;/p&gt;

&lt;h2 id=&quot;how-to-calculate-similarities&quot;&gt;How to calculate similarities?&lt;/h2&gt;

&lt;p&gt;The first question to ask is: 
    &lt;em&gt;How do you calculate similarity between two articles, recipes, objects in general ?&lt;/em&gt; 
Let’s use math! If object can be expressed as a series of ordered numbers (a vector) then there are many ways to express how two such vectors are similar to each other.&lt;/p&gt;

&lt;p&gt;So how can a recipe be expressed as a vector? My answer was: 
    &lt;em&gt;If they have similar ingredients they are similar&lt;/em&gt;
This means I have to create for each recipe, a vector of ingredients with 0 representing the lack of an ingredient and 1 its presence.&lt;/p&gt;

&lt;p&gt;Similarity between recipes can now be expressed as the number of common ingredients (do an AND operation and count all the ones). So, case closed, right? Well, not exactly. This design has some problems.&lt;/p&gt;

&lt;h2 id=&quot;building-a-similarities-vector&quot;&gt;Building a similarities vector&lt;/h2&gt;

&lt;p&gt;Let’s consider some cases where the initial idea will be too much of a simplification.&lt;/p&gt;

&lt;h3 id=&quot;taking-similarity-into-account&quot;&gt;Taking similarity into account&lt;/h3&gt;

&lt;p&gt;Let’s take two recipes, one containing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sea salt&lt;/code&gt; and the other &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;salt&lt;/code&gt;. In a boolean representation, the similarity between them would be equal  to zero. But they are actually similar, and can often be used interchangeably. So they are not the same but, they are similar. Now how to represent that?&lt;/p&gt;

&lt;p&gt;I can take the advantage of the fact that all ingredients in cookit are organized in a graph. Where the child is more specific than the parent. For example, in this case, I have:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Spices -&amp;gt; solid spices -&amp;gt; mineral spices -&amp;gt; salt -&amp;gt; sea salt&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;We can use this knowledge to work and put all the parents and children into the vector as owned ingredients. The problem is, I then lose the significance of the actual ingredient used (meaning that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sea salt&lt;/code&gt; for this recipe is ideal, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;salt&lt;/code&gt; is just OK). The best way would be to use weights on how accurate the ingredient is for this recipe. So my vector will look like this:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th style=&quot;text-align: left&quot;&gt; &lt;/th&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;Spices&lt;/th&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;Solid spices&lt;/th&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;Mineral spices&lt;/th&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;Salt&lt;/th&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;Sea salt&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Recipe with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;salt&lt;/code&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;(1*y)*y&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;(1*y)*y&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;(1*y)&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;1&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;(1*x)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Recipe with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;salt&lt;/code&gt;(numbers)&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;0.512&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;0.64&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;0.8&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;1&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;0.9&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Recipe with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sea salt&lt;/code&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;((1*y)*y)*y&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;((1*y)*y)*y&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;(1*y)*y&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;1*y&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;1&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Recipe with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sea salt&lt;/code&gt;(numbers)&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;0.4096&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;0.512&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;0.64&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;0.8&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;1&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;where:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;x is in the range of 0-1 and is the penalty for being further away for children&lt;/li&gt;
  &lt;li&gt;y is in the range of 0-1 and is the penalty for being further away for parents&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;adding-importance&quot;&gt;Adding importance&lt;/h3&gt;

&lt;p&gt;Let’s take &lt;em&gt;scrambled eggs&lt;/em&gt; made from these ingredients:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eggs&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;salt&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pepper&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And now a &lt;em&gt;steak&lt;/em&gt; made from these:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;meat&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;salt&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pepper&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The current model would have us believe that those dishes are, at roghly in 66% similar. This is because every ingredient is given the same importance. The question now becomes, how do I calculate an ingredient’s importance? Easily, using the same idea Lucene did - the &lt;a href=&quot;https://en.wikipedia.org/wiki/Inverted_index&quot;&gt;inverted index&lt;/a&gt;:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Sum of recipes having ingredient x / Sum of all ingredients in all recipes
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Because &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;salt&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pepper&lt;/code&gt; are very popular ingredients, their weight will be very small. Because &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Meat&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eggs&lt;/code&gt; are less popular, they will have a higher weight. This approach has the neat feature that it is &lt;a href=&quot;https://en.wikipedia.org/wiki/Normalization_(statistics)&quot;&gt;normalized&lt;/a&gt; in zero to one range.&lt;/p&gt;

&lt;p&gt;So, for now, the model looks good.&lt;/p&gt;

&lt;!-- Begin MailChimp Signup Form --&gt;

&lt;link href=&quot;//cdn-images.mailchimp.com/embedcode/horizontal-slim-10_7.css&quot; rel=&quot;stylesheet&quot; type=&quot;text/css&quot; /&gt;

&lt;style type=&quot;text/css&quot;&gt;
	#mc_embed_signup{
        clear:left; 
        font:14px Helvetica,Arial,sans-serif; 
        width:100%; 
        margin-top: 40px;
        margin-bottom: 40px;
        height:100px;
    }
    #mc_embed_signup .newsletter div{
        height: 100px;
    }
    #mc_embed_signup form{
        position: relative;
        top: -90px;
    }
	/* Add your own MailChimp form style overrides in your site stylesheet or in this style block.
	   We recommend moving this block and the preceding CSS link to the HEAD of your HTML file. */
&lt;/style&gt;

&lt;div id=&quot;mc_embed_signup&quot;&gt;
    &lt;div class=&quot;gradient newsletter&quot;&gt;
        &lt;div style=&quot;background:#000000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#1C0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#380000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#550000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#710000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#8D0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#AA0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#C60000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#E20000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF3800&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF5500&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF7100&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF8D00&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFAA00&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFC600&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFE200&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFFF00&quot;&gt;&lt;/div&gt;
    &lt;/div&gt;
    &lt;form action=&quot;https://IndexOutOfRange.us15.list-manage.com/subscribe/post?u=b1c1099bf7f49b95c64107c99&amp;amp;id=6a5eb68eb7&quot; method=&quot;post&quot; id=&quot;mc-embedded-subscribe-form&quot; name=&quot;mc-embedded-subscribe-form&quot; class=&quot;validate&quot; target=&quot;_blank&quot; novalidate=&quot;&quot;&gt;
        &lt;div id=&quot;mc_embed_signup_scroll&quot;&gt;
        &lt;label for=&quot;mce-EMAIL&quot; style=&quot;color: white;&quot;&gt;Get email notifications about new posts:&lt;/label&gt;
        &lt;input type=&quot;email&quot; value=&quot;&quot; name=&quot;EMAIL&quot; class=&quot;email&quot; id=&quot;mce-EMAIL&quot; placeholder=&quot;email address&quot; required=&quot;&quot; /&gt;
        &lt;!-- real people should not fill this in and expect good things - do not remove this or risk form bot signups--&gt;
        &lt;div style=&quot;position: absolute; left: -5000px;&quot; aria-hidden=&quot;true&quot;&gt;&lt;input type=&quot;text&quot; name=&quot;b_b1c1099bf7f49b95c64107c99_6a5eb68eb7&quot; tabindex=&quot;-1&quot; value=&quot;&quot; /&gt;&lt;/div&gt;
        &lt;div class=&quot;clear&quot;&gt;&lt;input type=&quot;submit&quot; value=&quot;Subscribe&quot; name=&quot;subscribe&quot; id=&quot;mc-embedded-subscribe&quot; class=&quot;button&quot; /&gt;&lt;/div&gt;
        &lt;/div&gt;
    &lt;/form&gt;
&lt;/div&gt;

&lt;!--End mc_embed_signup--&gt;

&lt;h2 id=&quot;calculating-the-vector&quot;&gt;Calculating the vector&lt;/h2&gt;

&lt;p&gt;Let’s transfer all this knowledge into code:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vector&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;kt&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NUMBER_OF_ALL_INGREDIENTS&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;ingredient&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;recipe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Ingredients&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;){&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;SetIngredientWeight&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ingredient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vector&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;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;SetIngredientWeight&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Ingredient&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ing&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vector&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;weight&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;){&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;vector&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ing&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;weight&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;//set the weight for the current ingredient&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;parent&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ing&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Parents&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;nf&quot;&gt;SetIngredientWeight&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vector&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;weight&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0.8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;//go recursivly over each parent and add them with smaller weight&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;child&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ing&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Children&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;//do the same for children&lt;/span&gt;
        &lt;span class=&quot;nf&quot;&gt;SetIngredientWeight&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;child&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vector&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;weight&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0.9&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;/div&gt;
&lt;p&gt;What is happening:&lt;/p&gt;

&lt;p&gt;I iterate over all the ingredients in the recipe and set the weight to 1. I then go recursively up and down the ingredient tree and set the weights for parents and children. The further away from the original ingredient, the less significant the ingredient is. So the weight is lowered (this is accomplished care by the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;weight*0.9&lt;/code&gt; part in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SetIngredientWeight&lt;/code&gt;)&lt;/p&gt;

&lt;p&gt;This gives me a vector representation of every recipe. The “only” thing left is to figure a way to compare two vectors.&lt;/p&gt;

&lt;h2 id=&quot;calculating-similarity&quot;&gt;Calculating similarity&lt;/h2&gt;

&lt;p&gt;Ok, I have recipes represented as a vector of floats. Now, how does one go about converting two of those vectors into a single digit, from zero to one, representing how similar they are.&lt;/p&gt;

&lt;p&gt;Luckily, mathematicians figured this long time ago:) There are many algorithms that can be helpful, but the most common, is to calculate the &lt;a href=&quot;https://en.wikipedia.org/wiki/Dot_product&quot;&gt;dot product&lt;/a&gt;. Hence it is there we shall start.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/data/2016-11-28-How_I_calculate_similarities_in_cookit/dot_product.gif&quot; alt=&quot;dot product&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Let’s assume that our vectors are two-dimensional (this is like saying that every dish can be made from a combination of only two ingredients). They can then be drawn like this (image taken from Wikipedia):&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://upload.wikimedia.org/wikipedia/commons/thumb/3/3e/Dot_Product.svg/220px-Dot_Product.svg.png&quot; alt=&quot;two dimensional dot product&quot; /&gt;&lt;/p&gt;

&lt;p&gt;So what you’re looking at is one vector being projected onto another (the cosine part takes care of it). This gives its length relative to the other vector. However, relative values are nice but useless. Why? Because comparing the similarity of A and B to that of A and C would be to comparing the length of A projected onto B and A projected onto C. But the divisors are different, thus the comparison makes no sense. One way to deal with that is to normalize the value to one range (the most common being from zero to one). This is simple. Just divide the shorter vector, or projection, by the length of the longer projection. &lt;br /&gt;
As &lt;a href=&quot;http://www.commitstrip.com/&quot;&gt;ComicStrip&lt;/a&gt; says:&lt;br /&gt;
&lt;img src=&quot;http://www.commitstrip.com/wp-content/uploads/2016/08/Strip-Les-specs-cest-du-code-650-finalenglish.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Lets putting all of it into C#:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Similarity&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Vector&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Vector&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;){&lt;/span&gt;    
    &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;accumulator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&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;accumulator&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&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;denom&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)*&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;//convertion to absolute &lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;accumulator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;denom&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;         &lt;span class=&quot;c1&quot;&gt;//convertion to absolute    &lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;    
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;where &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Length&lt;/code&gt; looks like this:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Vector&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&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;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Math&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Sqrt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Sum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;k&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;So all well then? Far from it. But this will be the topic of &lt;a href=&quot;http://indexoutofrange.com/How-to-calculate-17-billion-similarities/&quot;&gt;the next post&lt;/a&gt;. Stay tune, &lt;a href=&quot;http://indexoutofrange.com/feed.xml&quot;&gt;rss&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/maklipsa&quot;&gt;follow&lt;/a&gt;, or just don’t close to browser window ;)&lt;/p&gt;
</description>
        <pubDate>Mon, 28 Nov 2016 00:00:00 +0100</pubDate>
        <link>https://IndexOutOfRange.com//How_I_calculate_similarities_in_cookit/</link>
        <guid isPermaLink="true">https://IndexOutOfRange.com//How_I_calculate_similarities_in_cookit/</guid>
      </item>
    
      <item>
        <title>Problems with AsParallel</title>
        <description>&lt;img src='https://indexoutofrange.com/data/2016-11-21-Problems_with_AsParallel/logo.jpg' /&gt;&lt;p&gt;This post is covering a subset of what I am talking in my talk &lt;a href=&quot;https://www.youtube.com/watch?v=Dup24FdDYj4&quot;&gt;How I stopped worrying and learned to love parallel processing&lt;/a&gt; (currently only in polish).&lt;/p&gt;

&lt;p&gt;This will cover on how, in terms of performance, &lt;a href=&quot;https://msdn.microsoft.com/en-us/library/system.linq.parallelenumerable.asparallel(v=vs.110).aspx&quot;&gt;AsParallel&lt;/a&gt; can kick you in a place where it hurts a lot, simultaneously being a blessing in terms of… performance. How is that? Let’s look at some&lt;/p&gt;

&lt;h2 id=&quot;history&quot;&gt;History&lt;/h2&gt;

&lt;p&gt;AsParallel was introduced as an extension to &lt;a href=&quot;https://msdn.microsoft.com/en-us/library/bb308959.aspx&quot;&gt;LINQ&lt;/a&gt; with &lt;a href=&quot;https://msdn.microsoft.com/en-us/library/dd460717(v=vs.110).aspx&quot;&gt;TPL&lt;/a&gt; in .NET 4.0. In theory, it’s God’s sent. The promise was that it will:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;parallelize the LINQ query.&lt;/li&gt;
  &lt;li&gt;take care of all thread management and synchronization.&lt;/li&gt;
  &lt;li&gt;adjust the number of Tasks automatically.&lt;/li&gt;
  &lt;li&gt;not require any additional code changes except for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.AsParallel()&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And in the vast majority of cases, this promise was kept! For example look at this code: 
&lt;!--MORE--&gt;&lt;/p&gt;

&lt;h2 id=&quot;when-it-is-awesome&quot;&gt;When it is awesome&lt;/h2&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Main&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;//create a list&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_numberCount&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;m&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1000&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;list&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;_numberCount&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&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;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_numberCount&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&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;list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&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;//calculate in one thread&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;MeasureTime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;list&lt;/span&gt;
                        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Where&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IsPrime&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;nf&quot;&gt;Count&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;//use AsParallel&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;MeasureTime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;list&lt;/span&gt;
                        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;AsParallel&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;nf&quot;&gt;Where&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IsPrime&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;nf&quot;&gt;Count&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;c1&quot;&gt;//very bad way to calculate a prime. Not for production usage ;) &lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;internal&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;IsPrime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&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;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;number&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;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;false&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;number&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;2&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;k&quot;&gt;true&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;boundary&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;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Math&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Floor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Math&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Sqrt&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;for&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;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;boundary&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;i&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;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&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;k&quot;&gt;false&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;k&quot;&gt;true&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;private&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;MeasureTime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Func&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;a&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;sw&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Stopwatch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;StartNew&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;sw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Stop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;Console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;WriteLine&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Took: &quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ElapsedMilliseconds&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;/div&gt;

&lt;p&gt;This is a trivial example (a more real life example was published recently by Ayende &lt;a href=&quot;https://ayende.com/blog/176035/making-code-faster-the-obvious-costs&quot;&gt;here&lt;/a&gt;, &lt;a href=&quot;https://ayende.com/blog/176036/making-code-faster-starting-from-scratch&quot;&gt;here&lt;/a&gt;, &lt;a href=&quot;https://ayende.com/blog/176037/making-code-faster-going-down-the-i-o-chute&quot;&gt;here&lt;/a&gt; and &lt;a href=&quot;https://ayende.com/blog/176037/making-code-faster-going-down-the-i-o-chute&quot;&gt;here&lt;/a&gt;), but stay with me. 
In this case, the difference between single threaded and parallel execution is as follows:&lt;/p&gt;

&lt;div class=&quot;language-console highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;go&quot;&gt;Single threaded: 570
AsParallel: 138
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This is more than &lt;strong&gt;4-times speed up&lt;/strong&gt; with only 1 line and no additional code changes. Looks like all the promises were kept.&lt;/p&gt;

&lt;p&gt;But sometimes things don’t go that good.&lt;/p&gt;

&lt;!-- Begin MailChimp Signup Form --&gt;

&lt;link href=&quot;//cdn-images.mailchimp.com/embedcode/horizontal-slim-10_7.css&quot; rel=&quot;stylesheet&quot; type=&quot;text/css&quot; /&gt;

&lt;style type=&quot;text/css&quot;&gt;
	#mc_embed_signup{
        clear:left; 
        font:14px Helvetica,Arial,sans-serif; 
        width:100%; 
        margin-top: 40px;
        margin-bottom: 40px;
        height:100px;
    }
    #mc_embed_signup .newsletter div{
        height: 100px;
    }
    #mc_embed_signup form{
        position: relative;
        top: -90px;
    }
	/* Add your own MailChimp form style overrides in your site stylesheet or in this style block.
	   We recommend moving this block and the preceding CSS link to the HEAD of your HTML file. */
&lt;/style&gt;

&lt;div id=&quot;mc_embed_signup&quot;&gt;
    &lt;div class=&quot;gradient newsletter&quot;&gt;
        &lt;div style=&quot;background:#000000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#1C0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#380000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#550000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#710000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#8D0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#AA0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#C60000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#E20000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF3800&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF5500&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF7100&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF8D00&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFAA00&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFC600&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFE200&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFFF00&quot;&gt;&lt;/div&gt;
    &lt;/div&gt;
    &lt;form action=&quot;https://IndexOutOfRange.us15.list-manage.com/subscribe/post?u=b1c1099bf7f49b95c64107c99&amp;amp;id=6a5eb68eb7&quot; method=&quot;post&quot; id=&quot;mc-embedded-subscribe-form&quot; name=&quot;mc-embedded-subscribe-form&quot; class=&quot;validate&quot; target=&quot;_blank&quot; novalidate=&quot;&quot;&gt;
        &lt;div id=&quot;mc_embed_signup_scroll&quot;&gt;
        &lt;label for=&quot;mce-EMAIL&quot; style=&quot;color: white;&quot;&gt;Get email notifications about new posts:&lt;/label&gt;
        &lt;input type=&quot;email&quot; value=&quot;&quot; name=&quot;EMAIL&quot; class=&quot;email&quot; id=&quot;mce-EMAIL&quot; placeholder=&quot;email address&quot; required=&quot;&quot; /&gt;
        &lt;!-- real people should not fill this in and expect good things - do not remove this or risk form bot signups--&gt;
        &lt;div style=&quot;position: absolute; left: -5000px;&quot; aria-hidden=&quot;true&quot;&gt;&lt;input type=&quot;text&quot; name=&quot;b_b1c1099bf7f49b95c64107c99_6a5eb68eb7&quot; tabindex=&quot;-1&quot; value=&quot;&quot; /&gt;&lt;/div&gt;
        &lt;div class=&quot;clear&quot;&gt;&lt;input type=&quot;submit&quot; value=&quot;Subscribe&quot; name=&quot;subscribe&quot; id=&quot;mc-embedded-subscribe&quot; class=&quot;button&quot; /&gt;&lt;/div&gt;
        &lt;/div&gt;
    &lt;/form&gt;
&lt;/div&gt;

&lt;!--End mc_embed_signup--&gt;

&lt;h2 id=&quot;asparallel-on-a-to-small-set&quot;&gt;AsParallel on a to small set&lt;/h2&gt;

&lt;p&gt;Let’s change that code, and set the list size to 100. Then the results will look like that:&lt;/p&gt;

&lt;div class=&quot;language-console highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;go&quot;&gt;Single threaded: 4
AsParallel: 15
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And yes. Those numbers are tiny. But if you have it in every web request or a small that’s frequently called function it cumulates and affects overall performance. 
When talking about small functions they have a habit of being used in other functions, thus creating bigger blocks. Those blocks tend to be … parallelized. So let’s see what happens then.&lt;/p&gt;

&lt;h2 id=&quot;nested-asparallel&quot;&gt;Nested AsParallel&lt;/h2&gt;

&lt;p&gt;It is more or less the same code as above, but now we have:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CalcInSingleAsParallel&lt;/code&gt; that calculates the primes using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AsParallel&lt;/code&gt; (same as above)’&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CalcInTwoNestedAsParallel&lt;/code&gt; splits a list into chunks and returns in parallel calls &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CalcInSingleAsParallel&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;p&gt;One thing to note about &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CalcInTwoNestedAsParallel&lt;/code&gt; is that it splits the list into chunks when being invoked, but returns an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IEnumerable&lt;/code&gt;. This trick defers the calculation of the prime until &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Count&lt;/code&gt; is being called. This way &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MeasureTime&lt;/code&gt; only measures the prime calculating part.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Main&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;//create the list&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_numberCount&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;m&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1000&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;list&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;_numberCount&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&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;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_numberCount&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&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;list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&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;// split the list into 10 fragments and return an IEnumerable&amp;lt;IEnumerable&amp;lt;int&amp;gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tenFragments&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;CalcInTwoNestedAsParallel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;MeasureTime&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;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tenFragments&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Sum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Count&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;// split the list into 100 fragments and return an IEnumerable&amp;lt;IEnumerable&amp;lt;int&amp;gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hundretFragments&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;CalcInTwoNestedAsParallel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;//calculate the prime number&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;MeasureTime&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;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hundretFragments&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Sum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Count&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;// split the list into 1000 fragments and return an IEnumerable&amp;lt;IEnumerable&amp;lt;int&amp;gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;thousandFragments&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;CalcInTwoNestedAsParallel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;//calculate the prime number&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;MeasureTime&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;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;thousandFragments&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Sum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Count&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;private&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&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;IEnumerable&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;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;CalcInTwoNestedAsParallel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&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;numbers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;chunkNumber&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;numbersChunks&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ToChunks&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;numbers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;chunkNumber&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;numbersChunks&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;AsParallel&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;nf&quot;&gt;Select&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CalcInSingleAsParallel&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;private&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&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;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;CalcInSingleAsParallel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&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;numbers&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;numbers&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;AsParallel&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;nf&quot;&gt;Where&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IsPrime&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;private&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&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;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;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ToChunks&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&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;source&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nSize&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;30&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;ret&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;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;&amp;gt;();&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&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;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nSize&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;tmp&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetRange&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Math&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Min&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;nSize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Count&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&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;n&quot;&gt;ret&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;internal&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;IsPrime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&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;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;number&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;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;false&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;number&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;2&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;k&quot;&gt;true&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;boundary&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;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Math&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Floor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Math&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Sqrt&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;for&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;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;boundary&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;i&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;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&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;k&quot;&gt;false&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;k&quot;&gt;true&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;private&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;MeasureTime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Func&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;a&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;sw&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Stopwatch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;StartNew&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;sw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Stop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;WriteLine&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Took: &quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ElapsedMilliseconds&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;/div&gt;

&lt;p&gt;The results look like this:&lt;/p&gt;

&lt;div class=&quot;language-console highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;go&quot;&gt;For 10 chunks containing 100 000 elements it took: 1737
For 100 chunks containing 10 000 elements it took: 361
For 1000 chunks containing 1 000 elements it took: 228
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We have a &lt;strong&gt;~7.6 times difference&lt;/strong&gt; between the best and the worst run, and &lt;strong&gt;~12.5 times difference&lt;/strong&gt; when compared to a single &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AsParallel&lt;/code&gt;! 
It gets even worse when we nest it into another &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AsParallel&lt;/code&gt; (while maintaining the same total amount of calculations being done):&lt;/p&gt;

&lt;div class=&quot;language-console highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;go&quot;&gt;For 10*10 chunks containing 10 000 elements it took: 3061
For 100*100 chunks containing 100 elements it took: 571
For 1000*1000 chunks containing 1 elements it took: 284
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;blockquote&gt;
  &lt;p&gt;Take a look again at the last line:
For 1000*1000 chunks containing 1 elements it took: 284
It was the fastest in this run although having very tiny (one element) lists.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The difference between the best and the worst run is this case is &lt;strong&gt;11 times&lt;/strong&gt;. 
When compared to the best run (a single &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AsParallel&lt;/code&gt;) it is more than &lt;strong&gt;22 times slower!&lt;/strong&gt; 
Why is that?&lt;/p&gt;

&lt;h2 id=&quot;the-profiler&quot;&gt;The profiler&lt;/h2&gt;
&lt;p&gt;This is the dotTrace result for all of the above:&lt;/p&gt;

&lt;p&gt;No nesting, single &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AsParallel&lt;/code&gt;:
&lt;img src=&quot;/data/2016-11-21-Problems_with_AsParallel/NoNesting.png&quot; alt=&quot;single AsParallel&quot; /&gt;&lt;/p&gt;

&lt;p&gt;One nesting (so two &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AsParallel&lt;/code&gt;), 10 chunks:
&lt;img src=&quot;/data/2016-11-21-Problems_with_AsParallel/OneNesting_10.png&quot; alt=&quot;two nested AsParallel&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Two nestings (so three &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AsParallel&lt;/code&gt;), 10*10 chunks:
&lt;img src=&quot;/data/2016-11-21-Problems_with_AsParallel/TwoNesting_10.png&quot; alt=&quot;three nested AsParallel&quot; /&gt;&lt;/p&gt;

&lt;p&gt;So what is happening in those applications?&lt;/p&gt;

&lt;p&gt;The first thread is the main thread of the application. The long delay before spawning more threads is the start-up of the application and list creation.
Next threads start to show up. This is because of the call to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AsParallel&lt;/code&gt;. It triggers TPL’s &lt;a href=&quot;https://msdn.microsoft.com/en-us/library/system.threading.tasks.taskscheduler(v=vs.110).aspx&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TaskScheduler&lt;/code&gt;&lt;/a&gt; which tries to create just the right amount of threads to minimize &lt;a href=&quot;https://en.wikipedia.org/wiki/Context_switch&quot;&gt;context switching&lt;/a&gt; between them and, at the same time, parallelize as much as possible by assigning tasks to thread and if needed creating more threads.&lt;/p&gt;

&lt;p&gt;So why do we have such huge difference in execution times? Then we compare the images, the answer what is wrong becomes obvious. The cost is hidden in switching and managing threads. TPL’s task scheduler is creating new threads and assigning tasks to them because it thinks adding more will help (a single operation is short). At the same time, the operating system is switching between threads, trying to give each a slice of processors time thus reducing the time real computation is being done. Those two managers are interfering each other leading to almost no work being done and in the end a 22 times increase in time needed for the work to finish.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;This shows that micro-managing is not a good thing. In programming or in the real world ;)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h1&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AsParallel&lt;/code&gt; gives mind blowing performance gains with little to none effort. But it can’t be treated as a silver bullet. 
When you decide to use it:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;profile the whole process.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AsParallel&lt;/code&gt; is dependent on the data size. So have performance tests with wide range of size of the processed data&lt;/li&gt;
  &lt;li&gt;when used in a web application, test it under load. IIS likes to have control over threads and you are messing with it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Use with caution&lt;/strong&gt;&lt;/p&gt;
</description>
        <pubDate>Mon, 21 Nov 2016 00:00:00 +0100</pubDate>
        <link>https://IndexOutOfRange.com//Problems_with_AsParallel/</link>
        <guid isPermaLink="true">https://IndexOutOfRange.com//Problems_with_AsParallel/</guid>
      </item>
    
      <item>
        <title>Debugging high memory usage. Part 2 - .NET Memory Profiler</title>
        <description>&lt;img src='https://indexoutofrange.com/data/2016-09-30-Debugging-high-memory-usage.Part-2-dot-net-memory-profiler/logo.png' /&gt;&lt;p&gt;Diagnosing high memory usage can be tricky, here is the second part of how I found what was hogging to much memory in our system.
In the &lt;a href=&quot;/Debugging-high-memory-usage.Part-1-ProcDump/&quot;&gt;previous post&lt;/a&gt; I’ve wrote how to create a memory dump and how many possibilities of catching just the right moment for it ProcDump has. 
When trying to analyze memory leaks, or high memory usage (not necessary meaning a leak) we have a few ways to approach it:
&lt;!--MORE--&gt;&lt;/p&gt;

&lt;h3 id=&quot;attach-a-debugger&quot;&gt;Attach a debugger&lt;/h3&gt;

&lt;p&gt;There are many problems with this approach, to name a few:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;it has to be done on the machine where the memory outrage has happened (probably a test server). And there Visual Studio shouldn’t be installed.&lt;/li&gt;
  &lt;li&gt;when debugging an IIS managed process it is being stopped. While the process is stopped it won’t respond to IIS &lt;a href=&quot;https://blogs.msdn.microsoft.com/gaurav/2015/01/16/the-web-server-process-that-was-being-debugged-has-been-terminated-by-internet-information-services-iis-this-can-be-avoided-by-configuring-application-pool-ping-settings-in-iis/&quot;&gt;ping requests&lt;/a&gt; (they can be turn off, but it is a good practice to have them on). This in effect will make IIS believe that that the process is hanging and restart it. And there goes our debugging session :(&lt;/li&gt;
  &lt;li&gt;debugging a multithreaded application handling multiple incoming requests will lead to breakpoints being triggered by multiple requests, not just the one being debugged&lt;/li&gt;
  &lt;li&gt;step by step debugging doesn’t give a view of the memory allocated&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To sum up, this is not a good way to approach the problem.&lt;/p&gt;

&lt;h3 id=&quot;attach-an-online-profiler&quot;&gt;Attach an online profiler&lt;/h3&gt;
&lt;p&gt;Products like &lt;a href=&quot;http://www.red-gate.com/products/dotnet-development/ants-memory-profiler/&quot;&gt;Redgate ANTS Profiler&lt;/a&gt;, &lt;a href=&quot;https://www.jetbrains.com/dotmemory/features/&quot;&gt;JetBrains dotMemory&lt;/a&gt; can attach to a process and show current GC generation sizes, the paste of new memory being allocated, and compare memory between two points in time (snapshots). While those features are great when profiling and optimizing, they are not that useful when trying to diagnose what has allocated the memory.&lt;/p&gt;

&lt;h3 id=&quot;offline-memory-analyzers&quot;&gt;Offline memory analyzers&lt;/h3&gt;
&lt;p&gt;To clarify, by offline I mean programs that can read a memory dump ( the &lt;a href=&quot;http://indexoutofrange.com/Debugging-high-memory-usage.Part-1-ProcDump/&quot;&gt;previous post&lt;/a&gt; covers one of the methods how to create a memory dump). This criteria leaves us with not that many programs to choose from. Online profilers mentioned above can’t read a memory dump. From my knowledge at this point we can choose from:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://msdn.microsoft.com/en-us/library/windows/hardware/ff551063(v=vs.85).aspx&quot;&gt;WinDbg&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://memprofiler.com/&quot;&gt;.NET Memory Profiler from SciTech Software AB&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The first one is the all powerful big boys profiler with text commands and text based gui. It has the power and the speed that none other profiler has, but
&lt;img src=&quot;/data/2016-09-30-Debugging-high-memory-usage.Part-2-dot-net-memory-profiler/spyderman.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Another, more important in this cases, thing lacking is the ability to show dependencies between objects and memory they allocated. So let’s look at what .NET Memory profiler can do.&lt;/p&gt;

&lt;!-- Begin MailChimp Signup Form --&gt;

&lt;link href=&quot;//cdn-images.mailchimp.com/embedcode/horizontal-slim-10_7.css&quot; rel=&quot;stylesheet&quot; type=&quot;text/css&quot; /&gt;

&lt;style type=&quot;text/css&quot;&gt;
	#mc_embed_signup{
        clear:left; 
        font:14px Helvetica,Arial,sans-serif; 
        width:100%; 
        margin-top: 40px;
        margin-bottom: 40px;
        height:100px;
    }
    #mc_embed_signup .newsletter div{
        height: 100px;
    }
    #mc_embed_signup form{
        position: relative;
        top: -90px;
    }
	/* Add your own MailChimp form style overrides in your site stylesheet or in this style block.
	   We recommend moving this block and the preceding CSS link to the HEAD of your HTML file. */
&lt;/style&gt;

&lt;div id=&quot;mc_embed_signup&quot;&gt;
    &lt;div class=&quot;gradient newsletter&quot;&gt;
        &lt;div style=&quot;background:#000000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#1C0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#380000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#550000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#710000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#8D0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#AA0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#C60000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#E20000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF3800&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF5500&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF7100&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF8D00&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFAA00&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFC600&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFE200&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFFF00&quot;&gt;&lt;/div&gt;
    &lt;/div&gt;
    &lt;form action=&quot;https://IndexOutOfRange.us15.list-manage.com/subscribe/post?u=b1c1099bf7f49b95c64107c99&amp;amp;id=6a5eb68eb7&quot; method=&quot;post&quot; id=&quot;mc-embedded-subscribe-form&quot; name=&quot;mc-embedded-subscribe-form&quot; class=&quot;validate&quot; target=&quot;_blank&quot; novalidate=&quot;&quot;&gt;
        &lt;div id=&quot;mc_embed_signup_scroll&quot;&gt;
        &lt;label for=&quot;mce-EMAIL&quot; style=&quot;color: white;&quot;&gt;Get email notifications about new posts:&lt;/label&gt;
        &lt;input type=&quot;email&quot; value=&quot;&quot; name=&quot;EMAIL&quot; class=&quot;email&quot; id=&quot;mce-EMAIL&quot; placeholder=&quot;email address&quot; required=&quot;&quot; /&gt;
        &lt;!-- real people should not fill this in and expect good things - do not remove this or risk form bot signups--&gt;
        &lt;div style=&quot;position: absolute; left: -5000px;&quot; aria-hidden=&quot;true&quot;&gt;&lt;input type=&quot;text&quot; name=&quot;b_b1c1099bf7f49b95c64107c99_6a5eb68eb7&quot; tabindex=&quot;-1&quot; value=&quot;&quot; /&gt;&lt;/div&gt;
        &lt;div class=&quot;clear&quot;&gt;&lt;input type=&quot;submit&quot; value=&quot;Subscribe&quot; name=&quot;subscribe&quot; id=&quot;mc-embedded-subscribe&quot; class=&quot;button&quot; /&gt;&lt;/div&gt;
        &lt;/div&gt;
    &lt;/form&gt;
&lt;/div&gt;

&lt;!--End mc_embed_signup--&gt;

&lt;h2 id=&quot;net-memory-profiler&quot;&gt;.NET Memory Profiler&lt;/h2&gt;
&lt;blockquote&gt;
  &lt;p&gt;.NET Memory Profiler can have a tendency to crash after few minutes, sometimes even in less then one. As strange as it seams restarting the computer removes the problem. This happened to me 3 times.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;First let’s load the dump file with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;File &amp;gt; Import memory dump...&lt;/code&gt;.
This opens a nice import window with a few options and data to fill:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Include instance addresses&lt;/code&gt; - in our case not important. I’ m not planing on reading the dump in search of individual objects.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Collect instance data&lt;/code&gt; - this gives the ability to view values of fields and objects. Very nice feature, but at the first run I usually try to get a high-level look at the objects in memory so this is not needed for now.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After pushing Start another window will appear asking for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mscordacwks.dll&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sos.dll&lt;/code&gt;. &lt;strong&gt;You need to take those files from the machine on which the dump was made.&lt;/strong&gt; .NET Memory Profiler tries to give hints where to find them, but the exact framework version can be slightly different (4.5 instead of 4.6.1 etc).&lt;/p&gt;

&lt;p&gt;After some time (depending from the dump size) the main window will appear:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/data/2016-09-30-Debugging-high-memory-usage.Part-2-dot-net-memory-profiler/MemProfiler_step01.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;So let’s look what we have here. While this screen alone can give the answer to someone knowing the application, let’s go through it in investigative mode. What we see immediately is that the main memory holder is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;StatefulPersitanceContext&lt;/code&gt; from NHibernate. With 28 instances it is holding almost 2 Gigs of memory.
So lets double click on it and go into details. And we see this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/data/2016-09-30-Debugging-high-memory-usage.Part-2-dot-net-memory-profiler/MemProfiler_step02.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The window on the left shows the current instances and info about them. One instance is responsible for most used memory. So let’s drill into it. Double click and here we go.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/data/2016-09-30-Debugging-high-memory-usage.Part-2-dot-net-memory-profiler/MemProfiler_step03.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Did You notice that the graph on the right changed? It is showing dependency graphs for the currently selected instances.
What can be seen is that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Session&lt;/code&gt; is keeping hold of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Document&lt;/code&gt; entity, which has a few collections on its own.
The next object referring to this session is on the right side of the graph:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/data/2016-09-30-Debugging-high-memory-usage.Part-2-dot-net-memory-profiler/MemProfiler_step04.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;So &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AutoCloseDocumentService&lt;/code&gt; in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CloseSettledDocuments&lt;/code&gt; is holding to this large session, and the session holds &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Document&lt;/code&gt; entity.
So let’s get back to the first screen and see just how many &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Document&lt;/code&gt; entities there are:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/data/2016-09-30-Debugging-high-memory-usage.Part-2-dot-net-memory-profiler/MemProfiler_step05.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Yup. Over 301 thousand root entities in one NHibernate session. Just to be sure let’s look at the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CloseSettledDocuments&lt;/code&gt; function:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&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;CloseSettledDocuments&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;settledDocumentsToBeClosed&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;GetApprovedDocuments&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;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;document&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;settledDocumentsToBeClosed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;nf&quot;&gt;CloseDocument&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;document&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;/div&gt;

&lt;p&gt;and a peek into &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GetApprovedDocuments&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IList&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;GetApprovedDocuments&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;_session&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;QueryOver&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;().&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ToList&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;/div&gt;

&lt;p&gt;So we listed 301 thousand documents and processed each one independently. Classic n+1 problem that escalated because of large amount of data.&lt;/p&gt;

</description>
        <pubDate>Fri, 30 Sep 2016 00:00:00 +0200</pubDate>
        <link>https://IndexOutOfRange.com//Debugging-high-memory-usage.Part-2-DotNetMemoryProfiler/</link>
        <guid isPermaLink="true">https://IndexOutOfRange.com//Debugging-high-memory-usage.Part-2-DotNetMemoryProfiler/</guid>
      </item>
    
      <item>
        <title>Debugging high memory usage. Part 1 - ProcDump</title>
        <description>&lt;img src='https://indexoutofrange.com/data/2016-09-21-Debugging-high-memory-usage.Part-1-ProcDump/logo.png' /&gt;&lt;p&gt;I’m taking a short break from &lt;a href=&quot;/Don't-do-it/&quot;&gt;Hangfire series&lt;/a&gt;, but I will get back to it.&lt;/p&gt;

&lt;p&gt;This time - Where did my memory go ? Or to be more exact: Why is this using so much memory?&lt;/p&gt;

&lt;p&gt;The story starts with one IIS application pool using around 6 Gigabytes of memory on one of our test environments. It was several times above the values that we expected it to use, so we decided to investigate.&lt;/p&gt;

&lt;p&gt;Without much thinking we fired up Visual Studio installed on the test server, and attached to the process. Since the application was build in Debug mode we had all the pdb files in the website folder.&lt;/p&gt;

&lt;p&gt;Do I have your attention now? The above paragraph is of curse a joke and a bunch of &lt;strong&gt;anti patterns. Don’t do any of them!&lt;/strong&gt;&lt;/p&gt;

&lt;!--MORE--&gt;
&lt;p&gt;Now that I have your attentions let’s get back to what really happened. Since it was a remote sever handling multiple enviroments the only sane step to take is to make a memory dump of the process, kill it and analyze it on a developers machine. Since we always have &lt;a href=&quot;https://technet.microsoft.com/en-us/sysinternals/bb842062.aspx?f=255&amp;amp;MSPPError=-2147217396&quot;&gt;Sysinternals Suite&lt;/a&gt; in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;c:\tools&lt;/code&gt; (highly recommend having it, because when You need it the most, there is no time for download). Sysinternals Suite contains a simple console application for making process dump called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;procdump.exe&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ProcDump&lt;/code&gt; is a very powerful tool and it’s capabilities go far beyond what I will show now. To just give a glimpse flags that control then the dump will be triggered:&lt;/p&gt;

  &lt;ul&gt;
    &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;c&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cl&lt;/code&gt;- create a dump when &lt;strong&gt;CPU threshold&lt;/strong&gt; is above or below given limit&lt;/li&gt;
    &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;e&lt;/code&gt; -  create a dump when &lt;strong&gt;unhandled exception is thrown&lt;/strong&gt;&lt;/li&gt;
    &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;h&lt;/code&gt; - create a dump when processes &lt;strong&gt;window is not responsive&lt;/strong&gt;&lt;/li&gt;
    &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;m&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ml&lt;/code&gt; -  create a dump when &lt;strong&gt;CPU threshold&lt;/strong&gt; is above or below given limit&lt;/li&gt;
    &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;p&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pl&lt;/code&gt; - create a dump when a given &lt;strong&gt;performance counter&lt;/strong&gt; is above or below a given limit&lt;/li&gt;
    &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;t&lt;/code&gt; - create a dump when the &lt;strong&gt;process terminates&lt;/strong&gt;&lt;/li&gt;
    &lt;li&gt;absence of this flags means trigger the dump now
For a better insight of what ProcDump can do fire it up without any arguments and it will display a very good help.&lt;/li&gt;
  &lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;In this case we wanted to get the dump right now, so the command line looked like this:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;procdump.exe 25944 c:&lt;span class=&quot;se&quot;&gt;\t&lt;/span&gt;emp&lt;span class=&quot;se&quot;&gt;\ &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;-ma&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;To decompose:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;25944&lt;/code&gt; is the process id. We could pass a process name, but since it is a website hosted by IIS its process is named w3wp.exe.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;p&gt;Process id (PID in short) can be obtained be many tools such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ProcessExplorer&lt;/code&gt; which is also a part of SysInternals Suite. But the default Task Manager available on any Windows machine also has it. 
Just right click on the Name column, and check &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PID&lt;/code&gt; in the menu that will appear.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;c:\temp&lt;/code&gt; is the folder where the dump will be written to&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ma&lt;/code&gt; flag says that we want a full dump with all of processes memory written to the file.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you get this error:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Error opening w3wp.exe &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;25944&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;:
Error 0x00000005 &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;5&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;: Access is denied.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;That is because it has to be run with administrator privileges like any debugger. The normal output should look like this:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;ProcDump v8.0 - Writes process dump files
Copyright &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;C&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; 2009-2016 Mark Russinovich
Sysinternals - www.sysinternals.com
With contributions from Andrew Richards

&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;12:48:59] Dump 1 initiated: c:&lt;span class=&quot;se&quot;&gt;\t&lt;/span&gt;emp&lt;span class=&quot;se&quot;&gt;\w&lt;/span&gt;3wp.exe_160917_124859.dmp
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;12:49:03] Dump 1 writing: Estimated dump file size is 5612 MB.
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;12:49:59] Dump 1 &lt;span class=&quot;nb&quot;&gt;complete&lt;/span&gt;: 5614 MB written &lt;span class=&quot;k&quot;&gt;in &lt;/span&gt;55.6 seconds
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;12:50:00] Dump count reached.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;So we have the dump. What next? This is the topic for the next post :)&lt;/p&gt;
</description>
        <pubDate>Wed, 21 Sep 2016 00:00:00 +0200</pubDate>
        <link>https://IndexOutOfRange.com//Debugging-high-memory-usage.Part-1-ProcDump/</link>
        <guid isPermaLink="true">https://IndexOutOfRange.com//Debugging-high-memory-usage.Part-1-ProcDump/</guid>
      </item>
    
      <item>
        <title>Don't do it now! Part 6. Hangfire details - recurring jobs and cron expressions</title>
        <description>&lt;img src='https://indexoutofrange.com/data/2016-09-07-Dont-do-it-now!Part-6.recurring_jobs_and_cron_expressions/logo.jpg' /&gt;&lt;p&gt;Parts &lt;a href=&quot;/Don't-do-it-now!-Part-3.-Hangfire-details-jobs/&quot;&gt;3&lt;/a&gt;, &lt;a href=&quot;/Don't-do-it-now!-Part-4.-Hangfire-details-dashboard,-retries-and-job-cancellation/&quot;&gt;4&lt;/a&gt;, and &lt;a href=&quot;/Don't-do-it-now!-Part-5.-Hangfire-job-continuation,-ContinueWith/&quot;&gt;5&lt;/a&gt; covered the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BackgroundJob&lt;/code&gt; class responsible for enqueuing single jobs (fire and forget). This post will cover &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RecurringJob&lt;/code&gt; class exposing API for recurring jobs (as the name suggests).&lt;/p&gt;

&lt;h2 id=&quot;recurring-job&quot;&gt;Recurring job&lt;/h2&gt;
&lt;p&gt;Before we go into the API, let’s take a look what is a recurring job in Hangfire.
Recurring job is a timer that enqueues a job at specific time intervals defined with a cron expression. What is important is, that it does not execute the job. Only enqueues an ordinary Hangfire job. This implementation is very elegant, but it also means that if the queue is full the job will have to wait for its turn. So there is no guarantee about the time it will actually execute.
&lt;!--MORE--&gt;&lt;/p&gt;

&lt;h2 id=&quot;cron-expressions&quot;&gt;Cron expressions&lt;/h2&gt;
&lt;p&gt;I’ve mentioned cron expression few times, but what exactly are they? Cron expressions are a way to express time occurrence, like &lt;em&gt;“every Monday at 8”&lt;/em&gt;, or &lt;em&gt;“second Thursday of the month at 5:30”&lt;/em&gt;. How do they look? A few examples:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;every Monday at 8&lt;/strong&gt; can be expressed by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0 0 8 ? * MON *&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;second Thursday of the month at 5:30&lt;/strong&gt; can be expressed by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0 30 5 ? 1/1 THU#2 *&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;second Thursday of &lt;em&gt;every third month&lt;/em&gt; at 5&lt;/strong&gt; can be expressed by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0 30 5 ? 1/3 THU#2 *&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Just looking at the examples above a pattern emerges:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[seconds] [minutes] [hours] [day of month] [month] [day of week] [year]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Most of the fields accept special characters:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;*&lt;/code&gt; - all values&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;?&lt;/code&gt; - no specific value. So what is the difference between &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;*&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;?&lt;/code&gt; ? The first one selects all values and the second one says “I don’t care about it”. Like with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0 0 8 ? * MON *&lt;/code&gt; example. We put &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;?&lt;/code&gt; into &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;day of month&lt;/code&gt; field because which day of the month it will be is not important.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-&lt;/code&gt; - for ranges. For example: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MON-FRI&lt;/code&gt; for selecting &lt;em&gt;workweek days&lt;/em&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;,&lt;/code&gt; - naming multiple values. For example: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MON,FRI&lt;/code&gt; for selecting &lt;em&gt;Monday and Friday&lt;/em&gt; &lt;strong&gt;only&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/&lt;/code&gt; - for adding intervals. It is used like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;x/y&lt;/code&gt; which means: “start at x and do it every y times”. For example: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0/10&lt;/code&gt; in seconds field will result in values: 0,10,20,30,40,50. One thing to look out for is that cron uses human notation, so with days, months etc. we start counting from 1, not 0, like in example 2 and 3 above.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;L&lt;/code&gt; - last. It is allowed in two fields: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;day of month&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;day of week&lt;/code&gt;. This comes in handy when talking about the last day of February and not having to worry about leap years. It gets even better, and more confusing, when used for example like this: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;L-1&lt;/code&gt; in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;day of month&lt;/code&gt; field. Why is it powerful and confusing? Because it doesn’t mean &lt;em&gt;“the last day and day before the last day of the month”&lt;/em&gt; ( &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-&lt;/code&gt; is for expressing ranges), but it means &lt;em&gt;day before the last day of the month&lt;/em&gt;. So strange, but powerful since it gives the possibility to enumerate on days starting from the end of the month/week.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;W&lt;/code&gt; - &lt;strong&gt;nearest&lt;/strong&gt; weekday. How is it different from naming &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MON-FRI&lt;/code&gt;? It returns the &lt;strong&gt;nearest&lt;/strong&gt; working day from a given date. So:
    &lt;ul&gt;
      &lt;li&gt;a cron: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0 0 12 4W 9 ? *&lt;/code&gt; in the year 2016 will return the &lt;em&gt;5 of September 2016 12:00&lt;/em&gt; since 4 of September 2016 is Sunday, so Monday is the nearest.&lt;/li&gt;
      &lt;li&gt;a cron: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0 0 12 3W 9 ? *&lt;/code&gt; in the year 2016 will return the &lt;em&gt;2 of September 2016 12:00&lt;/em&gt; since 3 of September 2016 is Saturday, so Friday is the nearest.&lt;/li&gt;
      &lt;li&gt;a cron: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0 0 12 1W 10 ? *&lt;/code&gt; in the year 2016 will return the &lt;em&gt;3 of October 2016 12:00&lt;/em&gt; despite the fact that it is Saturday. Why? Because it returns the nearest workday &lt;strong&gt;in a given month&lt;/strong&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#&lt;/code&gt; - the nth value. Think of it as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/&lt;/code&gt; but without the iteration. Only allowed in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;day of week&lt;/code&gt; field  For example:
    &lt;ul&gt;
      &lt;li&gt;a cron &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;6#2&lt;/code&gt; used in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;day of week&lt;/code&gt; means &lt;em&gt;second Friday of the week&lt;/em&gt;. Why Friday? Because in this case days of week are numbered from 0 (Saturday)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If this looks complicated there is a &lt;a href=&quot;http://www.cronmaker.com/&quot;&gt;cron expression builder online&lt;/a&gt; and Hangfire has a helper class &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Hangfire.Cron&lt;/code&gt;. Inside Hangfire uses NCrontab (&lt;a href=&quot;https://www.nuget.org/packages/ncrontab/&quot;&gt;nuget&lt;/a&gt;, &lt;a href=&quot;https://github.com/atifaziz/NCrontab&quot;&gt;github&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Ok, lets get back to Hangfire and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RecurringJob&lt;/code&gt; class. It has three functions (excluding the overrides):&lt;/p&gt;

&lt;!-- Begin MailChimp Signup Form --&gt;

&lt;link href=&quot;//cdn-images.mailchimp.com/embedcode/horizontal-slim-10_7.css&quot; rel=&quot;stylesheet&quot; type=&quot;text/css&quot; /&gt;

&lt;style type=&quot;text/css&quot;&gt;
	#mc_embed_signup{
        clear:left; 
        font:14px Helvetica,Arial,sans-serif; 
        width:100%; 
        margin-top: 40px;
        margin-bottom: 40px;
        height:100px;
    }
    #mc_embed_signup .newsletter div{
        height: 100px;
    }
    #mc_embed_signup form{
        position: relative;
        top: -90px;
    }
	/* Add your own MailChimp form style overrides in your site stylesheet or in this style block.
	   We recommend moving this block and the preceding CSS link to the HEAD of your HTML file. */
&lt;/style&gt;

&lt;div id=&quot;mc_embed_signup&quot;&gt;
    &lt;div class=&quot;gradient newsletter&quot;&gt;
        &lt;div style=&quot;background:#000000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#1C0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#380000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#550000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#710000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#8D0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#AA0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#C60000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#E20000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF3800&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF5500&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF7100&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF8D00&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFAA00&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFC600&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFE200&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFFF00&quot;&gt;&lt;/div&gt;
    &lt;/div&gt;
    &lt;form action=&quot;https://IndexOutOfRange.us15.list-manage.com/subscribe/post?u=b1c1099bf7f49b95c64107c99&amp;amp;id=6a5eb68eb7&quot; method=&quot;post&quot; id=&quot;mc-embedded-subscribe-form&quot; name=&quot;mc-embedded-subscribe-form&quot; class=&quot;validate&quot; target=&quot;_blank&quot; novalidate=&quot;&quot;&gt;
        &lt;div id=&quot;mc_embed_signup_scroll&quot;&gt;
        &lt;label for=&quot;mce-EMAIL&quot; style=&quot;color: white;&quot;&gt;Get email notifications about new posts:&lt;/label&gt;
        &lt;input type=&quot;email&quot; value=&quot;&quot; name=&quot;EMAIL&quot; class=&quot;email&quot; id=&quot;mce-EMAIL&quot; placeholder=&quot;email address&quot; required=&quot;&quot; /&gt;
        &lt;!-- real people should not fill this in and expect good things - do not remove this or risk form bot signups--&gt;
        &lt;div style=&quot;position: absolute; left: -5000px;&quot; aria-hidden=&quot;true&quot;&gt;&lt;input type=&quot;text&quot; name=&quot;b_b1c1099bf7f49b95c64107c99_6a5eb68eb7&quot; tabindex=&quot;-1&quot; value=&quot;&quot; /&gt;&lt;/div&gt;
        &lt;div class=&quot;clear&quot;&gt;&lt;input type=&quot;submit&quot; value=&quot;Subscribe&quot; name=&quot;subscribe&quot; id=&quot;mc-embedded-subscribe&quot; class=&quot;button&quot; /&gt;&lt;/div&gt;
        &lt;/div&gt;
    &lt;/form&gt;
&lt;/div&gt;

&lt;!--End mc_embed_signup--&gt;

&lt;h2 id=&quot;addorupdate&quot;&gt;AddOrUpdate&lt;/h2&gt;
&lt;p&gt;As the name suggests it enables to create or update a recurring job. Without further ado let’s look at the overrides, because there are a few of them:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    
    &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;AddOrUpdate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Expression&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;methodCall&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cronExpression&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TimeZoneInfo&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;timeZone&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;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;queue&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;default&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;AddOrUpdate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Expression&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;methodCall&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cronExpression&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TimeZoneInfo&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;timeZone&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;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;queue&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;default&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    
    &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;AddOrUpdate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Expression&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;methodCall&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cronExpression&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TimeZoneInfo&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;timeZone&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;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;queue&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;default&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;AddOrUpdate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Expression&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;methodCall&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cronExpression&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TimeZoneInfo&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;timeZone&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;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;queue&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;default&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    
    &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;AddOrUpdate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;recurringJobId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Expression&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;methodCall&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cronExpression&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TimeZoneInfo&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;timeZone&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;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;queue&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;default&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;AddOrUpdate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;recurringJobId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Expression&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;methodCall&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cronExpression&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TimeZoneInfo&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;timeZone&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;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;queue&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;default&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    
    &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;AddOrUpdate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;recurringJobId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Expression&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;methodCall&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cronExpression&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TimeZoneInfo&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;timeZone&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;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;queue&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;default&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;AddOrUpdate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;recurringJobId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Expression&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;methodCall&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cronExpression&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TimeZoneInfo&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;timeZone&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;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;queue&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;default&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;AddOrUpdate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;recurringJobId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Expression&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;methodCall&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cronExpression&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TimeZoneInfo&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;timeZone&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;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;queue&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;default&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;AddOrUpdate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;recurringJobId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Expression&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;methodCall&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cronExpression&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TimeZoneInfo&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;timeZone&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;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;queue&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;default&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;AddOrUpdate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;recurringJobId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Expression&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;methodCall&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cronExpression&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TimeZoneInfo&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;timeZone&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;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;queue&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;default&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;AddOrUpdate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;recurringJobId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Expression&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;methodCall&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cronExpression&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TimeZoneInfo&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;timeZone&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;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;queue&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;default&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The total count is twelve functions, so what exactly differentiates then?&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;generic vs. nongeneric&lt;/li&gt;
  &lt;li&gt;requiring or not job Id. When using the overload without id, one will be generated as a concatenation of object type name and method called.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;p&gt;From my personal experience specifying the id is a better practice. It makes code refactoring easier because we don’t have to worry that we will lose the ability to alter the job because of refactored name.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
  &lt;li&gt;cron expression passed as a string or as a function returning a string (string vs. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Func&amp;lt;string&amp;gt;&lt;/code&gt;). I personally don’t see the use case for a function returning a string cron expression, but maybe it will be useful to someone.&lt;/li&gt;
  &lt;li&gt;enabling scheduling synchronous or asynchronous jobs (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Expression&amp;lt;Action&amp;gt;&lt;/code&gt; vs. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Expression&amp;lt;Func&amp;lt;Task&amp;gt;&amp;gt;&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Expression&amp;lt;Action&amp;lt;T&amp;gt;&amp;gt;&lt;/code&gt; vs. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Expression&amp;lt;Func&amp;lt;T,Task&amp;gt;&amp;gt;&lt;/code&gt; for generic overrides)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They all have:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TimeZoneInfo&lt;/code&gt; -  because knowing the timezone is important when talking about hours&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;string queue&lt;/code&gt; - as the name suggests jobs can be scheduled onto different queues, but I will leave it for now since it will be covered in future posts.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;trigger&quot;&gt;Trigger&lt;/h2&gt;
&lt;p&gt;With function signature looking like:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Trigger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;recurringJobId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;There is no doubt what it does - triggers the job. This of curse does not influence next scheduled triggering since they are scheduled in absolute time, not relative from the last execution.&lt;/p&gt;

&lt;h2 id=&quot;removeifexists&quot;&gt;RemoveIfExists&lt;/h2&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;RemoveIfExists&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;recurringJobId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Not much to say. It removes a scheduled job. Again, the job has to have an id. And it will remove only the trigger. Any enqueued jobs will execute.&lt;/p&gt;

&lt;h2 id=&quot;corner-cases&quot;&gt;Corner cases&lt;/h2&gt;

&lt;h3 id=&quot;what-happens-if-i-schedule-the-job-to-start-in-the-past&quot;&gt;What happens if I schedule the job to start in the past?&lt;/h3&gt;
&lt;p&gt;The job will be triggered when the next interval happens. Past jobs won’t be queued.&lt;/p&gt;

&lt;h3 id=&quot;what-happens-if-during-the-time-the-job-should-be-triggered-there-was-no-processing-server&quot;&gt;What happens if during the time the job should be triggered there was no processing server?&lt;/h3&gt;
&lt;p&gt;It depends:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;if the job was enqueued at least once and during downtime it should be triggered, then it will be enqueued.&lt;/li&gt;
  &lt;li&gt;if there was never any triggering, it will be triggered next time in the future according to cron expression.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This logic is in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TryScheduleJob&lt;/code&gt; function in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RecurringJobScheduler&lt;/code&gt;.&lt;/p&gt;

&lt;h3 id=&quot;what-is-the-minimal-precision-for-triggering-a-job&quot;&gt;What is the minimal precision for triggering a job?&lt;/h3&gt;
&lt;p&gt;One minute. It is achieved by a busy with a one-second sleep wait in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;EveryMinuteThrottler&lt;/code&gt;.&lt;/p&gt;
</description>
        <pubDate>Wed, 07 Sep 2016 00:00:00 +0200</pubDate>
        <link>https://IndexOutOfRange.com//Don't-do-it-now!-Part-6.-Hangfire-recurring-jobs/</link>
        <guid isPermaLink="true">https://IndexOutOfRange.com//Don't-do-it-now!-Part-6.-Hangfire-recurring-jobs/</guid>
      </item>
    
      <item>
        <title>Don't do it now! Part 5. Hangfire details - job continuation with ContinueWith</title>
        <description>&lt;img src='https://indexoutofrange.com/data/2016-08-30-Dont-do-it-now!Part-5.Hangfire-job-continuation,-ContinueWith/logo.jpg' /&gt;&lt;p&gt;&lt;a href=&quot;/Don't-do-it-now!-Part-3.-Hangfire-details-jobs/&quot;&gt;Previous post&lt;/a&gt; covered almost all functions in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BackgroundJob&lt;/code&gt; class except for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ContinueWith&lt;/code&gt; functions family. So here we go :)&lt;/p&gt;

&lt;p&gt;The fact that it has the same name as a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;System.Threading.Tasks.Task&lt;/code&gt; function is not without a coincidence, or at least I hope so. This method allows chaining jobs where one will be enqueued when the previous finishes. To repeat - the job won’t be executed, but enqueued. So it will go at the end of the queue.
So lets look at the function and overrides signature:
&lt;!--MORE--&gt;&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ContinueWith&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parentId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Expression&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;methodCall&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ContinueWith&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parentId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Expression&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;methodCall&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;JobContinuationOptions&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ContinueWith&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parentId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Expression&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;methodCall&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;JobContinuationOptions&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;JobContinuationOptions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OnlyOnSucceededState&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;    
&lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ContinueWith&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parentId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Expression&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;methodCall&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ContinueWith&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parentId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Expression&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;methodCall&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;JobContinuationOptions&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ContinueWith&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parentId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Expression&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;methodCall&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;JobContinuationOptions&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;JobContinuationOptions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OnlyOnSucceededState&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The API enables to fire multiple methods when one finishes, but not doing the opposite. This scenario was recently covered by &lt;a href=&quot;http://docs.hangfire.io/en/latest/background-methods/using-batches.html&quot;&gt;Batches&lt;/a&gt;, but it is a topic for a separate post, and they are available only in the paid version. So let’s have a look at the function and their overrides:&lt;/p&gt;

&lt;p&gt;So let’s look at what differentiates the overrides:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;generic vs. nongeneric&lt;/li&gt;
  &lt;li&gt;synchronous vs. asynchronous. This time, they are not exactly equal because methods differ in the fact that there are two versions for the synchronous override. One with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;JobContinuationOptions&lt;/code&gt; and one without. The asynchronous only has one with default initialization. This was probably done to keep backward compatibility (reflection, assembly binding), and since &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async&lt;/code&gt; support was implemented after &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ContinueWith&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We looked at the differences, let’s look at the similarities:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;parentId&lt;/code&gt; - remember the unique job id returned by all the functions from &lt;a href=&quot;/Don't-do-it-now!-Part-3.-Hangfire-details-jobs/&quot;&gt;enqueue part of the API&lt;/a&gt;? This is one of the cases when it comes in handy.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;JobContinuationOptions&lt;/code&gt; - this is an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;enum&lt;/code&gt; and has two options:
    &lt;ul&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OnAnyFinishedState&lt;/code&gt; - the default one, meaning the job will execute regardless of whatever parent finishes with success, or throws an error.&lt;/li&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OnlyOnSucceededState&lt;/code&gt; - the job will fire only when parent succeeded (didn’t throw any exception, or didn’t timeout)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;the return value is of curse a unique job id, so we can chain many jobs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Continuation can introduce some edge cases, here are those came into my mind:&lt;/p&gt;
&lt;h3 id=&quot;will-continuations-be-executed-once-more-if-we-enqueue-the-parent-job-that-ended-successfully&quot;&gt;Will continuations be executed once more if we enqueue the parent job that ended successfully?&lt;/h3&gt;
&lt;p&gt;The short answer is no. Continuation jobs will be enqueued only if they are in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AwaitingState&lt;/code&gt; (special state for continuation jobs in Hangfire state machine).&lt;/p&gt;

&lt;h3 id=&quot;what-happens-to-continuations-scheduled-to-execute-on-success-when-the-parent-fails-and-after-retry-succeeded&quot;&gt;What happens to continuations scheduled to execute on success when the parent fails and after retry succeeded?&lt;/h3&gt;
&lt;p&gt;To put it simply: is it possible for the parent job to finish and not enqueue continuations?
No. They are done in one transaction.&lt;/p&gt;

&lt;h3 id=&quot;what-if-we-continue-on-a-job-that-already-executed&quot;&gt;What if we continue on a job that already executed?&lt;/h3&gt;
&lt;p&gt;Continuations will be enqueued immediately.&lt;/p&gt;

&lt;h3 id=&quot;why-should-i-use-continuewith-if-i-can-enqueue-continuation-job-at-the-end-of-parent-job&quot;&gt;Why should I use ContinueWith if I can enqueue continuation job at the end of parent job?&lt;/h3&gt;
&lt;p&gt;To keep the code clean. Hangfire is just a way to execute functions, and in most cases, there is no need for it know, is it running from Hangfire or from a web request. It is just a matter of keeping code clean.&lt;/p&gt;

&lt;h3 id=&quot;can-a-parent-job-pass-parameters-to-continuations&quot;&gt;Can a parent job pass parameters to continuations?&lt;/h3&gt;
&lt;p&gt;No. If that’s the case I would recommend &lt;a href=&quot;https://msdn.microsoft.com/en-us/library/hh228603(v=vs.110).aspx&quot;&gt;TPL Dataflow&lt;/a&gt; or some agent system like &lt;a href=&quot;http://getakka.net/&quot;&gt;Akka.NET&lt;/a&gt; or &lt;a href=&quot;https://github.com/dotnet/orleans&quot;&gt;Orleans&lt;/a&gt;. Another option is to enqueue the child job at the end of parent job, but this can get messy.&lt;/p&gt;
</description>
        <pubDate>Tue, 30 Aug 2016 00:00:00 +0200</pubDate>
        <link>https://IndexOutOfRange.com//Don't-do-it-now!-Part-5.-Hangfire-job-continuation,-ContinueWith/</link>
        <guid isPermaLink="true">https://IndexOutOfRange.com//Don't-do-it-now!-Part-5.-Hangfire-job-continuation,-ContinueWith/</guid>
      </item>
    
      <item>
        <title>Don't do it now! Part 4. Hangfire details - dashboard, retries and job cancellation</title>
        <description>&lt;img src='https://indexoutofrange.com/data/2016-08-22-Dont-do-it-now!-Part-4.Hangfire-details-dashboard,retries-and-job-cancellation/logo.png' /&gt;&lt;p&gt;This part will cover few small topics:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;dashboard&lt;/li&gt;
  &lt;li&gt;retries&lt;/li&gt;
  &lt;li&gt;more technical part of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Hangfire.BackgroundJob&lt;/code&gt; class API&lt;/li&gt;
  &lt;li&gt;job cancellation
&lt;!--MORE--&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;dashboard&quot;&gt;Dashboard&lt;/h2&gt;
&lt;p&gt;Let’s start with the administrative dashboard because it gives a good background for the rest of the post.
It greets us with more or less this view:
&lt;img src=&quot;/data/2016-08-22-Dont-do-it-now!-Part-4.Hangfire-details-dashboard,retries-and-job-cancellation/dashboard_main.png&quot; alt=&quot;dashboard Main&quot; /&gt;
This is the main view of what the server is doing, and how well (are the jobs failing)
The more interesting part is the next view:
&lt;img src=&quot;/data/2016-08-22-Dont-do-it-now!-Part-4.Hangfire-details-dashboard,retries-and-job-cancellation/dashboard_jobs.png&quot; alt=&quot;dashboard Main&quot; /&gt;
There’s a bit more detail about jobs in all states. They are self explanatory, maybe except the awaiting, but I will cover this in the next post.
We can go as deep as the state of the specific job, which will look like this:
&lt;img src=&quot;/data/2016-08-22-Dont-do-it-now!-Part-4.Hangfire-details-dashboard,retries-and-job-cancellation/dashboard_failedJob.png&quot; alt=&quot;dashboard Main&quot; /&gt;&lt;/p&gt;

&lt;p&gt;And this brings us to the main motives of this post:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;auto retries&lt;/li&gt;
  &lt;li&gt;the ability to requeue a job&lt;/li&gt;
  &lt;li&gt;the ability to delete a job&lt;/li&gt;
  &lt;li&gt;job cancellation&lt;/li&gt;
&lt;/ul&gt;

&lt;!-- Begin MailChimp Signup Form --&gt;

&lt;link href=&quot;//cdn-images.mailchimp.com/embedcode/horizontal-slim-10_7.css&quot; rel=&quot;stylesheet&quot; type=&quot;text/css&quot; /&gt;

&lt;style type=&quot;text/css&quot;&gt;
	#mc_embed_signup{
        clear:left; 
        font:14px Helvetica,Arial,sans-serif; 
        width:100%; 
        margin-top: 40px;
        margin-bottom: 40px;
        height:100px;
    }
    #mc_embed_signup .newsletter div{
        height: 100px;
    }
    #mc_embed_signup form{
        position: relative;
        top: -90px;
    }
	/* Add your own MailChimp form style overrides in your site stylesheet or in this style block.
	   We recommend moving this block and the preceding CSS link to the HEAD of your HTML file. */
&lt;/style&gt;

&lt;div id=&quot;mc_embed_signup&quot;&gt;
    &lt;div class=&quot;gradient newsletter&quot;&gt;
        &lt;div style=&quot;background:#000000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#1C0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#380000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#550000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#710000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#8D0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#AA0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#C60000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#E20000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF3800&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF5500&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF7100&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF8D00&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFAA00&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFC600&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFE200&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFFF00&quot;&gt;&lt;/div&gt;
    &lt;/div&gt;
    &lt;form action=&quot;https://IndexOutOfRange.us15.list-manage.com/subscribe/post?u=b1c1099bf7f49b95c64107c99&amp;amp;id=6a5eb68eb7&quot; method=&quot;post&quot; id=&quot;mc-embedded-subscribe-form&quot; name=&quot;mc-embedded-subscribe-form&quot; class=&quot;validate&quot; target=&quot;_blank&quot; novalidate=&quot;&quot;&gt;
        &lt;div id=&quot;mc_embed_signup_scroll&quot;&gt;
        &lt;label for=&quot;mce-EMAIL&quot; style=&quot;color: white;&quot;&gt;Get email notifications about new posts:&lt;/label&gt;
        &lt;input type=&quot;email&quot; value=&quot;&quot; name=&quot;EMAIL&quot; class=&quot;email&quot; id=&quot;mce-EMAIL&quot; placeholder=&quot;email address&quot; required=&quot;&quot; /&gt;
        &lt;!-- real people should not fill this in and expect good things - do not remove this or risk form bot signups--&gt;
        &lt;div style=&quot;position: absolute; left: -5000px;&quot; aria-hidden=&quot;true&quot;&gt;&lt;input type=&quot;text&quot; name=&quot;b_b1c1099bf7f49b95c64107c99_6a5eb68eb7&quot; tabindex=&quot;-1&quot; value=&quot;&quot; /&gt;&lt;/div&gt;
        &lt;div class=&quot;clear&quot;&gt;&lt;input type=&quot;submit&quot; value=&quot;Subscribe&quot; name=&quot;subscribe&quot; id=&quot;mc-embedded-subscribe&quot; class=&quot;button&quot; /&gt;&lt;/div&gt;
        &lt;/div&gt;
    &lt;/form&gt;
&lt;/div&gt;

&lt;!--End mc_embed_signup--&gt;

&lt;h2 id=&quot;auto-retry&quot;&gt;Auto retry&lt;/h2&gt;
&lt;p&gt;This one is easy. Hangfire will auto retry every job that failed (timeouted or thrown an exception) configurable &lt;a href=&quot;http://docs.hangfire.io/en/latest/background-processing/dealing-with-exceptions.html&quot;&gt;amount of times&lt;/a&gt; (10 by default). Each retry is an equivalent to normal enqueuing, so it lands at the end of the queue.&lt;/p&gt;

&lt;h2 id=&quot;manual-requeue&quot;&gt;Manual requeue&lt;/h2&gt;
&lt;p&gt;This can be done in several ways:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;on the job page&lt;/li&gt;
  &lt;li&gt;on the jobs page (allows requeuing multiple jobs).&lt;/li&gt;
  &lt;li&gt;manually using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Requeue&lt;/code&gt; from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Hangfire.BackgroundJob&lt;/code&gt; :&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Requeue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;jobId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Requeue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;jobId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fromState&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Remember the unique job id returned by schedule methods from &lt;a href=&quot;/Don't-do-it-now!-Part-3.-Hangfire-details-jobs/&quot;&gt;previous post&lt;/a&gt;? This is one of the places where it becomes useful. The overload has an additional parameter, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fromState&lt;/code&gt; which is a fail switch. Job will be deleted only if it is in this exact state.&lt;/p&gt;

&lt;h2 id=&quot;delete-a-job&quot;&gt;Delete a job&lt;/h2&gt;
&lt;p&gt;A similar story to requeuing. It can be done from the UI or with the API:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Delete&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;jobId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Delete&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;jobId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fromState&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;No surprises here. The API is very similar as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Requeue&lt;/code&gt;.
This would seem to end the topic of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Delete&lt;/code&gt;, but one very important question should pop into Your mind:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Just how does Hangfire delete a job?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This question becomes even more interesting when:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;we look at &lt;a href=&quot;http://docs.hangfire.io/en/latest/background-methods/using-cancellation-tokens.html&quot;&gt;IJobCancellationToken in the documentation&lt;/a&gt;, which means cancellation is supported.&lt;/li&gt;
  &lt;li&gt;we see that Hangfire is using &lt;a href=&quot;https://msdn.microsoft.com/en-us/library/system.threading.cancellationtoken&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;System.Threading.CancellationToken&lt;/code&gt;&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;we take into account that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Delate&lt;/code&gt; may be called from a &lt;strong&gt;different machine&lt;/strong&gt; than currently executing the job.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;job-cancellation&quot;&gt;Job cancellation&lt;/h2&gt;

&lt;p&gt;Cancellation can be triggered by two events (and both of the handle it differently):&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Server shut down&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BackgroundJobServer&lt;/code&gt;(&lt;a href=&quot;https://github.com/HangfireIO/Hangfire/blob/master/src/Hangfire.Core/Server/BackgroundProcessingServer.cs&quot;&gt;github&lt;/a&gt;), which is responsible for job execution, is being shut down, it stops processing new messages and triggers &lt;a href=&quot;https://msdn.microsoft.com/en-us/library/dd321955(v=vs.110).aspx&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Cancel&lt;/code&gt;&lt;/a&gt; on its &lt;a href=&quot;https://msdn.microsoft.com/en-us/library/system.threading.cancellationtokensource%28v=vs.110%29.aspx?f=255&amp;amp;MSPPError=-2147217396&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CancellationTokenSource&lt;/code&gt;&lt;/a&gt;. This token is used by the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Worker&lt;/code&gt;(&lt;a href=&quot;https://github.com/HangfireIO/Hangfire/blob/master/src/Hangfire.Core/Server/Worker.cs&quot;&gt;github&lt;/a&gt;)  class to create the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ServerJobCancellationToken&lt;/code&gt; (&lt;a href=&quot;https://github.com/HangfireIO/Hangfire/blob/master/src/Hangfire.Core/ServerJobCancellationToken.cs&quot;&gt;github&lt;/a&gt;) instance that will be injected into the method if it has a parameter of type &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IJobCancellationToken&lt;/code&gt;. Calling &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ThrowIfCancellationRequested&lt;/code&gt; on it, checks the token and throws &lt;a href=&quot;https://msdn.microsoft.com/en-us/library/system.operationcanceledexception(v=vs.110).aspx&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OperationCanceledException&lt;/code&gt;&lt;/a&gt;. This exception is recognised as finishing due to issued cancellation. This way the server can gently close currently processing jobs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Job deletetion (job cancellation)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Delete&lt;/code&gt; method uses the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IBackgroundJobStateChanger&lt;/code&gt; (&lt;a href=&quot;https://github.com/HangfireIO/Hangfire/blob/master/src/Hangfire.Core/States/IBackgroundJobStateChanger.cs&quot;&gt;github&lt;/a&gt;), implemented by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BackgroundJobStateChanger&lt;/code&gt;(&lt;a href=&quot;https://github.com/HangfireIO/Hangfire/blob/master/src/Hangfire.Core/States/BackgroundJobStateChanger.cs&quot;&gt;github&lt;/a&gt;), to change the state of the job to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Deleted&lt;/code&gt; and write it to storage. On this its responsibility finishes.&lt;/p&gt;

&lt;p&gt;The rest of the cancellation logic is done in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ThrowIfCancellationRequested&lt;/code&gt; in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ServerJobCancellationToken&lt;/code&gt;(&lt;a href=&quot;https://github.com/HangfireIO/Hangfire/blob/master/src/Hangfire.Core/ServerJobCancellationToken.cs&quot;&gt;github&lt;/a&gt;)&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&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;ThrowIfCancellationRequested&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;_shutdownToken&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ThrowIfCancellationRequested&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;nf&quot;&gt;IsJobAborted&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;throw&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;JobAbortedException&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;/div&gt;

&lt;p&gt;The first line is checking the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CancellationToken&lt;/code&gt; mentioned in server shut down case. The second gets the job state from the database and checks if there were any state changes indicating whether it should be cancelled (like changing the state by calling &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Delete&lt;/code&gt;). If yes, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;JobAbortedException&lt;/code&gt;(&lt;a href=&quot;https://github.com/HangfireIO/Hangfire/blob/master/src/Hangfire.Core/Server/JobAbortedException.cs&quot;&gt;github&lt;/a&gt;) exception is being thrown. This exception is handled in a very similar way as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OperationCanceledException&lt;/code&gt; (from which it inherits) and also will be recognised as a indication of finishing due to issued cancellation.&lt;/p&gt;
</description>
        <pubDate>Mon, 22 Aug 2016 00:00:00 +0200</pubDate>
        <link>https://IndexOutOfRange.com//Don't-do-it-now!-Part-4.-Hangfire-details-dashboard,-retries-and-job-cancellation/</link>
        <guid isPermaLink="true">https://IndexOutOfRange.com//Don't-do-it-now!-Part-4.-Hangfire-details-dashboard,-retries-and-job-cancellation/</guid>
      </item>
    
      <item>
        <title>Don't do it now! Part 3. Hangfire details - jobs</title>
        <description>&lt;img src='https://indexoutofrange.com/data/2016-08-17-Dont-do-it-now!Part-3.Hangfire-details-jobs/logo.jpg' /&gt;&lt;p&gt;This part will focus on the basic scheduling API of Hangfire.
The easiest way to create a fire and forget job is by using the class&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Hangfire.BackgroundJob&lt;/code&gt; and its minimalistic  (and this is a complement) API of static functions:
&lt;!--MORE--&gt;&lt;/p&gt;

&lt;h2 id=&quot;enqueue&quot;&gt;Enqueue&lt;/h2&gt;
&lt;p&gt;As the name suggests it is &lt;strong&gt;the&lt;/strong&gt; method for enqueuing jobs. It comes in different overrides:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Enqueue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Expression&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;methodCall&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Enqueue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Expression&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;methodCall&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Enqueue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Expression&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;methodCall&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Enqueue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Expression&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;methodCall&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Two of them are non generic implementations of the generic version, so it comes down to whatever we want to:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;schedule an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async&lt;/code&gt; function &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Func&amp;lt;T, Task&amp;gt;&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;schedule a synchronous function &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Action&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What will be important further on is that all this methods return a string which is a unique identifier of the job. It will come in handy in the next posts.&lt;/p&gt;

&lt;h2 id=&quot;schedule&quot;&gt;Schedule&lt;/h2&gt;
&lt;p&gt;As the name suggests - it allows to enqueue a job, but delay its execution by some time period. The overrides are:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Schedule&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Expression&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;methodCall&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;DateTimeOffset&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;enqueueAt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Schedule&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Expression&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;methodCall&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TimeSpan&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;delay&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Schedule&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Expression&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;methodCall&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;DateTimeOffset&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;enqueueAt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Schedule&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Expression&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;methodCall&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TimeSpan&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;delay&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Schedule&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Expression&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;methodCall&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;DateTimeOffset&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;enqueueAt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Schedule&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Expression&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;methodCall&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TimeSpan&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;delay&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Schedule&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Expression&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;methodCall&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TimeSpan&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;delay&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Schedule&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Expression&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;methodCall&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;DateTimeOffset&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;enqueueAt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;A few overrides, but it boils down to:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;generic or nongeneric version&lt;/li&gt;
  &lt;li&gt;asynchronous vs. synchronous (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Func&amp;lt;T, Task&amp;gt;&lt;/code&gt; vs. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Action&amp;lt;T&amp;gt;&lt;/code&gt;)&lt;/li&gt;
  &lt;li&gt;delay it by a period from now, or execute it at specific time in future (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TimeSpan delay&lt;/code&gt; vs. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DateTimeOffset&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Similar to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Enqueue&lt;/code&gt; this functions also returns a string identifier of a job.&lt;/p&gt;

&lt;p&gt;This two function are enough to start to worry about corner cases when using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SqlServerStorage&lt;/code&gt; (probably the most common usage), so here we go:&lt;/p&gt;

&lt;h2 id=&quot;corner-cases&quot;&gt;Corner cases&lt;/h2&gt;

&lt;h3 id=&quot;does-hangfire-using-sqlserver-storage-requires-an-opened-transaction&quot;&gt;Does Hangfire using SQLServer storage requires an opened transaction?&lt;/h3&gt;
&lt;p&gt;No Hangfire will create its own transaction scope and manage it. Code handling it an be found in &lt;a href=&quot;https://github.com/HangfireIO/Hangfire/blob/master/src/Hangfire.SqlServer/SqlServerStorage.cs&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Hangfire.SqlServer.SqlServerStorage.CreateTransaction&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;if-there-is-an-opened-transaction-will-hangfire-use-it&quot;&gt;If there is an opened transaction will Hangfire use it?&lt;/h3&gt;
&lt;p&gt;Yes Hangfire will enlist to an opened transaction, and use it. This means that the job will be enqueued only if rest of the process succeeded and we commit the transaction.&lt;/p&gt;

&lt;h3 id=&quot;does-hangfie-using-sqlserver-storage-support-distributed-transactions&quot;&gt;Does Hangfie using SQLServer storage support &lt;a href=&quot;https://en.wikipedia.org/wiki/Distributed_transaction&quot;&gt;distributed transactions&lt;/a&gt;?&lt;/h3&gt;
&lt;p&gt;Yes. Again the code can be found in &lt;a href=&quot;https://github.com/HangfireIO/Hangfire/blob/master/src/Hangfire.SqlServer/SqlServerStorage.cs&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Hangfire.SqlServer.SqlServerStorage.CreateTransaction&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;can-i-rely-on-object-state&quot;&gt;Can I rely on object state?&lt;/h3&gt;
&lt;p&gt;No. Only things being serialized are:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;object type&lt;/li&gt;
  &lt;li&gt;called method&lt;/li&gt;
  &lt;li&gt;passed parameters&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This means that we can’t rely on any state that the object had at the time of scheduling its function because it won’t be recreated. This is why I wrote that Hangfire enables to schedule &lt;em&gt;functions&lt;/em&gt;. Because in C# functions aren’t &lt;a href=&quot;https://en.wikipedia.org/wiki/First-class_citizen&quot;&gt;first class citizens&lt;/a&gt;, but they are tied to a object instance you have to be more careful. To give an example of how a “Hello world” job looks in storage:&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;  
   &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;Type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;System.Console, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
   &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;Method&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;WriteLine&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
   &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;ParameterTypes&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;[&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;]&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
   &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;Arguments&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;[&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;\\\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Hello, world!&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\\&quot;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;]&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Based on this info Hangfire will recreate the object and execute the function. This also brings us to a small performance tip to keep in mind: 
&lt;strong&gt;keep your parameters small, and be sure to know how they will be serialized&lt;/strong&gt;&lt;/p&gt;
</description>
        <pubDate>Wed, 17 Aug 2016 00:00:00 +0200</pubDate>
        <link>https://IndexOutOfRange.com//Don't-do-it-now!-Part-3.-Hangfire-details-jobs/</link>
        <guid isPermaLink="true">https://IndexOutOfRange.com//Don't-do-it-now!-Part-3.-Hangfire-details-jobs/</guid>
      </item>
    
      <item>
        <title>Don't do it now! Part 2. Background tasks, job queuing and scheduling with Hangfire</title>
        <description>&lt;img src='https://indexoutofrange.com/data/2016-08-10-Dont-do-it-now!Part-2.Background-tasks-job-queuing-and-scheduling-with-Hangfire/logo.png' /&gt;&lt;p&gt;In the &lt;a href=&quot;/Don't-do-it&quot;&gt;previous post&lt;/a&gt; I’ve written about why I think the ability to schedule tasks for later execution is a fundamental technical feature, but also a must have from business’ point of view.
We are passed the &lt;em&gt;whys&lt;/em&gt;, so let’s get to the &lt;em&gt;hows&lt;/em&gt;. The answer is simple - Hangfire. I’ve written about it &lt;a href=&quot;http://indexoutofrange.com/GC-can-kill-You-Practical-GC-performance-counters-in-NET/&quot;&gt;here&lt;/a&gt;, &lt;a href=&quot;http://indexoutofrange.com/LocalOptimizationsDontAddUp/&quot;&gt;here&lt;/a&gt; and &lt;a href=&quot;http://indexoutofrange.com/How-is-cookit-build/&quot;&gt;here&lt;/a&gt;, so yeah, you guessed it, I like it.  Hangfire is an amazing library. It has shown it’s value in my pet project (&lt;a href=&quot;http://cookit.pl&quot;&gt;cookit.pl&lt;/a&gt;) and in a huge ERP system that we are building at work, where we replaced &lt;a href=&quot;http://www.quartz-scheduler.net/&quot;&gt;Quartz.NET&lt;/a&gt; with it and never looked back. 
&lt;!--MORE--&gt;&lt;/p&gt;

&lt;p&gt;Why do I like it so much?&lt;/p&gt;

&lt;h2 id=&quot;1-scheduling&quot;&gt;1. Scheduling&lt;/h2&gt;
&lt;p&gt;It enables:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;to fire(enqueue) and forget a job:&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;	&lt;span class=&quot;n&quot;&gt;BackgroundJob&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Enqueue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;WriteLine&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Simple!&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;to schedule a one time job using a cron expression&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;	&lt;span class=&quot;n&quot;&gt;BackgroundJob&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Schedule&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;WriteLine&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Reliable!&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TimeSpan&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;FromDays&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;and to schedule a recurring job also with a cron expression&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;	&lt;span class=&quot;n&quot;&gt;RecurringJob&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;AddOrUpdate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;WriteLine&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Transparent!&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Cron&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Daily&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;blockquote&gt;
  &lt;p&gt;A side note: Cron expressions allow to express almost any time span, and using them is a standard in most task scheduling cases (&lt;a href=&quot;http://www.quartz-scheduler.net/&quot;&gt;Quartz.NET&lt;/a&gt;, Unix, &lt;a href=&quot;https://www.jetbrains.com/teamcity/&quot;&gt;TeamCity&lt;/a&gt; to name a few). There is a good &lt;a href=&quot;https://en.wikipedia.org/wiki/Cron#CRON_expression&quot;&gt;Wikipedia page explaining the syntax&lt;/a&gt;. Think of them as regular expressions for time.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I personally fell in love with the simplicity of this API, and especially with the fact that it takes a function to execute, not an object. Although this examples are simple lambdas Hangfire allows to schedule executing methods on almost any objects, but this is a topic for another post. Probably the next one:)&lt;/p&gt;

&lt;h2 id=&quot;2-persistence&quot;&gt;2. Persistence&lt;/h2&gt;
&lt;p&gt;The key point in procrastinating tasks is to not do them now, but to have certainty that they will be executed. That is why persisting jobs in a database is a key feature. And Hangfire has a hand of stores to persist in:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;SQL Server (&lt;a href=&quot;Install-Package Hangfire.SqlServer&quot;&gt;nuget package&lt;/a&gt;)&lt;/li&gt;
  &lt;li&gt;PostgreSql (&lt;a href=&quot;postgres&quot;&gt;nuget package&lt;/a&gt;)&lt;/li&gt;
  &lt;li&gt;Redis (nuget package, but only in paid pro version)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And configuring any of them is as simple as scheduling a job:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;JobStorage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Current&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;nf&quot;&gt;SqlServerStorage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;HangfireConnectionString&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;3-job-execution&quot;&gt;3. Job execution&lt;/h2&gt;
&lt;p&gt;Persisting a job in a database gives the possibility for another process to execute it. And Hangfire does just that. Of course the process executing the job has to have all the assemblies needed to execute the code, but this is just another argument for not having everything jammed into one project. Hangfire can be hosted by a:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;console application&lt;/li&gt;
  &lt;li&gt;Windows service&lt;/li&gt;
  &lt;li&gt;IIS website&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And configuring it is as easy as scheduling a job:&lt;/p&gt;
&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;GlobalConfiguration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Configuration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;UseSqlServerStorage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;HangfireConnectionString&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;using&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;server&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;nf&quot;&gt;BackgroundJobServer&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;Console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;WriteLine&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Hangfire Server started. Press any key to exit...&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ReadKey&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;/div&gt;

&lt;h2 id=&quot;4-monitoring&quot;&gt;4. Monitoring&lt;/h2&gt;
&lt;p&gt;For me the ability to have a graphic interface to see current jobs, queues, errors and processing servers was a must-have when choosing a library for a simple reason - I needed it and didn’t want to write it myself. And Hangfire has just that:
&lt;img src=&quot;/data/LocalOptimizationsDontAddUp/HangfireDashboard.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The dashboard is fully served be Hangfire (there is no need to add any CSS or JavaScript files) and configuring it is a one liner extension on OWIN IAppBuilder:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;	&lt;span class=&quot;n&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;UseHangfireDashboard&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This was a glimpse of what this library can do. It’s not always bells and whistles, but I’ve never regretted choosing it can’t imagine working without the ability to schedule tasks. 
In the next post - a better look into jobs.&lt;/p&gt;
</description>
        <pubDate>Mon, 08 Aug 2016 00:00:00 +0200</pubDate>
        <link>https://IndexOutOfRange.com//Don't-do-it-now!-Part-2.-Background-tasks,-job-queuing-and-scheduling-with-Hangfire/</link>
        <guid isPermaLink="true">https://IndexOutOfRange.com//Don't-do-it-now!-Part-2.-Background-tasks,-job-queuing-and-scheduling-with-Hangfire/</guid>
      </item>
    
      <item>
        <title>Don't do it now.</title>
        <description>&lt;img src='https://indexoutofrange.com/data/2016-07-28-Dont_do_it/logo.jpg' /&gt;&lt;p&gt;This is a post about the importance of not doing stuff right here and right now. About doing stuff later, delaying them and in a perfect world making someone else do them. But I will still stick to IT, don’t expect any life tips or guidance.&lt;/p&gt;

&lt;p&gt;A mindset I see constantly in system design is doing the right thing right now, and even more stuff after that. Like sending an email, doing a REST call, performing some CPU intense calculations, calling an external resource. We are doing those things where they should be from the logical point of view. So, if we are given a task like registering an user that sound more or less like that:
&lt;!--MORE--&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&quot;Verify the required fields, check if a user with such email doesn't exist if everything is OK save it to the database, and send an confirmation email.&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We will:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;verify required fields&lt;/li&gt;
  &lt;li&gt;check for a duplicate&lt;/li&gt;
  &lt;li&gt;save it to the database&lt;/li&gt;
  &lt;li&gt;send the confirmation email&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And for me this is insane and even more - wrong. Wrong as not implementing what the requirement told. For me it should be:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;verify required fields&lt;/li&gt;
  &lt;li&gt;check for a duplicate&lt;/li&gt;
  &lt;li&gt;save it to the database&lt;/li&gt;
  &lt;li&gt;schedule sending the confirmation email&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Did you spot the difference? It is in the last step. My point is that we should &lt;strong&gt;schedule&lt;/strong&gt; sending the email and not send it. Why schedule not do it now? There are many reasons, but to name a few:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;in a web application it makes the request faster (scheduling is faster then sending an email)&lt;/li&gt;
  &lt;li&gt;processing of jobs can be done on different server.&lt;/li&gt;
  &lt;li&gt;it is easy to scale job processing servers&lt;/li&gt;
  &lt;li&gt;it is more fail resilient (easy to retry)&lt;/li&gt;
  &lt;li&gt;it allows to batch operations&lt;/li&gt;
  &lt;li&gt;it is easier to monitor&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But for me there is also a bigger point to make here. I believe it is more tha	n a technical detail, or a performance enhancer. I think that only the second version is implementing the requirement properly. This is because failure to send the email &lt;em&gt;now&lt;/em&gt; should not block the registration. It’s a technical problem, not a business one and it should be dealt with without the user knowing. Imagine getting an error from registering saying “SMTP port not responding”. Most of us will say, or I hope so at least, “This is obvious”. But most of us spend our days implementing more complicated processes, where it is not that obvious, and we don’t dare to ask:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&quot;Does it need to be done now? It is an integral part of the process? Do you need it in real time?&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Why? Maybe we feel it implies that the system isn’t fast enough or we can’t code it to work fast enough. Those may be, but my bet is on that &lt;strong&gt;we assume it is an integral part and we don’t ask&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;should the whole process fail if this part does?&lt;/li&gt;
  &lt;li&gt;can this action fail for any business reason?&lt;/li&gt;
  &lt;li&gt;how well should this scale? Long monolithic processes don’t scale.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you hear “Yes” to any of this questions then &lt;strong&gt;do it later&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Keep in mind that latency between scheduling a job and picking it up for execution shouldn’t be greater than 5 second for most cases, because then you are still in “real time” frame of most use cases.&lt;/p&gt;

</description>
        <pubDate>Sun, 24 Jul 2016 00:00:00 +0200</pubDate>
        <link>https://IndexOutOfRange.com//Don't-do-it/</link>
        <guid isPermaLink="true">https://IndexOutOfRange.com//Don't-do-it/</guid>
      </item>
    
      <item>
        <title>The cost of garbage collection. Part 2 - rectification.</title>
        <description>&lt;img src='https://indexoutofrange.com/data/2016-07-16-The-cost-of-garbage-collection.Part-2-rectification/logo.jpg' /&gt;&lt;p&gt;This is a rectification for the &lt;a href=&quot;/The-cost-of-garbage-collection/&quot;&gt;previous post about the cost of garbage collection&lt;/a&gt;. If You didn’t read it give it a try and check if You can spot the bug/mistake.&lt;/p&gt;

&lt;p&gt;Like &lt;a href=&quot;http://blog.kokosa.net/&quot;&gt;Konrad&lt;/a&gt; pointed out in &lt;a href=&quot;http://disq.us/p/1a0iccx&quot;&gt;his comment&lt;/a&gt; not all objects were in generation 0 as I assumed. This is partly connected to the fact that .NET, seeing rapid need for memory in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Setup&lt;/code&gt;, will try to collect some of them, calling garbage collection, but I make the matters worse by calling &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GC.Collect&lt;/code&gt; in the end. So making sure that objects created during &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Setup&lt;/code&gt; will be in generation 2 (in my defence it was left over after a bit different take on this problem).&lt;/p&gt;

&lt;p&gt;This is the proper code (it also was committed to the &lt;a href=&quot;https://github.com/maklipsa/CSharpPerfExperiments&quot;&gt;github repo&lt;/a&gt;):
&lt;!--MORE--&gt;&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;System.Collections.Generic&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;System.Diagnostics&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;System.Runtime.CompilerServices&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;NBench&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Tests&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;GCCollection&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;readonly&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_messages&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;&quot;Gen 0 ticks:       &quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;s&quot;&gt;&quot;Gen 0+1 ticks:     &quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;s&quot;&gt;&quot;Gen 0+1+2 ticks:   &quot;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;readonly&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_objectNumber&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1000&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;PerfSetup&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;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Setup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BenchmarkContext&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&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;Console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;WriteLine&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Objects generated.&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;nf&quot;&gt;GenerateObjects&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_objectNumber&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;GC&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Collect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GCCollectionMode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Forced&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;true&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;nf&quot;&gt;PerfBenchmark&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Description&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Gen 2 collection with nothing&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;NumberOfIterations&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;n&quot;&gt;RunMode&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RunMode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Iterations&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TestMode&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TestMode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Test&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;nf&quot;&gt;GcTotalAssertion&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GcMetric&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TotalCollections&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GcGeneration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Gen0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MustBe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ExactlyEqualTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;3d&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;nf&quot;&gt;GcTotalAssertion&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GcMetric&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TotalCollections&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GcGeneration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Gen1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MustBe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ExactlyEqualTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;2d&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;nf&quot;&gt;GcTotalAssertion&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GcMetric&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TotalCollections&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GcGeneration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Gen2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MustBe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ExactlyEqualTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1d&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;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Gen2CollectionWithNothing&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;GC&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Collect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GCCollectionMode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Forced&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;true&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;sw&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Stopwatch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;StartNew&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

            &lt;span class=&quot;nf&quot;&gt;RunGCAndCheck&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;span class=&quot;cm&quot;&gt;/* Run collect for gen 0 - collect everything.*/&lt;/span&gt;

            &lt;span class=&quot;nf&quot;&gt;RunGCAndCheck&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;n&quot;&gt;sw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;span class=&quot;cm&quot;&gt;/* Nothing should be here.*/&lt;/span&gt;

            &lt;span class=&quot;nf&quot;&gt;RunGCAndCheck&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;span class=&quot;cm&quot;&gt;/* Nothing should be here.*/&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;nf&quot;&gt;PerfBenchmark&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Description&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Gen 0 collection&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;NumberOfIterations&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;n&quot;&gt;RunMode&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RunMode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Iterations&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TestMode&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TestMode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Test&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;nf&quot;&gt;GcTotalAssertion&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GcMetric&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TotalCollections&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GcGeneration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Gen0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MustBe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ExactlyEqualTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1d&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;nf&quot;&gt;GcTotalAssertion&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GcMetric&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TotalCollections&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GcGeneration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Gen1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MustBe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ExactlyEqualTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0.0d&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;nf&quot;&gt;GcTotalAssertion&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GcMetric&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TotalCollections&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GcGeneration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Gen2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MustBe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ExactlyEqualTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0.0d&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;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Gen0Collection&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;list&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;GenerateObjects&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_objectNumber&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;list&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;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sw&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Stopwatch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;StartNew&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

            &lt;span class=&quot;nf&quot;&gt;RunGCAndCheck&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;span class=&quot;cm&quot;&gt;/* Run collect for gen 0 - collect everything.*/&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;nf&quot;&gt;PerfBenchmark&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Description&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Gen 1 collection&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;NumberOfIterations&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;n&quot;&gt;RunMode&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RunMode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Iterations&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TestMode&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TestMode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Test&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;nf&quot;&gt;GcTotalAssertion&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GcMetric&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TotalCollections&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GcGeneration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Gen0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MustBe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ExactlyEqualTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;2.0d&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;nf&quot;&gt;GcTotalAssertion&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GcMetric&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TotalCollections&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GcGeneration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Gen1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MustBe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ExactlyEqualTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1.0d&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;nf&quot;&gt;GcTotalAssertion&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GcMetric&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TotalCollections&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GcGeneration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Gen2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MustBe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ExactlyEqualTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0.0d&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;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Gen1Collection&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;list&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;GenerateObjects&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_objectNumber&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;sw&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Stopwatch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;StartNew&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
            &lt;span class=&quot;nf&quot;&gt;RunGCAndCheck&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;span class=&quot;cm&quot;&gt;/* Can't collect anything. Move it to gen 1.*/&lt;/span&gt;

            &lt;span class=&quot;n&quot;&gt;list&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;nf&quot;&gt;RunGCAndCheck&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;n&quot;&gt;sw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;span class=&quot;cm&quot;&gt;/* Run collect for gen 0 - it is empty. Run gen 1 collection - collect everything.*/&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;nf&quot;&gt;PerfBenchmark&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Description&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Gen 2 collection&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;NumberOfIterations&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;n&quot;&gt;RunMode&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RunMode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Iterations&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TestMode&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TestMode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Test&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;nf&quot;&gt;GcTotalAssertion&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GcMetric&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TotalCollections&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GcGeneration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Gen0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MustBe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ExactlyEqualTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;3.0d&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;nf&quot;&gt;GcTotalAssertion&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GcMetric&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TotalCollections&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GcGeneration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Gen1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MustBe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ExactlyEqualTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;2.0d&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;nf&quot;&gt;GcTotalAssertion&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GcMetric&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TotalCollections&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GcGeneration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Gen2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MustBe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ExactlyEqualTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1.0d&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;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Gen2Collection&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;list&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;GenerateObjects&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_objectNumber&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;sw&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Stopwatch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;StartNew&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

            &lt;span class=&quot;nf&quot;&gt;RunGCAndCheck&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;span class=&quot;cm&quot;&gt;/* Can't collect anything. Move it to gen 1.*/&lt;/span&gt;

            &lt;span class=&quot;nf&quot;&gt;RunGCAndCheck&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;n&quot;&gt;sw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;span class=&quot;cm&quot;&gt;/* Run collect for gen 0 - it is empty. Run gen 1 collection - collect the list elements.*/&lt;/span&gt;

            &lt;span class=&quot;n&quot;&gt;list&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;nf&quot;&gt;RunGCAndCheck&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;span class=&quot;cm&quot;&gt;/* Run collect for generation 0 - it is empty. Run collect for generation 1 - it is empty. Run collect for generation 2 - collect everything.*/&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;nf&quot;&gt;MethodImpl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MethodImplOptions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AggressiveInlining&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;RunGCAndCheck&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;generationNumber&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Stopwatch&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sw&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;sw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Restart&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;GC&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Collect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;generationNumber&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GCCollectionMode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Forced&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;Console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;WriteLine&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_messages&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;generationNumber&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;sw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ElapsedTicks&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;private&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;n&quot;&gt;MyGCTestClass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;GenerateObjects&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;count&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;ret&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;n&quot;&gt;MyGCTestClass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;();&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;for&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;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&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;ret&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Add&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;nf&quot;&gt;MyGCTestClass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Guid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;NewGuid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ToString&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;ret&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;private&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;MyGCTestClass&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;readonly&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Text&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;MyGCTestClass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;text&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;Text&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;text&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;nf&quot;&gt;MyGCTestClass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MyGCTestClass&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;source&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;Text&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Text&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;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;/div&gt;

&lt;h2 id=&quot;what-has-changed&quot;&gt;What has changed:&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;This code generates ‘only’ 20 thousand objects because it is the maximal number that does not trigger garbage collection at my machine.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Setup&lt;/code&gt; generates 40 thousand objects to make sure .NET will preallocate enough memory for the process so when tests are run it won’t need to ask the OS for additional memory. It also triggers &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GC.Collect(2)&lt;/code&gt; after it to make sure that all objects will be collected and the test will have a clean run.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GenerateObjects&lt;/code&gt; is called in every test to make sure I measure any &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GC.Collect&lt;/code&gt; that may affect in which generation objects are in.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And the results (I spared the NBench info, so just the numbers).&lt;/p&gt;

&lt;h3 id=&quot;gen0collection&quot;&gt;Gen0Collection&lt;/h3&gt;

&lt;p&gt;Gen 0 ticks:       6167&lt;/p&gt;

&lt;h3 id=&quot;gen1collection&quot;&gt;Gen1Collection&lt;/h3&gt;

&lt;p&gt;Gen 0 ticks:       6153
Gen 0+1 ticks:     5059&lt;/p&gt;

&lt;h3 id=&quot;gen2collection&quot;&gt;Gen2Collection&lt;/h3&gt;

&lt;p&gt;Gen 0 ticks:       4963
Gen 0+1 ticks:     4772
Gen 0+1+2 ticks:   2955&lt;/p&gt;

&lt;h3 id=&quot;gen2collectionwithnothing&quot;&gt;Gen2CollectionWithNothing&lt;/h3&gt;

&lt;p&gt;Gen 0 ticks:       171
Gen 0+1 ticks:     140
Gen 0+1+2 ticks:   1365&lt;/p&gt;

&lt;h2 id=&quot;final-thoughts&quot;&gt;Final thoughts:&lt;/h2&gt;
&lt;ol&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GC.Collect(1)&lt;/code&gt; takes a bit less time (keep in mind we are talking in ticks, not even miliseconds!) than &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GC.Collect(0)&lt;/code&gt;. For me it was not intuitive, and strange since calling &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GC.Collect(1)&lt;/code&gt; also calls &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GC.Collect(0)&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;And finally to answer &lt;a href=&quot;http://disq.us/p/18p9xvb&quot;&gt;Michał’s question&lt;/a&gt;. I think generation 0 and generation 1 algorithms are a bit different, and definitely generation 2 uses different, more complicated algorithm.&lt;/li&gt;
&lt;/ol&gt;
</description>
        <pubDate>Sat, 16 Jul 2016 00:00:00 +0200</pubDate>
        <link>https://IndexOutOfRange.com//The-cost-of-garbage-collection.Part-2-rectification/</link>
        <guid isPermaLink="true">https://IndexOutOfRange.com//The-cost-of-garbage-collection.Part-2-rectification/</guid>
      </item>
    
      <item>
        <title>The cost of garbage collection</title>
        <description>&lt;img src='https://indexoutofrange.com/data/2016-07-12-The-cost-of-garbage-collection/logo.png' /&gt;&lt;p&gt;&lt;strong&gt;Update&lt;/strong&gt;
There is a error in the first version of this code, and the tests are in fact always operating in a situation that almost all object are in generation 2. The answer is in the &lt;a href=&quot;/The-cost-of-garbage-collection.Part-2-rectification&quot;&gt;next post&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the &lt;a href=&quot;http://indexoutofrange.com/GC-can-kill-You-Practical-GC-performance-counters-in-NET/&quot;&gt;previous post&lt;/a&gt; I’ve promised to write how to have differentiate the number of workers in Hangfie, but in the comments Michał asked one interesting question - “Is generation 1 collection more expensive then generation 0 collection?”. Going further how does generation 2 collection fit into it?
&lt;!--MORE--&gt;&lt;/p&gt;

&lt;p&gt;I always believed that running &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GC.Collect&lt;/code&gt; is more expensive the deeper we go. So &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GC.Collect(0)&lt;/code&gt; is the least expensive, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GC.Collect(2)&lt;/code&gt; is most expensive. This opinion was reinforced by articles I remember reading and general opinion that .NET is optimized for fast young object collection.&lt;/p&gt;

&lt;p&gt;But after a moment of thought I came to conclusion that the same/very similar algorithm could be used for every garbage collection generation. I started a conversation with my team at work, and after a while they came to more or less the same conclusion:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;We don’t know. And to make matters worse there seem to be articles stating opposite opinions in this topic.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The only thing left was to check.&lt;br /&gt; 
To check I needed couple of things:&lt;/p&gt;

&lt;h2 id=&quot;1-large-number-of-object-that-can-be-collected&quot;&gt;1. Large number of object that can be collected.&lt;/h2&gt;

&lt;p&gt;I’ve assumed that increasing the number of objects will influence garbage collection time - this is quite logical assumption. One thing to have in mind is that those &lt;strong&gt;have to be objects&lt;/strong&gt; (instances of classes) &lt;strong&gt;not structs&lt;/strong&gt;. Why? Because structs and classes are collected in different ways. Classes are collected by counting references during &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GC.Collect&lt;/code&gt;, and structs, since you can’t have a reference to it, are collected when they loose scope, or during collection of object that contains it. More on this can be read for example &lt;a href=&quot;https://www.simple-talk.com/dotnet/.net-framework/5-tips-and-techniques-for-avoiding-automatic-gc-collections/&quot;&gt;here&lt;/a&gt;
So my class looks like this:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;MyGCTestClass&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;readonly&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Text&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;MyGCTestClass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;text&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;Text&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;text&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;nf&quot;&gt;MyGCTestClass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MyGCTestClass&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;source&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;Text&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Text&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;/div&gt;

&lt;p&gt;And generating code looks like this:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;private&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;n&quot;&gt;MyGCTestClass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;GenerateObjects&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;count&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;ret&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;n&quot;&gt;MyGCTestClass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;();&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&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;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&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;ret&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Add&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;nf&quot;&gt;MyGCTestClass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Guid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;NewGuid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ToString&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;ret&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;/div&gt;

&lt;h2 id=&quot;2-a-way-to-trigger-garbage-collection&quot;&gt;2. A way to trigger garbage collection&lt;/h2&gt;
&lt;p&gt;Since &lt;a href=&quot;https://blogs.msdn.microsoft.com/dotnet/2012/07/20/the-net-framework-4-5-includes-new-garbage-collector-enhancements-for-client-and-server-apps/&quot;&gt;.NET has two garbage collectors (client and server)&lt;/a&gt; and I wanted to measure time impact so using the blocking one (client) was the only logical choice. A quick entry in &lt;a href=&quot;https://msdn.microsoft.com/en-us/library/ms229357(v=vs.110).aspx&quot;&gt;app/web.config&lt;/a&gt;:&lt;/p&gt;

&lt;div class=&quot;language-xml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;configuration&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;runtime&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;gcServer&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;enabled=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;false&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/runtime&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/configuration&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Also &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GC.Collect&lt;/code&gt; has several overloads. The &lt;a href=&quot;https://msdn.microsoft.com/en-us/library/dn906200(v=vs.110).aspx&quot;&gt;four parameter overload&lt;/a&gt; enables to:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;set the collection as blocking&lt;/li&gt;
  &lt;li&gt;force garbage collection to actually execute&lt;/li&gt;
  &lt;li&gt;force compacting (So not only marking objects for deletion, &lt;a href=&quot;https://msdn.microsoft.com/en-us/library/ee787088(v=vs.110).aspx&quot;&gt;but also moving the rest together to minimize memory fragmentation&lt;/a&gt; )
The call will look like this:&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;GC&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Collect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;generationNumber&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GCCollectionMode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Forced&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;3-a-way-to-check-how-many-times-collection-was-executed&quot;&gt;3. A way to check how many times collection was executed&lt;/h2&gt;

&lt;p&gt;Because .NET runtime can trigger garbage collection on its own I had to be sure that the only garbage collection was that triggered by me.&lt;br /&gt;
This can be done by using &lt;a href=&quot;https://msdn.microsoft.com/en-us/library/system.gc.registerforfullgcnotification(VS.100).aspx&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GC.RegisterForFullGCNotification&lt;/code&gt;&lt;/a&gt;, but performance benchmarks like &lt;a href=&quot;https://github.com/petabridge/NBench&quot;&gt;NBench&lt;/a&gt; or  &lt;a href=&quot;https://github.com/PerfDotNet/BenchmarkDotNet&quot;&gt;BenchmarkDotNet&lt;/a&gt; have it nicely wrapped. I’ve decided to go with NBench and it’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GcTotalAssertion&lt;/code&gt; attribute.&lt;/p&gt;

&lt;p&gt;So my test class looked like this:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;System.Collections.Generic&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;System.Diagnostics&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;System.Runtime.CompilerServices&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;NBench&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Tests&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;GCCollection&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;readonly&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_messages&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;&quot;Gen 0 ticks:       &quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;s&quot;&gt;&quot;Gen 0+1 ticks:     &quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;s&quot;&gt;&quot;Gen 0+1+2 ticks:   &quot;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;private&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;n&quot;&gt;MyGCTestClass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_list&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;PerfSetup&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;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Setup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BenchmarkContext&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&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;_list&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;GenerateObjects&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;Console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;WriteLine&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Objects generated.&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;GC&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Collect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GCCollectionMode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Forced&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;span class=&quot;cm&quot;&gt;/*To be sure everything that can will be collected.*/&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;nf&quot;&gt;PerfBenchmark&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Description&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Gen 0 collection&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;NumberOfIterations&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;n&quot;&gt;RunMode&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RunMode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Iterations&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TestMode&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TestMode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Test&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;nf&quot;&gt;GcTotalAssertion&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GcMetric&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TotalCollections&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GcGeneration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Gen0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MustBe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ExactlyEqualTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1d&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;nf&quot;&gt;GcTotalAssertion&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GcMetric&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TotalCollections&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GcGeneration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Gen1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MustBe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ExactlyEqualTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0.0d&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;nf&quot;&gt;GcTotalAssertion&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GcMetric&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TotalCollections&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GcGeneration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Gen2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MustBe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ExactlyEqualTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0.0d&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;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Gen0Collection&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;_list&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;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sw&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Stopwatch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;StartNew&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

            &lt;span class=&quot;nf&quot;&gt;RunGCAndCheck&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;span class=&quot;cm&quot;&gt;/* Run collect for gen 0 - collect everything.*/&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;nf&quot;&gt;PerfBenchmark&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Description&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Gen 1 collection&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;NumberOfIterations&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;n&quot;&gt;RunMode&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RunMode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Iterations&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TestMode&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TestMode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Test&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;nf&quot;&gt;GcTotalAssertion&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GcMetric&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TotalCollections&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GcGeneration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Gen0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MustBe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ExactlyEqualTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;2.0d&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;nf&quot;&gt;GcTotalAssertion&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GcMetric&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TotalCollections&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GcGeneration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Gen1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MustBe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ExactlyEqualTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1.0d&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;nf&quot;&gt;GcTotalAssertion&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GcMetric&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TotalCollections&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GcGeneration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Gen2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MustBe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ExactlyEqualTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0.0d&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;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Gen1Collection&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;sw&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Stopwatch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;StartNew&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
            &lt;span class=&quot;nf&quot;&gt;RunGCAndCheck&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;span class=&quot;cm&quot;&gt;/* Can't collect anything. Move it to gen 1.*/&lt;/span&gt;

            &lt;span class=&quot;n&quot;&gt;_list&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;nf&quot;&gt;RunGCAndCheck&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;n&quot;&gt;sw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;span class=&quot;cm&quot;&gt;/* Run collect for gen 0 - it is empty. Run gen 1 collection - collect everything.*/&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;nf&quot;&gt;PerfBenchmark&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Description&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Gen 2 collection&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;NumberOfIterations&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;n&quot;&gt;RunMode&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RunMode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Iterations&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TestMode&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TestMode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Test&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;nf&quot;&gt;GcTotalAssertion&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GcMetric&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TotalCollections&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GcGeneration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Gen0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MustBe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ExactlyEqualTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;3.0d&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;nf&quot;&gt;GcTotalAssertion&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GcMetric&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TotalCollections&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GcGeneration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Gen1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MustBe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ExactlyEqualTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;2.0d&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;nf&quot;&gt;GcTotalAssertion&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GcMetric&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TotalCollections&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GcGeneration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Gen2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MustBe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ExactlyEqualTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1.0d&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;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Gen2Collection&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;sw&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Stopwatch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;StartNew&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

            &lt;span class=&quot;nf&quot;&gt;RunGCAndCheck&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;span class=&quot;cm&quot;&gt;/* Can't collect anything. Move it to gen 1.*/&lt;/span&gt;

            &lt;span class=&quot;nf&quot;&gt;RunGCAndCheck&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;n&quot;&gt;sw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;span class=&quot;cm&quot;&gt;/* Run collect for gen 0 - it is empty. Run gen 1 collection - collect the list elements.*/&lt;/span&gt;

            &lt;span class=&quot;n&quot;&gt;_list&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;nf&quot;&gt;RunGCAndCheck&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;span class=&quot;cm&quot;&gt;/* Run collect for generation 0 - it is empty. Run collect for generation 1 - it is empty. Run collect for generation 2 - collect everything.*/&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;nf&quot;&gt;MethodImpl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MethodImplOptions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AggressiveInlining&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;RunGCAndCheck&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;generationNumber&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Stopwatch&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sw&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;sw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Restart&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;GC&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Collect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;generationNumber&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GCCollectionMode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Forced&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;Console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;WriteLine&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_messages&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;generationNumber&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;sw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ElapsedTicks&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;private&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;n&quot;&gt;MyGCTestClass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;GenerateObjects&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;count&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;ret&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;n&quot;&gt;MyGCTestClass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;();&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;for&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;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&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;ret&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Add&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;nf&quot;&gt;MyGCTestClass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Guid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;NewGuid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ToString&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;ret&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;private&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;MyGCTestClass&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;readonly&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Text&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;MyGCTestClass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;text&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;Text&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;text&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;nf&quot;&gt;MyGCTestClass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MyGCTestClass&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;source&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;Text&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Text&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;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;/div&gt;

&lt;p&gt;Some things to point out:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RunGCAndCheck&lt;/code&gt; has &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[MethodImpl(MethodImplOptions.AggressiveInlining)]&lt;/code&gt; to inline the method and thus minimize the chance garbage collection will be called after it exits.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Setup&lt;/code&gt; will be called before every test because of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PerfSetup&lt;/code&gt; attribute.&lt;/li&gt;
  &lt;li&gt;Running &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GC.Collect(n)&lt;/code&gt; will cause garbage collection on all generation up to and with n-th generation.&lt;/li&gt;
&lt;/ul&gt;

&lt;!-- Begin MailChimp Signup Form --&gt;

&lt;link href=&quot;//cdn-images.mailchimp.com/embedcode/horizontal-slim-10_7.css&quot; rel=&quot;stylesheet&quot; type=&quot;text/css&quot; /&gt;

&lt;style type=&quot;text/css&quot;&gt;
	#mc_embed_signup{
        clear:left; 
        font:14px Helvetica,Arial,sans-serif; 
        width:100%; 
        margin-top: 40px;
        margin-bottom: 40px;
        height:100px;
    }
    #mc_embed_signup .newsletter div{
        height: 100px;
    }
    #mc_embed_signup form{
        position: relative;
        top: -90px;
    }
	/* Add your own MailChimp form style overrides in your site stylesheet or in this style block.
	   We recommend moving this block and the preceding CSS link to the HEAD of your HTML file. */
&lt;/style&gt;

&lt;div id=&quot;mc_embed_signup&quot;&gt;
    &lt;div class=&quot;gradient newsletter&quot;&gt;
        &lt;div style=&quot;background:#000000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#1C0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#380000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#550000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#710000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#8D0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#AA0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#C60000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#E20000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF3800&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF5500&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF7100&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF8D00&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFAA00&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFC600&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFE200&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFFF00&quot;&gt;&lt;/div&gt;
    &lt;/div&gt;
    &lt;form action=&quot;https://IndexOutOfRange.us15.list-manage.com/subscribe/post?u=b1c1099bf7f49b95c64107c99&amp;amp;id=6a5eb68eb7&quot; method=&quot;post&quot; id=&quot;mc-embedded-subscribe-form&quot; name=&quot;mc-embedded-subscribe-form&quot; class=&quot;validate&quot; target=&quot;_blank&quot; novalidate=&quot;&quot;&gt;
        &lt;div id=&quot;mc_embed_signup_scroll&quot;&gt;
        &lt;label for=&quot;mce-EMAIL&quot; style=&quot;color: white;&quot;&gt;Get email notifications about new posts:&lt;/label&gt;
        &lt;input type=&quot;email&quot; value=&quot;&quot; name=&quot;EMAIL&quot; class=&quot;email&quot; id=&quot;mce-EMAIL&quot; placeholder=&quot;email address&quot; required=&quot;&quot; /&gt;
        &lt;!-- real people should not fill this in and expect good things - do not remove this or risk form bot signups--&gt;
        &lt;div style=&quot;position: absolute; left: -5000px;&quot; aria-hidden=&quot;true&quot;&gt;&lt;input type=&quot;text&quot; name=&quot;b_b1c1099bf7f49b95c64107c99_6a5eb68eb7&quot; tabindex=&quot;-1&quot; value=&quot;&quot; /&gt;&lt;/div&gt;
        &lt;div class=&quot;clear&quot;&gt;&lt;input type=&quot;submit&quot; value=&quot;Subscribe&quot; name=&quot;subscribe&quot; id=&quot;mc-embedded-subscribe&quot; class=&quot;button&quot; /&gt;&lt;/div&gt;
        &lt;/div&gt;
    &lt;/form&gt;
&lt;/div&gt;

&lt;!--End mc_embed_signup--&gt;

&lt;h1 id=&quot;running-the-test-in-nbench&quot;&gt;Running the test in NBench&lt;/h1&gt;

&lt;p&gt;First thing to note is that NBench requires it’s own runner (it is avilable on &lt;a href=&quot;https://www.nuget.org/packages/NBench.Runner/&quot;&gt;nuget&lt;/a&gt;).
The second is that it runs every test twice as a warm up to minimize for such things like time spend by .NET allocating memory, and JITing the code.&lt;/p&gt;

&lt;h2 id=&quot;gen0collection-objects-collected-in-generation-0-collection&quot;&gt;Gen0Collection (objects collected in generation 0 collection):&lt;/h2&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;------------&lt;/span&gt; STARTING Tests.GCCollection+Gen0Collection &lt;span class=&quot;nt&quot;&gt;----------&lt;/span&gt;
Objects generated.
Gen 0 ticks:       21257
Objects generated.
Gen 0 ticks:       42541
&lt;span class=&quot;nt&quot;&gt;---------------&lt;/span&gt; BEGIN WARMUP &lt;span class=&quot;nt&quot;&gt;---------------&lt;/span&gt;
Elapsed: 00:00:00.0171519
TotalCollections &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;Gen0] - collections: 1,00 ,collections: /s 58,30 , ns / collections: 17 151 979,67
TotalCollections &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;Gen1] - collections: 0,00 ,collections: /s 0,00 , ns / collections: 17 151 979,67
TotalCollections &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;Gen2] - collections: 0,00 ,collections: /s 0,00 , ns / collections: 17 151 979,67
&lt;span class=&quot;nt&quot;&gt;---------------&lt;/span&gt; END WARMUP &lt;span class=&quot;nt&quot;&gt;---------------&lt;/span&gt;

Objects generated.
Gen 0 ticks:       47949
&lt;span class=&quot;nt&quot;&gt;---------------&lt;/span&gt; BEGIN RUN &lt;span class=&quot;nt&quot;&gt;---------------&lt;/span&gt;
Elapsed: 00:00:00.0192217
TotalCollections &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;Gen0] - collections: 1,00 ,collections: /s 52,02 , ns / collections: 19 221 705,61
TotalCollections &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;Gen1] - collections: 0,00 ,collections: /s 0,00 , ns / collections: 19 221 705,61
TotalCollections &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;Gen2] - collections: 0,00 ,collections: /s 0,00 , ns / collections: 19 221 705,61
&lt;span class=&quot;nt&quot;&gt;---------------&lt;/span&gt; END RUN &lt;span class=&quot;nt&quot;&gt;---------------&lt;/span&gt;

&lt;span class=&quot;nt&quot;&gt;---------------&lt;/span&gt; RESULTS: Tests.GCCollection+Gen0Collection &lt;span class=&quot;nt&quot;&gt;---------------&lt;/span&gt;
Gen 0 collection
&lt;span class=&quot;nt&quot;&gt;---------------&lt;/span&gt; DATA &lt;span class=&quot;nt&quot;&gt;---------------&lt;/span&gt;
TotalCollections &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;Gen0]: Max: 1,00 collections, Average: 1,00 collections, Min: 1,00 collections, StdDev: 0,00 collections
TotalCollections &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;Gen0]: Max / s: 52,02 collections, Average / s: 52,02 collections, Min / s: 52,02 collections, StdDev / s: 0,00 collections

TotalCollections &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;Gen1]: Max: 0,00 collections, Average: 0,00 collections, Min: 0,00 collections, StdDev: 0,00 collections
TotalCollections &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;Gen1]: Max / s: 0,00 collections, Average / s: 0,00 collections, Min / s: 0,00 collections, StdDev / s: 0,00 collections

TotalCollections &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;Gen2]: Max: 0,00 collections, Average: 0,00 collections, Min: 0,00 collections, StdDev: 0,00 collections
TotalCollections &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;Gen2]: Max / s: 0,00 collections, Average / s: 0,00 collections, Min / s: 0,00 collections, StdDev / s: 0,00 collections

&lt;span class=&quot;nt&quot;&gt;---------------&lt;/span&gt; ASSERTIONS &lt;span class=&quot;nt&quot;&gt;---------------&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;PASS] Expected TotalCollections &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;Gen0] to must be exactly 1,00 collections&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; actual value was 1,00 collections.
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;PASS] Expected TotalCollections &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;Gen1] to must be exactly 0,00 collections&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; actual value was 0,00 collections.
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;PASS] Expected TotalCollections &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;Gen2] to must be exactly 0,00 collections&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; actual value was 0,00 collections.

&lt;span class=&quot;nt&quot;&gt;------------&lt;/span&gt; FINISHED Tests.GCCollection+Gen0Collection &lt;span class=&quot;nt&quot;&gt;----------&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The test itself is the part after &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;END WARMUP&lt;/code&gt;. And according do this run generation 0 collection collecting all the objects lasts 47949 ticks.&lt;/p&gt;

&lt;h2 id=&quot;gen1collection-objects-collected-in-generation-1-collection&quot;&gt;Gen1Collection (objects collected in generation 1 collection)&lt;/h2&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;------------&lt;/span&gt; STARTING Tests.GCCollection+Gen1Collection &lt;span class=&quot;nt&quot;&gt;----------&lt;/span&gt;
Objects generated.
Gen 0 ticks:       45994
Gen 0+1 ticks:     546
Objects generated.
Gen 0 ticks:       45196
Gen 0+1 ticks:     522
&lt;span class=&quot;nt&quot;&gt;---------------&lt;/span&gt; BEGIN WARMUP &lt;span class=&quot;nt&quot;&gt;---------------&lt;/span&gt;
Elapsed: 00:00:00.0194638
TotalCollections &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;Gen0] - collections: 2,00 ,collections: /s 102,75 , ns / collections: 9 731 939,08
TotalCollections &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;Gen1] - collections: 1,00 ,collections: /s 51,38 , ns / collections: 19 463 878,17
TotalCollections &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;Gen2] - collections: 0,00 ,collections: /s 0,00 , ns / collections: 19 463 878,17
&lt;span class=&quot;nt&quot;&gt;---------------&lt;/span&gt; END WARMUP &lt;span class=&quot;nt&quot;&gt;---------------&lt;/span&gt;

Objects generated.
Gen 0 ticks:       47584
Gen 0+1 ticks:     472
&lt;span class=&quot;nt&quot;&gt;---------------&lt;/span&gt; BEGIN RUN &lt;span class=&quot;nt&quot;&gt;---------------&lt;/span&gt;
Elapsed: 00:00:00.0206490
TotalCollections &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;Gen0] - collections: 2,00 ,collections: /s 96,86 , ns / collections: 10 324 530,97
TotalCollections &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;Gen1] - collections: 1,00 ,collections: /s 48,43 , ns / collections: 20 649 061,95
TotalCollections &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;Gen2] - collections: 0,00 ,collections: /s 0,00 , ns / collections: 20 649 061,95
&lt;span class=&quot;nt&quot;&gt;---------------&lt;/span&gt; END RUN &lt;span class=&quot;nt&quot;&gt;---------------&lt;/span&gt;

&lt;span class=&quot;nt&quot;&gt;---------------&lt;/span&gt; RESULTS: Tests.GCCollection+Gen1Collection &lt;span class=&quot;nt&quot;&gt;---------------&lt;/span&gt;
Gen 1 collection
&lt;span class=&quot;nt&quot;&gt;---------------&lt;/span&gt; DATA &lt;span class=&quot;nt&quot;&gt;---------------&lt;/span&gt;
TotalCollections &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;Gen0]: Max: 2,00 collections, Average: 2,00 collections, Min: 2,00 collections, StdDev: 0,00 collections
TotalCollections &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;Gen0]: Max / s: 96,86 collections, Average / s: 96,86 collections, Min / s: 96,86 collections, StdDev / s: 0,00 collections

TotalCollections &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;Gen1]: Max: 1,00 collections, Average: 1,00 collections, Min: 1,00 collections, StdDev: 0,00 collections
TotalCollections &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;Gen1]: Max / s: 48,43 collections, Average / s: 48,43 collections, Min / s: 48,43 collections, StdDev / s: 0,00 collections

TotalCollections &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;Gen2]: Max: 0,00 collections, Average: 0,00 collections, Min: 0,00 collections, StdDev: 0,00 collections
TotalCollections &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;Gen2]: Max / s: 0,00 collections, Average / s: 0,00 collections, Min / s: 0,00 collections, StdDev / s: 0,00 collections

&lt;span class=&quot;nt&quot;&gt;---------------&lt;/span&gt; ASSERTIONS &lt;span class=&quot;nt&quot;&gt;---------------&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;PASS] Expected TotalCollections &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;Gen0] to must be exactly 2,00 collections&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; actual value was 2,00 collections.
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;PASS] Expected TotalCollections &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;Gen1] to must be exactly 1,00 collections&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; actual value was 1,00 collections.
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;PASS] Expected TotalCollections &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;Gen2] to must be exactly 0,00 collections&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; actual value was 0,00 collections.

&lt;span class=&quot;nt&quot;&gt;------------&lt;/span&gt; FINISHED Tests.GCCollection+Gen1Collection &lt;span class=&quot;nt&quot;&gt;----------&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The difference between 47584 ticks for generation 0 and 472 ticks for generation 1 collection is big (more than 100 times), but keep reading because the best is yet to come.&lt;/p&gt;

&lt;h2 id=&quot;gen2collection-objects-collected-in-generation-2-collection&quot;&gt;Gen2Collection (objects collected in generation 2 collection)&lt;/h2&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;------------&lt;/span&gt; STARTING Tests.GCCollection+Gen2Collection &lt;span class=&quot;nt&quot;&gt;----------&lt;/span&gt;
Objects generated.
Gen 0 ticks:       46034
Gen 0+1 ticks:     559
Gen 0+1+2 ticks:   1461791
Objects generated.
Gen 0 ticks:       37438
Gen 0+1 ticks:     451
Gen 0+1+2 ticks:   793937
&lt;span class=&quot;nt&quot;&gt;---------------&lt;/span&gt; BEGIN WARMUP &lt;span class=&quot;nt&quot;&gt;---------------&lt;/span&gt;
Elapsed: 00:00:00.3300270
TotalCollections &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;Gen0] - collections: 3,00 ,collections: /s 9,09 , ns / collections: 110 009 021,88
TotalCollections &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;Gen1] - collections: 2,00 ,collections: /s 6,06 , ns / collections: 165 013 532,82
TotalCollections &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;Gen2] - collections: 1,00 ,collections: /s 3,03 , ns / collections: 330 027 065,65
&lt;span class=&quot;nt&quot;&gt;---------------&lt;/span&gt; END WARMUP &lt;span class=&quot;nt&quot;&gt;---------------&lt;/span&gt;

Objects generated.
Gen 0 ticks:       36631
Gen 0+1 ticks:     524
Gen 0+1+2 ticks:   1358065
&lt;span class=&quot;nt&quot;&gt;---------------&lt;/span&gt; BEGIN RUN &lt;span class=&quot;nt&quot;&gt;---------------&lt;/span&gt;
Elapsed: 00:00:00.5528463
TotalCollections &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;Gen0] - collections: 3,00 ,collections: /s 5,43 , ns / collections: 184 282 119,04
TotalCollections &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;Gen1] - collections: 2,00 ,collections: /s 3,62 , ns / collections: 276 423 178,56
TotalCollections &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;Gen2] - collections: 1,00 ,collections: /s 1,81 , ns / collections: 552 846 357,12
&lt;span class=&quot;nt&quot;&gt;---------------&lt;/span&gt; END RUN &lt;span class=&quot;nt&quot;&gt;---------------&lt;/span&gt;

&lt;span class=&quot;nt&quot;&gt;---------------&lt;/span&gt; RESULTS: Tests.GCCollection+Gen2Collection &lt;span class=&quot;nt&quot;&gt;---------------&lt;/span&gt;
Gen 2 collection
&lt;span class=&quot;nt&quot;&gt;---------------&lt;/span&gt; DATA &lt;span class=&quot;nt&quot;&gt;---------------&lt;/span&gt;
TotalCollections &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;Gen0]: Max: 3,00 collections, Average: 3,00 collections, Min: 3,00 collections, StdDev: 0,00 collections
TotalCollections &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;Gen0]: Max / s: 5,43 collections, Average / s: 5,43 collections, Min / s: 5,43 collections, StdDev / s: 0,00 collections

TotalCollections &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;Gen1]: Max: 2,00 collections, Average: 2,00 collections, Min: 2,00 collections, StdDev: 0,00 collections
TotalCollections &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;Gen1]: Max / s: 3,62 collections, Average / s: 3,62 collections, Min / s: 3,62 collections, StdDev / s: 0,00 collections

TotalCollections &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;Gen2]: Max: 1,00 collections, Average: 1,00 collections, Min: 1,00 collections, StdDev: 0,00 collections
TotalCollections &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;Gen2]: Max / s: 1,81 collections, Average / s: 1,81 collections, Min / s: 1,81 collections, StdDev / s: 0,00 collections

&lt;span class=&quot;nt&quot;&gt;---------------&lt;/span&gt; ASSERTIONS &lt;span class=&quot;nt&quot;&gt;---------------&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;PASS] Expected TotalCollections &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;Gen0] to must be exactly 3,00 collections&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; actual value was 3,00 collections.
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;PASS] Expected TotalCollections &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;Gen1] to must be exactly 2,00 collections&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; actual value was 2,00 collections.
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;PASS] Expected TotalCollections &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;Gen2] to must be exactly 1,00 collections&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; actual value was 1,00 collections.

&lt;span class=&quot;nt&quot;&gt;------------&lt;/span&gt; FINISHED Tests.GCCollection+Gen2Collection &lt;span class=&quot;nt&quot;&gt;----------&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;the-final-results&quot;&gt;The final results&lt;/h1&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Gen 0 ticks:       36631
Gen 0+1 ticks:     524
Gen 0+1+2 ticks:   1358065
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Yes, the difference between generation 2 and 1 is almost &lt;strong&gt;2600 times!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To be sure below are averages from 5 runs:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Gen 0 ticks:       38364
Gen 0+1 ticks:     424
Gen 0+1+2 ticks:   1403400.6
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;So generation 1 is surprisingly fast, and generation 2 collection is relatively slow (remember those are ticks! Not milliseconds!). But case closed?&lt;/p&gt;

&lt;p&gt;Not exactly.&lt;br /&gt;
Take a look at this test:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;PerfBenchmark&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Description&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Gen 2 collection with nothing&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;NumberOfIterations&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;n&quot;&gt;RunMode&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RunMode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Iterations&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TestMode&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TestMode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Test&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;nf&quot;&gt;GcTotalAssertion&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GcMetric&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TotalCollections&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GcGeneration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Gen0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MustBe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ExactlyEqualTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;3d&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;nf&quot;&gt;GcTotalAssertion&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GcMetric&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TotalCollections&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GcGeneration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Gen1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MustBe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ExactlyEqualTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;2d&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;nf&quot;&gt;GcTotalAssertion&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GcMetric&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TotalCollections&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GcGeneration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Gen2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MustBe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ExactlyEqualTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1d&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;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Gen2CollectionWithNothing&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;_list&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;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sw&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Stopwatch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;StartNew&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

    &lt;span class=&quot;nf&quot;&gt;RunGCAndCheck&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;span class=&quot;cm&quot;&gt;/* Run collect for gen 0 - collect everything.*/&lt;/span&gt;

    &lt;span class=&quot;nf&quot;&gt;RunGCAndCheck&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;n&quot;&gt;sw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;span class=&quot;cm&quot;&gt;/* Nothing should be here.*/&lt;/span&gt;

    &lt;span class=&quot;nf&quot;&gt;RunGCAndCheck&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;span class=&quot;cm&quot;&gt;/* Nothing should be here.*/&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It should collect everything in generation 0 collection, the rest should be close to 0, but here are the results:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Gen 0 ticks:       32872
Gen 0+1 ticks:     358
Gen 0+1+2 ticks:   1297617
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;So yeah. Basically no difference from previous test. So this post should be named &lt;em&gt;“The cost of GC - a failed try”&lt;/em&gt;. I don’t know what to make of it. I have some ideas what to change and what to check to be more sure that those numbers are valid.&lt;/p&gt;

&lt;p&gt;If anyone has any suggestions I’ve put this code in a &lt;a href=&quot;https://github.com/maklipsa/CSharpPerfExperiments&quot;&gt;repo on github&lt;/a&gt;, any pull requests are welcomed.&lt;/p&gt;
</description>
        <pubDate>Tue, 12 Jul 2016 00:00:00 +0200</pubDate>
        <link>https://IndexOutOfRange.com//The-cost-of-garbage-collection/</link>
        <guid isPermaLink="true">https://IndexOutOfRange.com//The-cost-of-garbage-collection/</guid>
      </item>
    
      <item>
        <title>GC can kill You. Practical GC performance counters in .NET</title>
        <description>&lt;img src='https://indexoutofrange.com/' /&gt;&lt;p&gt;One of the steps in cookit is calculating similar recipes.
This is what you can see on the left on the recipe page like &lt;a href=&quot;https://cookit.pl/przepis/350106/Karkowka+marynowana+w+mleku+i+cebuli+%E2%80%93+grill&quot;&gt;this&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For the sake of clarity and manageability it’s scheduled as separate Hangfire jobs. Because cookit is running 5 workers, so similarities are calculated for 5 websites concurrently.&lt;br /&gt;
The process uses &lt;a href=&quot;https://en.wikipedia.org/wiki/Cosine_similarity&quot;&gt;cosine similarity&lt;/a&gt;, so it allocates a huge list at start and calculates similarities. A very CPU heavy operation.
&lt;!--MORE--&gt;&lt;/p&gt;

&lt;p&gt;So some time after triggering all recipes recalculation I saw this in Hangfire console.
&lt;img src=&quot;/data/GC-can-kill-You-Practical-GC-performance-counters-in-NET/HangfieConsole.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The process can take a while, but on average it lasts couple of minutes.
First thing was to check was if the server was doing anything. So fire up Task Manager and here it is:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/data/GC-can-kill-You-Practical-GC-performance-counters-in-NET/TaskManager.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;So, something is happening. To better know what, I’ve fired up &lt;a href=&quot;https://technet.microsoft.com/en-us/sysinternals/processexplorer.aspx&quot;&gt;Process Explorer&lt;/a&gt;(run it as administrator!) and in the &lt;strong&gt;Properties &amp;gt; .NET Performance&lt;/strong&gt; tab I saw this.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/data/GC-can-kill-You-Practical-GC-performance-counters-in-NET/ProcessExplorer.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;A side note.&lt;br /&gt;
Process Explorer is an element of &lt;a href=&quot;https://technet.microsoft.com/en-us/sysinternals/bb842062.aspx&quot;&gt;Sysinternals Suite&lt;/a&gt;. This is &lt;strong&gt;the must have&lt;/strong&gt; for any developer using Windows. They don’t need installation and weight less than 16MB. I always place them under C:\tools&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I really like this tab, because it shows all the main performance counters for .NET programs.
And in this case it also worked. Spending 43% (in the peeks) in GC is &lt;strong&gt;not&lt;/strong&gt; a good thing.&lt;/p&gt;

&lt;!-- Begin MailChimp Signup Form --&gt;

&lt;link href=&quot;//cdn-images.mailchimp.com/embedcode/horizontal-slim-10_7.css&quot; rel=&quot;stylesheet&quot; type=&quot;text/css&quot; /&gt;

&lt;style type=&quot;text/css&quot;&gt;
	#mc_embed_signup{
        clear:left; 
        font:14px Helvetica,Arial,sans-serif; 
        width:100%; 
        margin-top: 40px;
        margin-bottom: 40px;
        height:100px;
    }
    #mc_embed_signup .newsletter div{
        height: 100px;
    }
    #mc_embed_signup form{
        position: relative;
        top: -90px;
    }
	/* Add your own MailChimp form style overrides in your site stylesheet or in this style block.
	   We recommend moving this block and the preceding CSS link to the HEAD of your HTML file. */
&lt;/style&gt;

&lt;div id=&quot;mc_embed_signup&quot;&gt;
    &lt;div class=&quot;gradient newsletter&quot;&gt;
        &lt;div style=&quot;background:#000000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#1C0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#380000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#550000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#710000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#8D0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#AA0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#C60000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#E20000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF3800&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF5500&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF7100&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF8D00&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFAA00&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFC600&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFE200&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFFF00&quot;&gt;&lt;/div&gt;
    &lt;/div&gt;
    &lt;form action=&quot;https://IndexOutOfRange.us15.list-manage.com/subscribe/post?u=b1c1099bf7f49b95c64107c99&amp;amp;id=6a5eb68eb7&quot; method=&quot;post&quot; id=&quot;mc-embedded-subscribe-form&quot; name=&quot;mc-embedded-subscribe-form&quot; class=&quot;validate&quot; target=&quot;_blank&quot; novalidate=&quot;&quot;&gt;
        &lt;div id=&quot;mc_embed_signup_scroll&quot;&gt;
        &lt;label for=&quot;mce-EMAIL&quot; style=&quot;color: white;&quot;&gt;Get email notifications about new posts:&lt;/label&gt;
        &lt;input type=&quot;email&quot; value=&quot;&quot; name=&quot;EMAIL&quot; class=&quot;email&quot; id=&quot;mce-EMAIL&quot; placeholder=&quot;email address&quot; required=&quot;&quot; /&gt;
        &lt;!-- real people should not fill this in and expect good things - do not remove this or risk form bot signups--&gt;
        &lt;div style=&quot;position: absolute; left: -5000px;&quot; aria-hidden=&quot;true&quot;&gt;&lt;input type=&quot;text&quot; name=&quot;b_b1c1099bf7f49b95c64107c99_6a5eb68eb7&quot; tabindex=&quot;-1&quot; value=&quot;&quot; /&gt;&lt;/div&gt;
        &lt;div class=&quot;clear&quot;&gt;&lt;input type=&quot;submit&quot; value=&quot;Subscribe&quot; name=&quot;subscribe&quot; id=&quot;mc-embedded-subscribe&quot; class=&quot;button&quot; /&gt;&lt;/div&gt;
        &lt;/div&gt;
    &lt;/form&gt;
&lt;/div&gt;

&lt;!--End mc_embed_signup--&gt;

&lt;p&gt;Just to be sure that high GC isn’t caused by another issue, like exceptions let’s look at &lt;strong&gt;.NET CLR Exceptions&lt;/strong&gt; tab:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/data/GC-can-kill-You-Practical-GC-performance-counters-in-NET/ProcessExplorer_Exceptions.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;More than I would want, but:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;those are all exceptions thrown during the lifetime of the process and earlier it has done some extraction jobs and they can cause exceptions.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;those are also first level exceptions&lt;/strong&gt;. So also the caught ones. Some libraries use exceptions as way to control logic, and this can be seen on this tab. It can be a major performance hit.&lt;/li&gt;
  &lt;li&gt;under heavy load &lt;a href=&quot;http://hangfire.io/&quot;&gt;Hangfrie&lt;/a&gt; can throw some sql timeout exceptions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Process Explorer only shows snapshots. To see how it looks over time fire up Performance  Monitor (perfmon.exe - it is installed on every Windows) and add &lt;strong&gt;.NET CLR Memory % Time in GC&lt;/strong&gt; performance counter (using the green plus).&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/data/GC-can-kill-You-Practical-GC-performance-counters-in-NET/PerformanceMonitor_01.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Well it looks really bad. To say the least.&lt;br /&gt;
This only gives a very high level view. To have a better look let’s add more performance counters:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;.NET CLR Memory # Gen 0 Collections (how many times &lt;strong&gt;Gen 0, Gen 1 and Gen 2&lt;/strong&gt; collection was called. &lt;strong&gt;It is a sum of all Gen collections count not only Gen 0&lt;/strong&gt;)&lt;/li&gt;
  &lt;li&gt;.NET CLR Memory \ # Gen 1 Collections (Sum of Gen 1 and Gen 2 collections called.)&lt;/li&gt;
  &lt;li&gt;.NET CLR Memory \ # Gen 2 Collections&lt;/li&gt;
  &lt;li&gt;.NET CLR Memory \ % Time in GC&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;and we see this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/data/GC-can-kill-You-Practical-GC-performance-counters-in-NET/PerformanceMonitor_02.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;So a lot of Gen 0 and Gen 1 collections, plus a little bit of Gen 2.&lt;br /&gt;
This is showing that .NET is under memory pressure and it’s trying to free memory. Because it’s not running a lot of Gen 2 collections means that enough memory is being freed during Gen 0 and 1.&lt;br /&gt;
To be sure lets see how big Gen 0 and 1 heaps are (how much memory is allocated on them), and how they behave over time. Lets have a look at those counters:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;.NET CLR Memory \ # Gen 0 heap size&lt;/li&gt;
  &lt;li&gt;.NET CLR Memory \ # Gen 1 heap size&lt;/li&gt;
  &lt;li&gt;.NET CLR Memory \ # Gen 2 heap size&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;/data/GC-can-kill-You-Practical-GC-performance-counters-in-NET/PerformanceMonitor_03.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;This &lt;strong&gt;almost&lt;/strong&gt; what I expect how the process would use memory:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;It allocates a huge list at start (the Gen 0)&lt;/li&gt;
  &lt;li&gt;It loops through every recipe, calculates similarity, and stores it in a sorted list. The list is limited to five top similarities. So a lot of objects are being moved into and from the list.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So were is the &lt;strong&gt;almost&lt;/strong&gt;?&lt;br /&gt;
Most allocated object should have a short life span, so they should be collected cheaply in Gen 0. But because Gen 1 is this big it means that when GC is triggered it can’t collect them, so they are being moved to Gen 1. Then Gen 1 collection is being triggered, and previously moved objects are being collected. And Gen 1 collection is far more costly. In summary GC is being triggered too often.&lt;/p&gt;

&lt;p&gt;To show my point where is the Performance Monitor with only one worker.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/data/GC-can-kill-You-Practical-GC-performance-counters-in-NET/PerformanceMonitor_04.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;You may be wondering where is the Gen 1 line?&lt;br /&gt;
It is still there. It’s those few pixels just above the 0 line is the Gen 1 heap size. And this is the same scale as plot above.&lt;br /&gt;
To make a point I’ve added time in GC.&lt;br /&gt;
A very boring plot. Just as it should be.&lt;/p&gt;

&lt;p&gt;But this only shows the problem. Possible solutions are:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;em&gt;Get a better machine with more RAM.&lt;/em&gt; This is out of the question, as I already explain &lt;a href=&quot;http://indexoutofrange.com/The-importance-of-running-on-crapp/&quot;&gt;why cookit runs on crap&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;Have one worker.&lt;/em&gt; This is also not a good solutions because some jobs are I/O (network) bound. And having one worker is in general not that good (anyone remembers 1 core processors?)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So how to have differentiate the number of workers in Hangfie?&lt;br /&gt;
This will be in the next post :)&lt;/p&gt;

</description>
        <pubDate>Mon, 30 May 2016 00:00:00 +0200</pubDate>
        <link>https://IndexOutOfRange.com//GC-can-kill-You-Practical-GC-performance-counters-in-NET/</link>
        <guid isPermaLink="true">https://IndexOutOfRange.com//GC-can-kill-You-Practical-GC-performance-counters-in-NET/</guid>
      </item>
    
      <item>
        <title>System.Console is slow</title>
        <description>&lt;img src='https://indexoutofrange.com/' /&gt;&lt;p&gt;&lt;strong&gt;This post is written more as a warning&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Anyone who made any &lt;a href=&quot;https://www.hackerrank.com/&quot;&gt;HackerRank&lt;/a&gt; problems considering performance has seen this phrase in the assignment: “watch out for slow IO”.&lt;br /&gt;
We are used to think about files, databases and such as potentially slow IO, but the Console?&lt;br /&gt;
Yes, and you will be amazed how much.
&lt;!--MORE--&gt;&lt;/p&gt;

&lt;p&gt;Couple words about the setup.&lt;br /&gt;
I am using NLog with &lt;a href=&quot;https://github.com/nlog/NLog/wiki/File-target&quot;&gt;file target&lt;/a&gt; (for normal logging) and &lt;a href=&quot;https://github.com/nlog/NLog/wiki/Mail-target&quot;&gt;mail target&lt;/a&gt; (for total failure, and aggregated reports).&lt;br /&gt;
When debugging or profiling I run the process as a console application, so I have a &lt;a href=&quot;https://github.com/NLog/NLog/wiki/Console-target&quot;&gt;NLog console target&lt;/a&gt;. It outputs some basic info and debug messages summing up to exactly 329KB of text.&lt;/p&gt;

&lt;p&gt;So here are the numbers of running the application with console target:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/data/System.ConsoleIsSlow/BaseRun.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;And here are the numbers with console target commented:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/data/System.ConsoleIsSlow/WithoutConsole.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;28 seconds for outputting 329 KB of text. &lt;br /&gt;
To be fair, if you output it in one big chunk it will be faster.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;To sum it up:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;don’t assume something is fast. Measure it!&lt;br /&gt;&lt;/li&gt;
  &lt;li&gt;control your output. If this was a program running normally as a console application with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Console.WriteLine&lt;/code&gt; thrown all over the code base the change wouldn’t take less than 1 minute.&lt;/li&gt;
  &lt;li&gt;NLog is a good abstraction over where your logs go.&lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Wed, 25 May 2016 00:00:00 +0200</pubDate>
        <link>https://IndexOutOfRange.com//System.ConsoleIsSlow/</link>
        <guid isPermaLink="true">https://IndexOutOfRange.com//System.ConsoleIsSlow/</guid>
      </item>
    
      <item>
        <title>Local optimizations don't add up</title>
        <description>&lt;img src='https://indexoutofrange.com/' /&gt;&lt;p&gt;One of the main processes in &lt;a href=&quot;http://cookit.pl&quot; title=&quot;cookit.pl&quot;&gt;cookit&lt;/a&gt; is dealing with extracting recipe information from raw html. I know it isn’t the most elegant solution but it is the only universal one.&lt;/p&gt;

&lt;p&gt;But to the point.&lt;/p&gt;

&lt;p&gt;Every web page goes through a process involving &lt;a href=&quot;https://htmlagilitypack.codeplex.com/&quot;&gt;html parsing&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/Stemming&quot;&gt;stemming&lt;/a&gt;, parsing, and &lt;a href=&quot;https://en.wikipedia.org/wiki/N-gram&quot;&gt;n-gram token matching&lt;/a&gt;. Then it’s saved to Sql Server and after transformation to Solr. So a lot of string manipulation, math calculations and from time to time mostly 0-gen GC.
&lt;!--MORE--&gt;&lt;/p&gt;

&lt;p&gt;In the most pessimistic case this process has to be re-run for every cached website for every page.
And to give you a sense of how much data this is, here is the properties window for the folder containing the cached html files:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/data/LocalOptimizationsDontAddUp/CrawlerSites.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;And since &lt;a href=&quot;http://indexoutofrange.com/The-importance-of-running-on-crapp/&quot;&gt;I run on crapp&lt;/a&gt; this process can take &lt;em&gt;“a while”&lt;/em&gt;. 
And by that I mean days.
It used to be more than a week but after a lot of work put into optimizations it takes now from 3 to 4 days for ~1000 websites.&lt;/p&gt;

&lt;p&gt;I do optimization sessions from time to time, or when it feels necessary to. And when is that? 
There are some performance tests for some of the most critical parts, but the whole process is to complex to have a full blown performance test coverage.
But this isn’t an issue &lt;a href=&quot;http://indexoutofrange.com//How-is-cookit-build/&quot;&gt;since all background jobs are run in the background with Hangfire&lt;/a&gt; I get total run times out of the box and even better with a great dashboard:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/data/LocalOptimizationsDontAddUp/HangfireDashboard.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;If those were parsing jobs being shown I would know that I have a big problem.&lt;/p&gt;

&lt;p&gt;This will be a story of one of those “from time to time” sessions.&lt;/p&gt;

&lt;p&gt;So lets begin and fire up Excel.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://media.giphy.com/media/gpufDFw0sPBYY/giphy.gif&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;↑&lt;/strong&gt; This is probably the reaction of most people reading the above, but it is one of the most crucial steps in any optimization work.&lt;/p&gt;

&lt;p&gt;Why?&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;it gives an easy place where I note the run times and current tasks under tests.&lt;/li&gt;
  &lt;li&gt;it can easily calculate means and any average function.&lt;/li&gt;
  &lt;li&gt;since those runs usually last for a couple of minutes each in the meantime I do some reading, catching up with RSS feeds and so on. So when the run ends notes in excel let me easily switch context to the task currently under tests.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To be as close to the real run I fire it as a console application and go through the whole process. From reading the files, extraction, to saving to Sql Server and exporting to Solr. This is important because optimizations can speed up one fragment, but slow down the process as a whole.&lt;/p&gt;

&lt;p&gt;This is what I saw in the base run :&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;98 sec&lt;/li&gt;
  &lt;li&gt;96 sec&lt;/li&gt;
  &lt;li&gt;130 sec&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now at this moment I could treat the third run as just a glitch, but I decided to do some more runs.
And I saw this:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;70 sec&lt;/li&gt;
  &lt;li&gt;69 sec&lt;/li&gt;
  &lt;li&gt;108 sec&lt;/li&gt;
  &lt;li&gt;106 sec&lt;/li&gt;
  &lt;li&gt;109 sec&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This meant one thing - I have no baseline. The results had such a huge dispersion that they didn’t mean nothing.&lt;/p&gt;

&lt;!-- Begin MailChimp Signup Form --&gt;

&lt;link href=&quot;//cdn-images.mailchimp.com/embedcode/horizontal-slim-10_7.css&quot; rel=&quot;stylesheet&quot; type=&quot;text/css&quot; /&gt;

&lt;style type=&quot;text/css&quot;&gt;
	#mc_embed_signup{
        clear:left; 
        font:14px Helvetica,Arial,sans-serif; 
        width:100%; 
        margin-top: 40px;
        margin-bottom: 40px;
        height:100px;
    }
    #mc_embed_signup .newsletter div{
        height: 100px;
    }
    #mc_embed_signup form{
        position: relative;
        top: -90px;
    }
	/* Add your own MailChimp form style overrides in your site stylesheet or in this style block.
	   We recommend moving this block and the preceding CSS link to the HEAD of your HTML file. */
&lt;/style&gt;

&lt;div id=&quot;mc_embed_signup&quot;&gt;
    &lt;div class=&quot;gradient newsletter&quot;&gt;
        &lt;div style=&quot;background:#000000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#1C0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#380000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#550000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#710000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#8D0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#AA0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#C60000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#E20000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF0000&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF3800&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF5500&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF7100&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FF8D00&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFAA00&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFC600&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFE200&quot;&gt;&lt;/div&gt;
        &lt;div style=&quot;background:#FFFF00&quot;&gt;&lt;/div&gt;
    &lt;/div&gt;
    &lt;form action=&quot;https://IndexOutOfRange.us15.list-manage.com/subscribe/post?u=b1c1099bf7f49b95c64107c99&amp;amp;id=6a5eb68eb7&quot; method=&quot;post&quot; id=&quot;mc-embedded-subscribe-form&quot; name=&quot;mc-embedded-subscribe-form&quot; class=&quot;validate&quot; target=&quot;_blank&quot; novalidate=&quot;&quot;&gt;
        &lt;div id=&quot;mc_embed_signup_scroll&quot;&gt;
        &lt;label for=&quot;mce-EMAIL&quot; style=&quot;color: white;&quot;&gt;Get email notifications about new posts:&lt;/label&gt;
        &lt;input type=&quot;email&quot; value=&quot;&quot; name=&quot;EMAIL&quot; class=&quot;email&quot; id=&quot;mce-EMAIL&quot; placeholder=&quot;email address&quot; required=&quot;&quot; /&gt;
        &lt;!-- real people should not fill this in and expect good things - do not remove this or risk form bot signups--&gt;
        &lt;div style=&quot;position: absolute; left: -5000px;&quot; aria-hidden=&quot;true&quot;&gt;&lt;input type=&quot;text&quot; name=&quot;b_b1c1099bf7f49b95c64107c99_6a5eb68eb7&quot; tabindex=&quot;-1&quot; value=&quot;&quot; /&gt;&lt;/div&gt;
        &lt;div class=&quot;clear&quot;&gt;&lt;input type=&quot;submit&quot; value=&quot;Subscribe&quot; name=&quot;subscribe&quot; id=&quot;mc-embedded-subscribe&quot; class=&quot;button&quot; /&gt;&lt;/div&gt;
        &lt;/div&gt;
    &lt;/form&gt;
&lt;/div&gt;

&lt;!--End mc_embed_signup--&gt;

&lt;p&gt;My Excel showed this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/data/LocalOptimizationsDontAddUp/Excel01.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Where:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;avg&lt;/strong&gt; is of curse the most common &lt;a href=&quot;https://en.wikipedia.org/wiki/Average&quot;&gt;average&lt;/a&gt; - the &lt;a href=&quot;https://en.wikipedia.org/wiki/Arithmetic_mean&quot;&gt;arithmetic mean&lt;/a&gt;. And as anyone will tell you, it doesn’t mean anything without the second.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;st dev&lt;/strong&gt; is the &lt;a href=&quot;https://en.wikipedia.org/wiki/Standard_deviation&quot;&gt;standard deviation&lt;/a&gt; which shows how &lt;strong&gt;precise&lt;/strong&gt; the average is. And in my case it is telling me it isn’t.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So I fired up the profiler at hand, witch was &lt;a href=&quot;https://www.jetbrains.com/profiler/&quot;&gt;dotTrace&lt;/a&gt; and because I wanted a view what was going on I used the Timeline mode. I had to run it several times to catch the long run, but finally I’ve got it.
And when I did here is what I saw:
&lt;img src=&quot;/data/LocalOptimizationsDontAddUp/dotTrace_02.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The main problem with this is that it is not showing a CPU bound process. But from Process Explorer I knew that all cores were hard at work. 
The second thing is that it shows a lot of threads doing almost nothing.&lt;/p&gt;

&lt;p&gt;From the two above it was clear what to search for in the code.&lt;/p&gt;

&lt;p&gt;This is the culprit:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ingredients&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;AsParallel&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;nf&quot;&gt;Select&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&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;float&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;relevance&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;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_ingredientRelevance&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;_ingredientRelevance&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_getIngredientRelevance&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Do&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;_ingredientRelevance&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ContainsKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&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;relevance&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_ingredientRelevance&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&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;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;IngredientWithRelevanceAndLevel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&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;relevance&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Level&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;nf&quot;&gt;ToList&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Because the profiler is showing only my code that means that the rest of the processing power was used to switch threads.&lt;/p&gt;

&lt;p&gt;After removing the AsParallel my excel looked like this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/data/LocalOptimizationsDontAddUp/Excel02.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;A lot nicer and a bit more predictable. 
So how did this change got through? It was a local optimization. It worked in a separated test, but when used in the whole process became a problem.&lt;/p&gt;

&lt;p&gt;The Excel can be downloaded form &lt;a href=&quot;/data/LocalOptimizationsDontAddUp/OptimizationRuns.xlsx&quot;&gt;here&lt;/a&gt;, and a &lt;a href=&quot;https://docs.google.com/spreadsheets/d/1DMf3VMuG5iFvoN-CXLR9Rm-lgLAi9VG7IhH4MEGluMs/edit?usp=sharing&quot; target=&quot;_blank&quot;&gt;Google Spreadsheet&lt;/a&gt;&lt;/p&gt;

</description>
        <pubDate>Fri, 20 May 2016 00:00:00 +0200</pubDate>
        <link>https://IndexOutOfRange.com//LocalOptimizationsDontAddUp/</link>
        <guid isPermaLink="true">https://IndexOutOfRange.com//LocalOptimizationsDontAddUp/</guid>
      </item>
    
      <item>
        <title>Neo4j stored procedures for Windows</title>
        <description>&lt;img src='https://indexoutofrange.com/data/Neo4jStoredProcedures/StoredProcedures.png' /&gt;&lt;p&gt;In the &lt;a href=&quot;http://indexoutofrange.com/GraphConnectEurope/&quot;&gt;previous post I’ve written about new features in Neo4j&lt;/a&gt;. 
One of the new game changing functions were stored procedures. But, as I experienced, getting them to run on a Windows / .NET environment wasn’t that easy, and I was seeing “&lt;strong&gt;There is no procedure with the name&lt;/strong&gt; …” more often then I wished for.
So here is a short how to. Hope to save you some googling.&lt;/p&gt;

&lt;!--MORE--&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;JDK&lt;/strong&gt;&lt;/p&gt;

    &lt;ol&gt;
      &lt;li&gt;
        &lt;p&gt;Download and install JDK 8.x from &lt;a href=&quot;http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html&quot;&gt;here&lt;/a&gt;. I’ve used 8u92 version.&lt;/p&gt;
      &lt;/li&gt;
      &lt;li&gt;
        &lt;p&gt;Set environment variable for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;JAVA_HOME&lt;/code&gt; pointing to JDK install location (in my case &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;C:\Program Files\Java\jdk1.8.0_92&lt;/code&gt;). This can be done with some PowerShell:&lt;/p&gt;
        &lt;pre&gt;&lt;code class=&quot;powershell&quot;&gt;[Environment]::SetEnvironmentVariable(&quot;JAVA_HOME&quot;,&quot;C:\Program Files\Java\jdk1.8.0_92&quot;,&quot;Machine&quot;)
 &lt;/code&gt;&lt;/pre&gt;
      &lt;/li&gt;
    &lt;/ol&gt;

    &lt;p&gt;The last parameter sets it as a machine level variable (visible for all users).&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Install Maven&lt;/strong&gt;&lt;/p&gt;

    &lt;ol&gt;
      &lt;li&gt;Download Maven from the &lt;a href=&quot;https://maven.apache.org/download.cgi&quot;&gt;official site&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;Unzip it to a directory. In my case &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;C:\Program Files\Maven&lt;/code&gt;&lt;/li&gt;
      &lt;li&gt;Add environment variables for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;M2_HOME&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MAVEN_HOME&lt;/code&gt;.
        &lt;pre&gt;&lt;code class=&quot;powershell&quot;&gt;[Environment]::SetEnvironmentVariable(&quot;M2_HOME&quot;,&quot;C:\Program Files\Maven&quot;,&quot;Machine&quot;)&lt;br /&gt;
 [Environment]::SetEnvironmentVariable(&quot;MAVEN_HOME&quot;,&quot;C:\Program Files\Maven&quot;,&quot;Machine&quot;)
 &lt;/code&gt;&lt;/pre&gt;
      &lt;/li&gt;
      &lt;li&gt;
        &lt;p&gt;Update &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PATH&lt;/code&gt; environment.&lt;/p&gt;

        &lt;pre&gt;&lt;code class=&quot;powershell&quot;&gt;
$path=[Environment]::GetEnvironmentVariable(&quot;Path&quot;,&quot;Machine&quot;)&lt;br /&gt;
if($path -notcontains &quot;%M2_HOME%\bin&quot;){&lt;br /&gt;
    &amp;nbsp;&amp;nbsp;&amp;nbsp;$newPath=$path+&quot;;&quot;+ &quot;%M2_HOME%\bin&quot;&lt;br /&gt;
    &amp;nbsp;&amp;nbsp;&amp;nbsp;[Environment]::SetEnvironmentVariable(&quot;Path&quot;,$newPath,&quot;Machine&quot;)&lt;br /&gt;
}&lt;br /&gt;
&lt;/code&gt;&lt;/pre&gt;
      &lt;/li&gt;
      &lt;li&gt;Check. Run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mvn -version&lt;/code&gt; in a new cmd.&lt;/li&gt;
    &lt;/ol&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Neo4j&lt;/strong&gt;&lt;/p&gt;

    &lt;ol&gt;
      &lt;li&gt;If you haven’t, download the new Neo4j version (stored procedures are available in version 3.0 and up) from &lt;a href=&quot;http://neo4j.com/download/&quot;&gt;here&lt;/a&gt;.&lt;/li&gt;
      &lt;li&gt;Add &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NEO4J_HOME&lt;/code&gt; environment path for Neo4j folder(in my case &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;C:\Program Files\Neo4j CE 3.0.0&lt;/code&gt;).
        &lt;pre&gt;&lt;code class=&quot;powershell&quot;&gt;[Environment]::SetEnvironmentVariable(&quot;NEO4J_HOME&quot;,&quot;C:\Program Files\Neo4j CE 3.0.0&quot;,&quot;Machine&quot;)
 &lt;/code&gt;&lt;/pre&gt;
      &lt;/li&gt;
      &lt;li&gt;Clone &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;neo4j-apoc-procedures&lt;/code&gt;. Again some PowerShell - 
should be executed with admin privileges:
        &lt;pre&gt;&lt;code class=&quot;powershell&quot;&gt;git clone http://github.com/jexp/neo4j-apoc-procedures&lt;br /&gt;
 cd neo4j-apoc-procedures&lt;br /&gt;
 mvn clean install&lt;br /&gt;
 copy target/apoc-1.0.0-SNAPSHOT.jar $Env:NEO4J_HOME/plugins/ 
 &lt;/code&gt;&lt;/pre&gt;
      &lt;/li&gt;
      &lt;li&gt;
        &lt;p&gt;Edit Neo4j config.&lt;/p&gt;

        &lt;p&gt;Open &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;%userprofile%\AppData\Roaming\Neo4j Community Edition&lt;/code&gt; and add this entry (&lt;strong&gt;change the path if yours was different then in point 3.1&lt;/strong&gt;):&lt;/p&gt;

        &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dbms.directories.plugins=c:/Program\ Files/Neo4j\ CE\ 3.0.0/plugins&lt;/code&gt;&lt;/p&gt;
      &lt;/li&gt;
      &lt;li&gt;Restart Neo4j (if it was running)&lt;/li&gt;
      &lt;li&gt;Check if it is OK and enter for example &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;call apoc.help('search')&lt;/code&gt; in Neo4j cmd. And this should appear:
 	&lt;img src=&quot;/data/Neo4jStoredProcedures/StoredProceduresWorking.png&quot; alt=&quot;Neo4j stored procedures working&quot; /&gt;&lt;/li&gt;
    &lt;/ol&gt;
  &lt;/li&gt;
&lt;/ol&gt;
</description>
        <pubDate>Mon, 09 May 2016 00:00:00 +0200</pubDate>
        <link>https://IndexOutOfRange.com//Neo4jStoredProceduresWindows/</link>
        <guid isPermaLink="true">https://IndexOutOfRange.com//Neo4jStoredProceduresWindows/</guid>
      </item>
    
      <item>
        <title>Graph Connect Europe 2016</title>
        <description>&lt;img src='https://indexoutofrange.com/data/GraphConnect2016/GrahConnect.jpg' /&gt;&lt;p&gt;Last week I had the opportunity to attend &lt;a href=&quot;http://graphconnect.com/&quot;&gt;Graph Connect Europe&lt;/a&gt;. Many great sessions, but one thing topped them all - &lt;a href=&quot;http://neo4j.com/release-notes/neo4j-3-0-0/&quot;&gt;Neo4j 3.0 is out&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;And as with previous major release (it introduced &lt;a href=&quot;http://neo4j.com/developer/cypher-query-language/&quot;&gt;Cypher&lt;/a&gt;) there are many bug fixes, tweaks, speed improvements, but here are my personal favorites:
&lt;!--MORE--&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Stored procedures&lt;/strong&gt;…. Yeah I know I’ve lost you there. But those aren’t yours father’s stored procedures. Neo4j now enables to call any JVM custom function from Cypher. To start with, they published a &lt;a href=&quot;https://github.com/neo4j-contrib/neo4j-apoc-procedures&quot;&gt;repo with 99 procedures called apoc&lt;/a&gt; (and if ‘apoc’ sounds familiar, yes it’s a Matrix reference). It doesn’t make any sense to describe all of them since they are all quite well described in the GitHub repo, but just to point out the more awesome ones:
    &lt;ul&gt;
      &lt;li&gt;
        &lt;p&gt;&lt;a href=&quot;https://github.com/neo4j-contrib/neo4j-apoc-procedures#meta-graph&quot;&gt;&lt;strong&gt;Meta Graph&lt;/strong&gt;&lt;/a&gt; - to be exact &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;apoc.meta.graph&lt;/code&gt;. This procedure analyzes the whole graph and creates a meta-graph showing what node types have what relations with each other. For me a great one for exploring an unknown Neo4j database, or just to check if we didn’t screw up any relations.&lt;/p&gt;

        &lt;p&gt;To have a look how it looks lets fire the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:play movie graph&lt;/code&gt; in Neo4j cmd. It displays a widget with couple steps. The code generating the database is on the second screen. After executing the graph should look like this:&lt;/p&gt;

        &lt;p&gt;&lt;img src=&quot;/data/GraphConnect2016/MovieDatabase.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

        &lt;p&gt;As You can see in the top left corner it has nodes labeled &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Movie&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Person&lt;/code&gt; and relations named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ACTED_IN&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DIRECTED&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DIRECTED&lt;/code&gt;,&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FOLLOWS&lt;/code&gt;,&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PRODUCED&lt;/code&gt;,&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;REVIEWED&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WROTE&lt;/code&gt;.&lt;br /&gt;
  So lets see meta graph:&lt;/p&gt;

        &lt;p&gt;&lt;img src=&quot;/data/GraphConnect2016/MovieDatabase_metagraph.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

        &lt;p&gt;This graph is a XXXXS size, but with 171 nodes and 253 relations it is hard to gasp it’s structure. The meta graph makes it extremely simple and easy.&lt;/p&gt;
      &lt;/li&gt;
      &lt;li&gt;
        &lt;p&gt;&lt;a href=&quot;https://github.com/neo4j-contrib/neo4j-apoc-procedures#loading-data-from-rdbms&quot;&gt;&lt;strong&gt;Loading data from RDBMS&lt;/strong&gt;&lt;/a&gt; - It enables to connect to any database supporting JDBC connector.&lt;br /&gt;
  What is even more is the syntax:
  &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CALL apoc.load.jdbc('jdbc:derby:derbyDB','PERSON') YIELD row CREATE (:Person {name:row.name})&lt;/code&gt; &lt;br /&gt;
  for loading the whole table, or&lt;br /&gt;
  &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CALL apoc.load.jdbc('jdbc:derby:derbyDB','SELECT * FROM PERSON WHERE AGE &amp;gt; 18')&lt;/code&gt;&lt;br /&gt;
  for executing any SQL statement.&lt;/p&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Bolt&lt;/strong&gt;. A binary protocol for communicating with Neo4j. Because not long ago &lt;a href=&quot;https://ayende.com/blog/173890/the-design-of-ravendb-4-0-over-the-wire-protocol&quot;&gt;Ayende with Raven&lt;/a&gt; also announced they are moving to a binary protocol. For me it is a good signal. It means that those databases are maturing and HTTP overhead,which for millisecond operations can be bigger than time spend actually executing the query, is starting to be an issue. This would be a problem, because binary protocols are harder to implement drivers if not for the next announcement:&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Official drivers.&lt;/strong&gt; For Java, JavaScript, Python and &lt;strong&gt;.NET :)&lt;/strong&gt;. The syntax looks simple, but clear:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;csharp&quot;&gt;using (var driver = GraphDatabase.Driver(&quot;bolt://localhost&quot;))
using (var session = driver.Session())
{
   var result = session.Run(&quot;MATCH (u:User) RETURN u.name&quot;);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;No node limit.&lt;/strong&gt; This may seem like a big thing (and probably was from implementation perspective), but previously the limit was 34 bilion nodes. So it wasn’t a real limit for most cases. But good to know:)&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;GUI changes.&lt;/strong&gt; When You click on any node in the graph options will appear: 
  &lt;img src=&quot;/data/GraphConnect2016/NodeOptions.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

    &lt;p&gt;So what do these buttons do?&lt;/p&gt;

    &lt;ul&gt;
      &lt;li&gt;&lt;strong&gt;x&lt;/strong&gt; - removes the node from view (not from the database)&lt;/li&gt;
      &lt;li&gt;&lt;strong&gt;lock&lt;/strong&gt; - locks this node into position, so it won’t move when the graph is expanded.&lt;/li&gt;
      &lt;li&gt;&lt;strong&gt;arrows&lt;/strong&gt; -  it shows all relations and nodes connected to this node. So from the above we get:&lt;/li&gt;
    &lt;/ul&gt;

    &lt;p&gt;&lt;img src=&quot;/data/GraphConnect2016/NodeExpanded.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

    &lt;p&gt;And if we expand Joel Silver we get this:&lt;/p&gt;

    &lt;p&gt;&lt;img src=&quot;/data/GraphConnect2016/NodeExpanded2.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

    &lt;p&gt;And so on and so on. You get the point. Why is it cool? Because it allows to actualy walk the graph and explore it. Imagine debugging Minority Report style (only without the gloves, the screen, and being Tom Cruse)&lt;/p&gt;

    &lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/PJqbivkm0Ms&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It doesn’t mean that those are all the features. If you got hooked go check &lt;a href=&quot;http://neo4j.com/blog/neo4j-3-0-massive-scale-developer-productivity/&quot;&gt;Neo4j 3.0 blogpost on the official blog&lt;/a&gt;.&lt;/p&gt;
</description>
        <pubDate>Fri, 06 May 2016 00:00:00 +0200</pubDate>
        <link>https://IndexOutOfRange.com//GraphConnectEurope/</link>
        <guid isPermaLink="true">https://IndexOutOfRange.com//GraphConnectEurope/</guid>
      </item>
    
      <item>
        <title>How is cookit build</title>
        <description>&lt;img src='https://indexoutofrange.com/' /&gt;&lt;p&gt;The last time I described the hardware cookit is running on. Commonly referred as crap.&lt;/p&gt;

&lt;p&gt;Now it’s time for some info what exactly is running on this fine pieace of hardware.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/data/how-cookit-is-build/howIsCookitBuild.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;So, what is responsible for what?&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;The website&lt;/strong&gt; - besides the obvious of serving the &lt;a href=&quot;https://cookit.pl&quot;&gt;cookit.pl&lt;/a&gt;, it also hosts the admin panel and Hangfire dashboard. This part is almost read-only. Even the admin panel - all it does is schedule a Hangfire job and that’s it.&lt;br /&gt; 
That idea stuck with me since reading a blog post about how &lt;a href=&quot;http://highscalability.com/blog/2010/5/17/7-lessons-learned-while-building-reddit-to-270-million-page.html&quot;&gt;reddit is architectured&lt;/a&gt;. And by the way it is a must read blog for anyone interested in how the big guys design their systems.
&lt;!--MORE--&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Windows service&lt;/strong&gt; In two words: &lt;a href=&quot;http://docs.hangfire.io/en/latest/background-processing/processing-jobs-in-windows-service.html&quot;&gt;Hangfire service&lt;/a&gt;.&lt;/p&gt;

    &lt;p&gt;Why the separation and not going the easy way of hosting Hangfire in the IIS process? Couple of reasons:&lt;/p&gt;

    &lt;ul&gt;
      &lt;li&gt;&lt;strong&gt;Scaling&lt;/strong&gt; - Building this way gives an easy way for horizontally (more machines with services) or vertically (more powerful machine hosting more workers)&lt;/li&gt;
      &lt;li&gt;&lt;strong&gt;Autonomous&lt;/strong&gt; - I can easily deploy one without the effect on the other.&lt;/li&gt;
      &lt;li&gt;&lt;strong&gt;Very easy to debug&lt;/strong&gt; - This may sound strange since debugging a Windows Service isn’t the nicest thing. But since all the Hangfire service is doing is executing a function in a class, the execution can be moved to a console application. It is &lt;a href=&quot;http://docs.hangfire.io/en/latest/background-processing/processing-jobs-in-console-app.html&quot;&gt;supported by Hangfire&lt;/a&gt; and it just works. Simple as that.&lt;/li&gt;
      &lt;li&gt;&lt;strong&gt;Resistent&lt;/strong&gt; - The main process it hosts is crawling and parsing. And it used to crash a LOT. And I don’t mean throwing an exception and ending. Since it is highly parallel (hundreds of jobs) it used to create couple gigabyte log files, use so much processor that everything became unresponsive or just tried to allocate insane amount of memory and going down with a out of memory exception or stack overflow. And since the last ones can’t be caught after 5 such exceptions IIS stopped the whole pool, so the site was also down.&lt;/li&gt;
      &lt;li&gt;
        &lt;p&gt;&lt;strong&gt;Ease of deployment&lt;/strong&gt; - Few lines of PowerShell and that is it:&lt;/p&gt;

        &lt;p&gt;&lt;code&gt;
      Stop-Service $serviceName&lt;br /&gt;
      //replace the files&lt;br /&gt;
      Start-Service $serviceName
  &lt;/code&gt;&lt;/p&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Full text search(&lt;a href=&quot;http://lucene.apache.org/solr/&quot;&gt;Solr&lt;/a&gt;)&lt;/strong&gt; - Searching (the no-brainer) and providing all the data for displaying the search results page.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;SQL Server&lt;/strong&gt; -   the single point of truth. Except one case:&lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Ingredients graph&lt;/strong&gt; - while it may not seam as a equal building block as the above, it is. It fills a small problem where SQL databases suck. Modeling relations. I am talking a bit about this problem in my &lt;a href=&quot;http://indexoutofrange.com/why-dragons-need-graphs/&quot;&gt;graph talk&lt;/a&gt;, but to show what I mean:&lt;/p&gt;

    &lt;p&gt;This is how sql displays subgraph of my ingredient graph:&lt;/p&gt;

    &lt;p&gt;&lt;img src=&quot;/data/how-cookit-is-build/skladniki_sql.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

    &lt;p&gt;This view if great if You want to see data as numbers and values. For relations I prefer this (the same sub graph):&lt;/p&gt;

    &lt;p&gt;&lt;img src=&quot;/data/how-cookit-is-build/skladniki_yEd.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

    &lt;p&gt;Meet &lt;a href=&quot;https://www.yworks.com/products/yed&quot;&gt;yEd&lt;/a&gt; - a graph editing tool able of editing most graph files formats (mostly text files).&lt;/p&gt;

    &lt;p&gt;And while this data is being loaded into sql, this file is the point of truth.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Wed, 27 Apr 2016 00:00:00 +0200</pubDate>
        <link>https://IndexOutOfRange.com//How-is-cookit-build/</link>
        <guid isPermaLink="true">https://IndexOutOfRange.com//How-is-cookit-build/</guid>
      </item>
    
      <item>
        <title>The importance of running on crap</title>
        <description>&lt;img src='https://indexoutofrange.com/' /&gt;&lt;p&gt;As a pet project, I’m running &lt;a href=&quot;http://cookit.pl&quot;&gt;cookit.pl&lt;/a&gt; - a search engine for recipes, ingredients and food in general. &lt;/p&gt;

&lt;p&gt;I will be writing some more about the software side and all the problems I’ve encountered, but because &lt;a href=&quot;http://nickcraver.com/blog/2016/02/17/stack-overflow-the-architecture-2016-edition/&quot;&gt;StackExchange published it’s hardware setup&lt;/a&gt; I also felt in need to share what is my hardware.&lt;/p&gt;

&lt;p&gt;Let’s start with…
&lt;!--MORE--&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Application services:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;An IIS 8 hosted website,&lt;/li&gt;
  &lt;li&gt;SOLR hosted on Tomcat as the search engine,&lt;/li&gt;
  &lt;li&gt;SQL Server as the main source of truth ,&lt;/li&gt;
  &lt;li&gt;a windows service for doing all the work (the website is almost in read only mode).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Supporting applications:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.jetbrains.com/teamcity/&quot;&gt;TeamCity&lt;/a&gt; to run builds, test, health checks, and deploy.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.voidtools.com/&quot;&gt;Search everything&lt;/a&gt;, because Windows Search doesn’t work to good when searching through almost 3 million images and 600 000 text files.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.faststone.org/FSResizerDetail.htm&quot;&gt;FastStone Photo Resizer&lt;/a&gt; for batch image optimization, cropping and rescaling. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Some numbers&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;550 GB of images,&lt;/li&gt;
  &lt;li&gt;584,834 dumped parse result files,&lt;/li&gt;
  &lt;li&gt;~ 110 000+ recipes,&lt;/li&gt;
  &lt;li&gt;~ 3000 ingredients,&lt;/li&gt;
  &lt;li&gt;~ 150 ms main page, and ~250 ms search results response time (this varies on what is going on on the server)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And all of this runs on, there is no better way of putting it, on
&lt;img src=&quot;https://cdn0.iconfinder.com/data/icons/pixelo/32/poo.png&quot; alt=&quot;crap&quot; /&gt; (with added RAM).&lt;/p&gt;

&lt;p&gt;To be more specific on a i3-3250 CPU, 8 GB of RAM, and 1 TB hard drive (with write speed sometimes between 3-4 MB/sec).&lt;/p&gt;

&lt;p&gt;Why don’t I upgrade to a better server, or even better go to the cloud?&lt;/p&gt;

&lt;p&gt;There are many reasons, but here are some of them:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;I shouldn’t need a better server&lt;/strong&gt;. The http load that cookit is taking isn’t that big, so this machine should have plenty of computing power spare. This wasn’t true in the past, but now it uses ~15% CPU and ~1GB of RAM.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;It is auto testing my code&lt;/strong&gt;. Any performance problems will be visible much sooner. Basically if in the morning my mail isn’t flooded with error logs, or any of my monitoring services didn’t send me an auto alert, in most cases it means things are fine.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Fast is callable.&lt;/strong&gt; It isn’t true in general, but it is easier to scale a fast application, then a slow one. Running on this machine gives me a lot of space to go up without any need for major code changes.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;It is hard&lt;/strong&gt;. Running on crap is much harder than on an 8 core 32GB machine with SSD/nvme drives. It makes is easier to run into strange problems, and that means I have to learn more. And very often go outside of my comfort zone. That is a good thing.&lt;/li&gt;
  &lt;li&gt;Finally it turns out &lt;strong&gt;crap if cheep&lt;/strong&gt;. And since I’m not making any money from it, spending little is nice.&lt;/li&gt;
&lt;/ul&gt;

</description>
        <pubDate>Sat, 09 Apr 2016 00:00:00 +0200</pubDate>
        <link>https://IndexOutOfRange.com//The-importance-of-running-on-crapp/</link>
        <guid isPermaLink="true">https://IndexOutOfRange.com//The-importance-of-running-on-crapp/</guid>
      </item>
    
      <item>
        <title>Why dragons need graphs - demo files</title>
        <description>&lt;img src='https://indexoutofrange.com/' /&gt;&lt;p&gt;This describes the content of a &lt;a href=&quot;/data/why-dragons-need-graphs.zip&quot;&gt;zip package&lt;/a&gt; containing demo files from my talk &lt;strong&gt;Why dragons need graphs&lt;/strong&gt;.
There are two folders containing a create script and some query scripts showing basic, and more advanced syntax of Neo4j Cypher.
&lt;!--MORE--&gt;&lt;/p&gt;

&lt;h3 id=&quot;dragons&quot;&gt;Dragons&lt;/h3&gt;
&lt;p&gt;Demoes basic syntax of Cypher.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;00_Create.txt&lt;/code&gt; - Graph creation script&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;01_SelectAllNodes.txt&lt;/code&gt; - Displays all nodes. Neo4j by default shows all edges, so it will show the whole graph.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;02_SelectAllNodesConnectedToMonster.txt&lt;/code&gt; - Demonstrates how to filter nodes type.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;03_SelectAllNodesConnectedTo.txt&lt;/code&gt; - Adds edge type filtering.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;04_MultipleSelect.txt&lt;/code&gt; - Shows how to select multiple nodes by multiple filters.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;05_SelectStrongestMonster.txt&lt;/code&gt; - Using two way relations (from left to right, and right to left), multiple edge and node filtering selects the strongest monster.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;06_ShortestPath.txt&lt;/code&gt; - Uses Neo4j shortestPath and shortestPaths to select shortest paths between nodes.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;text-recognition&quot;&gt;Text recognition&lt;/h3&gt;
&lt;p&gt;A very simplified example how graphs can be used in text recognition tasks. It gives the answer to the sentence:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Sushi restaurants in New York that my friends like&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;All select scripts are additive (they extend the previous one)&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;00_Create.txt&lt;/code&gt; - Graph creation script&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;01_SelectMe.txt&lt;/code&gt; - Selects node responsible for ‘me’&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;02_SelectFriendsFoMe.txt&lt;/code&gt; - Selects my friends&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;03_SelectSushi.txt&lt;/code&gt; - Selects ‘sushi’ food type&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;04_SelectSushiRestaurants.txt&lt;/code&gt; - Selects sushi restaurants&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;05_SelectRestaurantsThatMyFriendsLike.txt&lt;/code&gt; - Selects sushi restaurants that my friends like.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;06_SelectRestaurantsInNewYork.txt&lt;/code&gt; - Narrows the restaurants to those in New York.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;selectAll.txt&lt;/code&gt; - Selects all edges.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Update&lt;/strong&gt;
And the video:&lt;/p&gt;

&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/Bo6uOQ-P25w&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;
</description>
        <pubDate>Mon, 24 Aug 2015 00:00:00 +0200</pubDate>
        <link>https://IndexOutOfRange.com//why-dragons-need-graphs/</link>
        <guid isPermaLink="true">https://IndexOutOfRange.com//why-dragons-need-graphs/</guid>
      </item>
    
  </channel>
</rss>