<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/"
	>

<channel>
	<title>Søren Øxenhave</title>
	<atom:link href="https://oexenhave.dk/feed/" rel="self" type="application/rss+xml" />
	<link>https://oexenhave.dk</link>
	<description>CTO at Zylinc. Building team, tech vision and architecture. Also dad and M. Sc. Telecom.</description>
	<lastBuildDate>Sun, 19 Jun 2022 13:15:40 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>http://wordpress.com/</generator>

<image>
	<url>https://oexenhave.dk/wp-content/uploads/2022/06/20201101-sox-closer.png?w=32</url>
	<title>Søren Øxenhave</title>
	<link>https://oexenhave.dk</link>
	<width>32</width>
	<height>32</height>
</image> 
<site xmlns="com-wordpress:feed-additions:1">155556042</site><cloud domain='oexenhave.dk' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' />
<atom:link rel="search" type="application/opensearchdescription+xml" href="https://oexenhave.dk/osd.xml" title="Søren Øxenhave" />
	<atom:link rel='hub' href='https://oexenhave.dk/?pushpress=hub'/>
	<item>
		<title>The Developer Onboarding Time Tracking Pitch</title>
		<link>https://oexenhave.dk/2022/06/19/the-developer-onboarding-time-tracking-pitch/</link>
		
		<dc:creator><![CDATA[oexenhave]]></dc:creator>
		<pubDate>Sun, 19 Jun 2022 13:15:40 +0000</pubDate>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[team]]></category>
		<guid isPermaLink="false">http://oexenhave.dk/?p=201</guid>

					<description><![CDATA[I recently had the pleasure of onboarding another senior developer to my team in TimeLog. As part of the onboarding, we naturally need to get all developers to start registering time. It&#8217;s not always an easy sell. However, I crafted an introduction email that I share below for others to be inspired by or to &#8230; <a href="https://oexenhave.dk/2022/06/19/the-developer-onboarding-time-tracking-pitch/" class="more-link">Continue reading <span class="screen-reader-text">The Developer Onboarding Time Tracking&#160;Pitch</span> <span class="meta-nav">&#8594;</span></a>]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">I recently had the pleasure of onboarding another senior developer to my team in TimeLog. As part of the onboarding, we naturally need to get all developers to start registering time. It&#8217;s not always an easy sell. However, I crafted an introduction email that I share below for others to be inspired by or to comment on. I&#8217;ll be happy to get some feedback on it.</p>



<p class="wp-block-paragraph"></p>



<h2 class="wp-block-heading">The email</h2>



<p class="wp-block-paragraph">Hi XX</p>



<p class="wp-block-paragraph">Naturally in TimeLog, we register our own time.&nbsp;</p>



<p class="wp-block-paragraph">For you personally, and together with your immediate manager (me), we do this primarily for the following reasons:&nbsp;</p>



<ul class="wp-block-list"><li>We can evaluate if you end up using your time on the right things according to our plan and priority (for TimeLog and for your personal growth)</li><li>We can evaluate if your balance between working and taking time off matches our expectations (in general your norm hours)</li><li>We can keep track of your vacation balance and requests for vacation </li></ul>



<p class="wp-block-paragraph">For all,&nbsp;if we together identify that it&#8217;s not as we expect, we can address this and mitigate it for the future. I will not use it for pointing fingers (unless you are complete off the charts, which in essence means that I have failed to catch it early and work with you to improve). It&#8217;s a tool for finding the right balance.&nbsp;This only works if you register the actual hours you work! I rather want to have an open discussion of &#8220;why you needed to work 60 hours in a given week&#8221; or &#8220;why you ended up with 25 hours in another&#8221; than a picture perfect 100% norm time registrations that does not fit with reality. I encourage flexibility, and that only works if we see the same picture.</p>



<p class="wp-block-paragraph">For TimeLog, we use for other reasons as well:</p>



<ul class="wp-block-list"><li>We evaluate if we use the hours we expected on projects. Budget vs. realized.</li><li>We evaluate which projects are profitable (internal projects can also have cost and financial upsides)</li><li>We calculate work-in-progress financial project value that are required for financial reporting</li></ul>



<p class="wp-block-paragraph">My philosophy&nbsp;is simple. If we satisfy&nbsp;the boxes above, I want it to be as simple as possible. It needs to be easy to track time. I don&#8217;t want to break something down in smaller pieces that I will never want to report on.</p>



<p class="wp-block-paragraph">The science is clear, register your hours as close to real-time&nbsp;as&nbsp;possible to make them more accurate. Use the desktop and mobile apps to be efficient. At the very least do it daily&nbsp;<img src="https://s0.wp.com/wp-content/mu-plugins/wpcom-smileys/twemoji/2/72x72/1f609.png" alt="😉" class="wp-smiley" style="height: 1em; max-height: 1em;" />&nbsp;Submit your timesheet every Monday before 10AM CEST.</p>



<p class="wp-block-paragraph">Having said that, the following projects in TimeLog &#8220;local&#8221; (our own instance of product) are necessary for&nbsp;you&nbsp;as part of Team Platform right now:</p>



<ul class="wp-block-list"><li>_TIM &#8211; Team Platform 2022 (P22.0086) &#8211; for work related to our team</li><li>_TIM &#8211; R&amp;D Scrum 2022 (P22.0002) &#8211; for scrum related tasks. However, as we use Kanban, it&#8217;s primarily for the shared sprint review meetings</li><li>_TIM &#8211; R&amp;D Administration 2022 (P22.0003) &#8211; for hours not covered above</li><li>_TIM &#8211; R&amp;D Internal IT 2022 (P22.0004) &#8211; if you end up doing regular IT support. Primarily used for Team Automation, but we want to be friendly for non-techies</li><li>_TIM &#8211; Administration 2022 (P22.0010) &#8211; specifically the &#8220;Mail handling&#8221; task</li><li>_TIM &#8211; Support 2022 (P22.0039) &#8211; the goal is that we don&#8217;t use this because everything we do is in backlogs. However, the world is not perfect, so register time here if you are pulled into it</li></ul>



<p class="wp-block-paragraph">You can add comments on time registrations. They are optional. I encourage&nbsp;you to add short context comments e.g. &#8220;Talk with SOX&#8221;, &#8220;BI 23563&#8221; in case we want to dive deeper.</p>



<p class="wp-block-paragraph">When you are getting involved in other projects, they will have specific projects to register on. Ask if in doubt.</p>



<hr class="wp-block-separator has-alpha-channel-opacity" />



<p class="wp-block-paragraph">Feel free to copy it, if you see it could make sense in your context. If you change anything, I would love hear about your changes so I can learn.</p>
]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">201</post-id>
		<media:content url="https://1.gravatar.com/avatar/46cfe6a6b80d60aa0ced71fc175493dc90d03a6fcab7a5540c70d9cbc060a70e?s=96&#38;d=https%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">oexenhave</media:title>
		</media:content>
	</item>
		<item>
		<title>Export NuGet Package Licenses to CSV with PowerShell</title>
		<link>https://oexenhave.dk/2020/08/13/export-nuget-package-licenses-to-csv-with-powershell/</link>
		
		<dc:creator><![CDATA[oexenhave]]></dc:creator>
		<pubDate>Thu, 13 Aug 2020 19:47:08 +0000</pubDate>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[nuget]]></category>
		<category><![CDATA[powershell]]></category>
		<guid isPermaLink="false">http://oexenhave.dk/?p=159</guid>

					<description><![CDATA[I needed a way to export all the licenses of the NuGet packages used in a .NET solution with a lot of projects, so naturally I did a search for it &#8211; surely others have faced the same problem as I. And there was. Unfortunately, the various solutions didn&#8217;t quite suit my needs. I needed &#8230; <a href="https://oexenhave.dk/2020/08/13/export-nuget-package-licenses-to-csv-with-powershell/" class="more-link">Continue reading <span class="screen-reader-text">Export NuGet Package Licenses to CSV with&#160;PowerShell</span> <span class="meta-nav">&#8594;</span></a>]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">I needed a way to export all the licenses of the NuGet packages used in a .NET solution with a lot of projects, so naturally I did a search for it &#8211; surely others have faced the same problem as I. And there was. Unfortunately, the various solutions didn&#8217;t quite suit my needs.</p>



<p class="wp-block-paragraph">I needed a CSV export of the name, current version, license URL and possibly the actual license name (e.g. MIT License, Apache License). I ended up extending the solution by <a href="https://do-it-ger.github.io/2019/03/19/Get-Licenses-from-used-NuGet-Packages/">Dominik</a>.</p>



<pre class="wp-block-code"><code>### This script only works inside the Package Manager Console in VS
### Make sure the /license/ folder exists

$output = @()

# Find all unique packages across all projects
@( Get-Project -All | Where-Object { $_.ProjectName } | ForEach-Object {
    Get-Package -ProjectName $_.ProjectName # | ? { $_.LicenseUrl }
  } ) | Sort-Object Id -Unique | ForEach-Object {
  $pkg = $_;
  Try {
     
    #Write-Host $_.Id
    #Write-Host $_.LicenseUrl
    #Write-Host $_.Version

    $licenseUrl = $_.LicenseUrl

    if ($licenseUrl -eq $null) {
      $licenseUrl = ""
    }

    if ($licenseUrl.contains('github.com')) {
      $licenseUrl = $licenseUrl.replace("/blob/", "/raw/")
    }

    $extension = ".txt"
    if ($licenseUrl.EndsWith(".md")) {
      $extension = ".md"
    }
    if ($licenseUrl.EndsWith(".html")) {
      $extension = ".html"
    }

    $filePath = (Join-Path (Get-Location) 'licenses\') + $pkg.Id + $extension;

    # Only download if it doesn't already exist
    if ((Test-Path -Path $filePath) -eq $false -and $licenseUrl.Trim() -ne "") {
      try {
        #Write-Host("Downloading... " + $licenseUrl)
        (New-Object System.Net.WebClient).DownloadFile($licenseUrl, $filePath);           
      }
      Catch &#091;system.exception] {
        Write-Host($pkg.Id + " FAILED");
      }
    }

    # Don't try to parse the HTML files, the first line doesn't include the license name anyways
    if ($extension -ne ".html" -and (Test-Path -Path $filePath) -eq $true) {
      $textLicence = Get-Content $filePath | Select-Object -First 1

      # Extensionless URLs might be HTML after all, so let's handle that
      if ($textLicence.Contains("html")) {
        $textLicence = "-"
      }
    }
    else {
      $textLicence = "-"
    }

    # Build a better output format for CSV
    $output += &#091;pscustomobject]@{
      Name    = $pkg.Id;
      Version = $pkg.Version;
      Url     = $licenseUrl;
      License = $textLicence.Trim()
    }

    Write-Host($pkg.Id + " processed");
  }
  Catch &#091;system.exception] {
    Write-Host ($error&#091;0].Exception);
    Write-Host ("Could not read license for " + $pkg.Id)
  }
}

$output | Export-Csv -Path licenseoutput.csv</code></pre>



<p class="wp-block-paragraph">The actual licenses are stored in the /licenses/ folder if required. Nuget packages without a specified license URL will be included in the list, but with empty license details.</p>
]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">159</post-id>
		<media:content url="https://1.gravatar.com/avatar/46cfe6a6b80d60aa0ced71fc175493dc90d03a6fcab7a5540c70d9cbc060a70e?s=96&#38;d=https%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">oexenhave</media:title>
		</media:content>
	</item>
		<item>
		<title>Pushing Developer Growth with an Engineering Career Ladder</title>
		<link>https://oexenhave.dk/2019/11/11/pushing-developer-growth-with-an-engineering-career-ladder/</link>
		
		<dc:creator><![CDATA[oexenhave]]></dc:creator>
		<pubDate>Mon, 11 Nov 2019 12:33:53 +0000</pubDate>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[growth]]></category>
		<guid isPermaLink="false">http://oexenhave.dk/?p=119</guid>

					<description><![CDATA[I have just completed building the first version of our Engineering Career Ladder together with our Head of R&#38;D at TimeLog. The ladder will serve as a tool for developers (and QA) as well as the technical leadership to grow each developer and in effect all teams. So why build a career ladder in the &#8230; <a href="https://oexenhave.dk/2019/11/11/pushing-developer-growth-with-an-engineering-career-ladder/" class="more-link">Continue reading <span class="screen-reader-text">Pushing Developer Growth with an Engineering Career&#160;Ladder</span> <span class="meta-nav">&#8594;</span></a>]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">I have just completed building the first version of our Engineering Career Ladder together with our Head of R&amp;D at TimeLog. The ladder will serve as a tool for developers (and QA) as well as the technical leadership to grow each developer and in effect all teams.</p>



<p class="wp-block-paragraph">So why build a career ladder in the first place? To make it very visible how to progress, gain experience and grow in our R&amp;D organization. Most people strive to advance in their career over time, but it&#8217;s not always easy to know what is expected from each individual to progress, and the technical leadership might not even know &#8211; or at least it&#8217;s subjective and implicit. We have decided to spend the time to carefully craft a career ladder to clearly set the expectations for our technical crew at each level. In effect, we are defining what a great engineer does, and what he/she is, for us. Naturally, this could vary based on the company culture and leadership, but after looking into what other companies have done, it aligns quite nicely. For example, we found inspiration in the published <a href="https://dresscode.renttherunway.com/blog/ladder">ladder </a>from the team behind Rent the Runway, the <a href="https://open.buffer.com/engineering-career-framework/">engineering career framework</a> from Buffer and <a href="https://codeascraft.com/2019/10/02/engineering-career-development-at-etsy/">engineering career development</a> at Etsy. Also the blog by <a href="https://blog.usejournal.com/the-software-engineering-job-ladder-4bf70b4c24f3">Chuck Groom</a> and a talk by <a href="https://www.youtube.com/watch?v=jA1Q94d2z10">Marco Rogers</a> is good input for crafting the ladder.</p>



<p class="wp-block-paragraph">I would have likes even more examples, so I have decided to share ours for others to get inspiration from. The TimeLog Career Ladder for Engineers ended up like this:</p>



<figure class="wp-block-image size-large is-resized"><a href="https://oexenhave.dk/wp-content/uploads/2019/11/timelog-career-ladder-for-engineers.pdf"><img data-attachment-id="123" data-permalink="https://oexenhave.dk/2019/11/11/pushing-developer-growth-with-an-engineering-career-ladder/timelog-career-ladder-for-engineers-2/" data-orig-file="https://oexenhave.dk/wp-content/uploads/2019/11/timelog-career-ladder-for-engineers.png" data-orig-size="599,422" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="TimeLog Career Ladder for Engineers" data-image-description="" data-image-caption="" data-large-file="https://oexenhave.dk/wp-content/uploads/2019/11/timelog-career-ladder-for-engineers.png?w=599" src="https://oexenhave.dk/wp-content/uploads/2019/11/timelog-career-ladder-for-engineers.png?w=599" alt="" class="wp-image-123" width="743" height="523" srcset="https://oexenhave.dk/wp-content/uploads/2019/11/timelog-career-ladder-for-engineers.png 599w, https://oexenhave.dk/wp-content/uploads/2019/11/timelog-career-ladder-for-engineers.png?w=150 150w, https://oexenhave.dk/wp-content/uploads/2019/11/timelog-career-ladder-for-engineers.png?w=300 300w" sizes="(max-width: 743px) 100vw, 743px" /></a></figure>



<p class="wp-block-paragraph">We ended up with 7 different positions, each of them defined as the scope of influence, how work is conducted (and expected) by the role, the hard competencies required, anti-patterns that a developer at a given level shouldn&#8217;t have and finally which kind of ownership is expected. </p>



<p class="wp-block-paragraph">Apart from being a great alignment tool within the department, I also see this a great tool for the technical leadership to pin-point each developer within the matrix and figure out which elements to coach and nurture. Naturally, these items can also be added to each developers&#8217; IPM (individual performance management) plans as action points to enhance on. </p>



<p class="wp-block-paragraph">Another great benefit is that the career ladder also clearly sets the scene for discussions about promotions.  Well in advance, a developer can prepare for negotiating a promotion based on the ladder &#8211; naturally other things might factor in as well, but you get the idea. By introducing a career ladder with this level of details might also cause developers to transition up and down from their current title, so I suggest to validate it carefully before making it public. In TimeLog, none of our developers needed to transition as part of introducing this, but we have got a more clear understanding of who under- and over-performs based on their current level from an objective point of view. Both cases gives great material to grow each developer to new levels. Another interesting experience is, that we now see how some colleagues at the same level, wildly differ in strengths, which fortunately correlate with their personalities.</p>



<p class="wp-block-paragraph">To make it a more visual experience, we have attempted to flag/color each statement that is either not met or require coaching based on each individual in an Excel spreadsheet. Below is the results on myself (it&#8217;s blurry by design, but you may correlate with the ladder itself, it you find the need).</p>



<figure class="wp-block-image size-large"><img width="910" height="394" data-attachment-id="128" data-permalink="https://oexenhave.dk/2019/11/11/pushing-developer-growth-with-an-engineering-career-ladder/timelog-career-ladder-for-engineers-flagged/" data-orig-file="https://oexenhave.dk/wp-content/uploads/2019/11/timelog-career-ladder-for-engineers-flagged.png" data-orig-size="910,394" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="TimeLog Career Ladder for Engineers Flagged" data-image-description="" data-image-caption="" data-large-file="https://oexenhave.dk/wp-content/uploads/2019/11/timelog-career-ladder-for-engineers-flagged.png?w=910" src="https://oexenhave.dk/wp-content/uploads/2019/11/timelog-career-ladder-for-engineers-flagged.png?w=910" alt="" class="wp-image-128" srcset="https://oexenhave.dk/wp-content/uploads/2019/11/timelog-career-ladder-for-engineers-flagged.png 910w, https://oexenhave.dk/wp-content/uploads/2019/11/timelog-career-ladder-for-engineers-flagged.png?w=150 150w, https://oexenhave.dk/wp-content/uploads/2019/11/timelog-career-ladder-for-engineers-flagged.png?w=300 300w, https://oexenhave.dk/wp-content/uploads/2019/11/timelog-career-ladder-for-engineers-flagged.png?w=768 768w" sizes="(max-width: 910px) 100vw, 910px" /></figure>



<p class="wp-block-paragraph">An interesting fact is that each individual might have a shape of flagged cells. Consider a developer which conducts work as expected according to his/her role as well as having the right competencies, but a lot of anti-patterns flagged. An inverse L shape. Or a developer with no anti-patterns and conducts work as expected, but lacks competencies. An upside-down T. Which one do you prefer? Competencies can be taught, anti-patterns require behavior change.</p>



<p class="wp-block-paragraph">One thing we noticed during this flagging exercise was that a few of the anti-patterns changed scope based on the anticipated level of developers. For example, the demands behind &#8220;Disregards opportunities where he or she can have a positive impact&#8221; is very different from Tech Lead to Software Engineer III. In any case, we decided to stick to this model for now and then evaluate after using it for a while. After all, it&#8217;s just one tool in toolbox to align and grow developers.</p>



<p class="wp-block-paragraph">I hope this gives some inspiration into creating your own career ladder. I would love to hear feedback and get questions about this.</p>
]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">119</post-id>
		<media:thumbnail url="https://oexenhave.dk/wp-content/uploads/2019/11/timelog-career-ladder-for-engineers.png" />
		<media:content url="https://oexenhave.dk/wp-content/uploads/2019/11/timelog-career-ladder-for-engineers.png" medium="image">
			<media:title type="html">TimeLog Career Ladder for Engineers</media:title>
		</media:content>

		<media:content url="https://1.gravatar.com/avatar/46cfe6a6b80d60aa0ced71fc175493dc90d03a6fcab7a5540c70d9cbc060a70e?s=96&#38;d=https%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">oexenhave</media:title>
		</media:content>

		<media:content url="https://oexenhave.dk/wp-content/uploads/2019/11/timelog-career-ladder-for-engineers.png?w=599" medium="image" />

		<media:content url="https://oexenhave.dk/wp-content/uploads/2019/11/timelog-career-ladder-for-engineers-flagged.png?w=910" medium="image" />
	</item>
		<item>
		<title>Cleaning up indices in ElasticSearch through Powershell</title>
		<link>https://oexenhave.dk/2019/09/26/cleaning-up-indices-in-elasticsearch-through-powershell/</link>
		
		<dc:creator><![CDATA[oexenhave]]></dc:creator>
		<pubDate>Thu, 26 Sep 2019 10:48:15 +0000</pubDate>
				<category><![CDATA[Uncategorized]]></category>
		<guid isPermaLink="false">http://oexenhave.dk/?p=113</guid>

					<description><![CDATA[If you, like TimeLog, are running an Elastic cluster gathering all kinds of data point for analysis of user behavior, server health and performance logs, audit logs for GDPR requirements or other logs you will at some point have to make a decision on whether to keep increasing the storage to accommodate the data points &#8230; <a href="https://oexenhave.dk/2019/09/26/cleaning-up-indices-in-elasticsearch-through-powershell/" class="more-link">Continue reading <span class="screen-reader-text">Cleaning up indices in ElasticSearch through&#160;Powershell</span> <span class="meta-nav">&#8594;</span></a>]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">If you, like <a href="https://www.timelog.com" target="_blank" rel="noreferrer noopener" aria-label="TimeLog (opens in a new tab)">TimeLog</a>, are running an Elastic cluster gathering all kinds of data point for analysis of user behavior, server health and performance logs, audit logs for GDPR requirements or other logs you will at some point have to make a decision on whether to keep increasing the storage to accommodate the data points or create a retention policy to get rid of old data.</p>



<p class="wp-block-paragraph">In the beginning it have worked for us to setup alerts when space is getting low and the using the API to manually delete old months, but as our Elastic cluster becomes a first class citizen in our IT infrastructure and strategy, we need to automate and follow stricter processes for ensuring up-time and data availability based on business demands. TimeLog hosts the Elastic cluster in AWS and (for now) we are only using it for log data for analysis. This means that we only store time series data and all of our indices will at some point be old enough to delete them all together.</p>



<p class="wp-block-paragraph">I took a decision early in the adoption of the <a rel="noreferrer noopener" aria-label="ELK stack (opens in a new tab)" href="https://www.elastic.co/what-is/elk-stack" target="_blank">ELK stack</a>, to name the indices with a named prefix and a date post-fix to easily identify those indices that could be deleted. Example of our indices are therefore: &#8220;iis-20190926&#8221;, &#8220;metricbeat-20190924&#8221; etc.</p>



<p class="wp-block-paragraph">With the standard Elastic API, I can easily query the list of indices and delete those of a certain month.</p>



<pre class="wp-block-code"><code>GET {elastic_url}/iis-*/_stats
DELETE {elastic_url}/iis-201906*</code></pre>



<p class="wp-block-paragraph">However, having to keep monitoring the storage requirements before it is too late. And trust me, you don&#8217;t want to max out the storage. I ended up creating a completely new Elastic cluster and migrating to that, because I failed to believe that after over 24 hours of &#8220;reconfiguration&#8230;&#8221; status in AWS trying to add more storage that this would ever work. It did eventually, but by that time I already migrated. In any case, I have setup the following alarms in AWS CloudWatch:</p>



<pre class="wp-block-code"><code>FreeStorageSpace &lt;= 2500 for 3 datapoints within 15 minutes
ClusterIndexWritesBlocked &gt;= 1 for 1 datapoints within 5 minutes
JVMMemoryPressure &gt;= 80 for 3 datapoints within 15 minutes
ClusterStatus.red &gt;= 1 for 1 datapoints within 5 minutes
CPUUtilization &gt;= 80 for 3 datapoints within 15 minutes</code></pre>



<p class="wp-block-paragraph">I put together that set of alarms following the <a rel="noreferrer noopener" aria-label="recommendations from Amazon (opens in a new tab)" href="https://docs.aws.amazon.com/elasticsearch-service/latest/developerguide/cloudwatch-alarms.html" target="_blank">recommendations from Amazon</a>.</p>



<p class="wp-block-paragraph">But enough about the general setup, I wanted to automate the clean up. First I looked closer at <a rel="noreferrer noopener" aria-label="Curator  (opens in a new tab)" href="https://www.elastic.co/guide/en/elasticsearch/client/curator/current/index.html" target="_blank">Curator </a>to figure out if that was a good fit for me. But for the time being it wasn&#8217;t, the step into Python and AWS Lambda was not a route I wanted to pursue. Instead I did a fall back to Powershell. The idea: Define a function where I can provide the prefix and the days to keep indices and then it will look up all the indices with a specific prefix, then parse the date in the name and delete based on that. This is the script I ended up with:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; title: ; notranslate">
$elasticUrl = &quot;https://*.es.amazonaws.com&quot;
$today = Get-Date

Function CleanElasticIndices($prefix, $daysToKeep) {

    $listIndicesUrl = ($elasticUrl + &quot;/&quot; + $prefix + &quot;-*/_stats&quot;)

    Write-Host (&quot;Fetching data from: &quot; + $listIndicesUrl)

    $jsonIndices = Invoke-WebRequest -Method Get -Uri $listIndicesUrl -UseBasicParsing | ConvertFrom-Json

    $indicesKept = 0
    foreach ($index in $jsonIndices.indices.PSObject.Properties) {
        
        $indexDateString = $index.Name.Substring($prefix.Length + 1, $index.Name.Length - $prefix.Length - 1)

        &#91;datetime]$indexDate = New-Object DateTime
        if (&#91;DateTime]::TryParseExact(  $indexDateString, 
                                        &quot;yyyyMMdd&quot;, 
                                        &#91;System.Globalization.CultureInfo]::InvariantCulture,
                                        &#91;System.Globalization.DateTimeStyles]::None,
                                        &#91;ref]$indexDate)) {
            if ($indexDate -le $today.AddDays(-$daysToKeep)) {
                Write-Host (&quot;Examining the index: &quot; + $index.Name + &quot; =&gt; &quot; + $indexDate.ToShortDateString() + &quot; =&gt; Attempting delete... &quot;) -NoNewline
                $indiceDeleteUrl = ($elasticUrl + &quot;/&quot; + $index.Name)
                $deleteResult = Invoke-WebRequest -Method Delete -Uri $indiceDeleteUrl -UseBasicParsing
                Write-Host $deleteResult

                Start-Sleep -Seconds 2
            } else {
                Write-Host (&quot;Examining the index: &quot; + $index.Name + &quot; =&gt; &quot; + $indexDate.ToShortDateString() + &quot; =&gt; keep&quot;)
                $indicesKept = $indicesKept + 1
            }
        }
    }

    Write-Host ($indicesKept.ToString() + &quot; &quot;&quot;&quot; + $prefix + &quot;&quot;&quot; indices kept on Elastic&quot;)
}

CleanElasticIndices &quot;iis&quot; (18 * 7) # 18 weeks
CleanElasticIndices &quot;metricbeat&quot; (2 * 7) # 2 weeks
</pre></div>


<p class="wp-block-paragraph">Add it to a scheduled task on a Windows box executing every day then you are good. Until the daily volume increases to a level to make the AWS CloudWatch alarms to go off again. Then you are back to the initial question: Increase storage or reduce data retention?</p>



<p class="wp-block-paragraph">I started our Elastic cluster as a proof of concept that now have turned into production use. On that journey, I have taken the time to define the definition of each index type and the related retention policy. Each the indices are defined with:</p>



<ul class="wp-block-list"><li>Index name (the prefix)</li><li>Friendly name</li><li>Description (business value)</li><li>Retention policy (in weeks)</li><li>Estimated number of entries per day</li><li>Estimated size increase per day</li></ul>



<p class="wp-block-paragraph">The estimations will allow you to bridge over to the money aspect and only argue about long term retention on indices with high daily storage demand. All in all, it makes it easier to communicate to the leadership team the value it brings, hence ensure funding. Assuming that you are actually using the cluster for something delivering business value in the first place <img src="https://s0.wp.com/wp-content/mu-plugins/wpcom-smileys/twemoji/2/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>
]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">113</post-id>
		<media:content url="https://1.gravatar.com/avatar/46cfe6a6b80d60aa0ced71fc175493dc90d03a6fcab7a5540c70d9cbc060a70e?s=96&#38;d=https%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">oexenhave</media:title>
		</media:content>
	</item>
		<item>
		<title>Single-Tenant API Conventions to the Rescue</title>
		<link>https://oexenhave.dk/2019/01/28/single-tenant-api-conventions-to-the-rescue/</link>
		
		<dc:creator><![CDATA[oexenhave]]></dc:creator>
		<pubDate>Mon, 28 Jan 2019 15:01:33 +0000</pubDate>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[api]]></category>
		<category><![CDATA[conventions]]></category>
		<category><![CDATA[style guides]]></category>
		<category><![CDATA[tech nirvana]]></category>
		<guid isPermaLink="false">http://oexenhave.dk/?p=101</guid>

					<description><![CDATA[TimeLog is special. In many ways. However for this blog post, it&#8217;s the way our product is built. TimeLog started out over 18 years ago and at that time many applications were built to service one customer only. And to scale companies just copied the whole thing (code and database) to the next customer and &#8230; <a href="https://oexenhave.dk/2019/01/28/single-tenant-api-conventions-to-the-rescue/" class="more-link">Continue reading <span class="screen-reader-text">Single-Tenant API Conventions to the&#160;Rescue</span> <span class="meta-nav">&#8594;</span></a>]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph"><a href="https://www.timelog.com">TimeLog </a>is special. In many ways. However for this blog post, it&#8217;s the way our product is built. TimeLog started out over 18 years ago and at that time many applications were built to service one customer only. And to scale companies just copied the whole thing (code and database) to the next customer and so on. Single-tenant apps became scalable. TimeLog is build that way, so all our customers have their own silo. Naturally, it gives all kinds of issues, but some good stuff as well. To the far extreme then all customers could potentially run their own version of our product &#8211; however, this is not at all the case with us. We upgrade most sites to the latest version weekly.</p>



<p class="wp-block-paragraph"><a href="https://api.timelog.com">TimeLog have various APIs</a> and have had them for years. However, we want to enhance our abilities and (finally) move to a REST-based API. We believe that our API will grow more rapidly in the future, so we need to consider more carefully how to versioning our API &#8211; especially due to our nature of being a single-tenant app.</p>



<p class="wp-block-paragraph">One of my recent initiatives as Tech Lead is, that I have started to build our definition of &#8220;Tech Nirvana&#8221; in TimeLog. An (for now) internal website gathering all our discussions and putting into short numbered rules categorized in manifestos and style guides across the different areas we operate in. Only technical stuff and focused on why-documentation &#8211; another blog post about that at another time.</p>



<p class="wp-block-paragraph">In any case, I have worked with one of my colleagues to craft the conventions we need for ensuring that our mobile app offering (Android and iOS) can function well (almost) no matter which of our single-tenant apps they are trying to access. The API style guide have a number of sections, but the notable ones for this exercise is REST API Conventions and API Consumer Conventions.</p>



<p class="wp-block-paragraph">I hope this can be used for inspiration for others &#8211; also in a multi-tenant environment.</p>



<h4 class="wp-block-heading" id="api03-rest-api-conventions">API03: REST API Conventions</h4>



<p class="wp-block-paragraph"><strong>API03.1:</strong>After a method has been released, method names, input parameters and the general output structure MUST NOT be changed in any form.</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>Because consumers of the API should not have to update their solution due to our changes.</p></blockquote>



<p class="wp-block-paragraph"><strong>API03.2:</strong>After a method has been released, additional optional input properties and output properties MAY be added.</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>Because consumers SHOULD NOT care about new elements. General renames and/or adding required fields will break existing solutions so these MUST NOT happen.</p></blockquote>



<p class="wp-block-paragraph"><strong>API03.3:</strong>If API changes violate either API03.1 or API03.2, we will always bump the API version number &#8211; and implement necessary internal backwards compatibility into existing API versions.</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>Because it allows existing integrations against our API to continue to work. For example, if a new required field is added, then for earlier API versions we automatically (internally) set a good default value to cope with the lack of API consumer input.</p></blockquote>



<p class="wp-block-paragraph"><strong>API03.4: </strong>API version and TLP version are not supposed to follow each other.</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>Because the API only needed to be increased based on API03.3. However, new functionality and other additions will follow the TLP version which will increase the version each week.</p></blockquote>



<h4 class="wp-block-heading" id="api04-api-consumer-conventions">API04: API Consumer Conventions</h4>



<p class="wp-block-paragraph"><strong>API04.1:</strong>All API consumers MUST adopt an upgrade-only distribution pattern.</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>Because of the nature of app stores, this is inherently required for Play Store and Apple Store. A user can only download the latest version of the app, so we need to cope with that limitation for all our API consumers to make our integrations as homogenous as possible.</p></blockquote>



<p class="wp-block-paragraph"><strong>API04.2:</strong>Testing API consumers SHOULD target the latest TLP version and API version only.</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>Because we upgrade all (latest TLP version) TLP sites at more or less the same time, and under 2% are held back for various reasons for a shorter period of time. Most of the time our web-app will be of a more recent TLP version than the API consumer targets.</p></blockquote>



<p class="wp-block-paragraph"><strong>API04.3:</strong>API consumers (that targets an unreleased TLP version) SHOULD support at least the latest two TLP versions.</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>Because internal API consumers might be required to release before the general TLP release, e.g. for app stores to ensure close-to-same release date of app and TLP but due to the nature of app stores, we cannot count on it. API04.4 would solve most issues, but e.g. for personal settings those are hard. If required by PO, we should add a else-statement with a message to the user that the functionality they turned on is not available yet.</p></blockquote>



<p class="wp-block-paragraph"><strong>API04.4:</strong>Favor using the hypermedia structure to decide if a UI element or feature should be available over hardcoding display rules.</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>For example, only show the “Expenses” tab (in the mobile apps) if link:Expenses is available from the root hypermedia note. This allows the server to control UI behavior (e.g. due to TLP versioning, licensing og setting constraints) in the applications without having to redo the apps. Another benefit is that the API consumer is backwards compatible (when targeting older TLP versions) for most use cases.</p></blockquote>



<p class="wp-block-paragraph"><strong>API04.5:</strong>API consumers SHOULD assume that features and functionalities are default off (until the hypermedia tree tells otherwise).</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>Because we want to ensure that the app works even when targeting different TLP versions. In general, defaults should be implemented at all levels.</p></blockquote>



<p class="wp-block-paragraph"><strong>API04.5:</strong>Favor preloading content in the background over lazy loading content. If preloading fails, lazy loading SHOULD kick in.</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>Because for mobile apps in particular requests take time, so if we can load data in the background the user gets a better experience.</p></blockquote>
]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">101</post-id>
		<media:content url="https://1.gravatar.com/avatar/46cfe6a6b80d60aa0ced71fc175493dc90d03a6fcab7a5540c70d9cbc060a70e?s=96&#38;d=https%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">oexenhave</media:title>
		</media:content>
	</item>
		<item>
		<title>Venturing into Scaling a Monolith</title>
		<link>https://oexenhave.dk/2018/12/12/venturing-into-scaling-a-monolith/</link>
		
		<dc:creator><![CDATA[oexenhave]]></dc:creator>
		<pubDate>Wed, 12 Dec 2018 14:56:57 +0000</pubDate>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[azure]]></category>
		<category><![CDATA[monolith]]></category>
		<category><![CDATA[service bus]]></category>
		<guid isPermaLink="false">http://oexenhave740096776.wordpress.com/?p=36</guid>

					<description><![CDATA[At TimeLog, we are rapidly moving into a situation where we need to discuss how we will keep up customer growth, both in terms of new and existing ones. TimeLog is a single-tenant web application, so we scaling both horizontally and vertically. However, our monolith of an application requires us to scale for peaks. It &#8230; <a href="https://oexenhave.dk/2018/12/12/venturing-into-scaling-a-monolith/" class="more-link">Continue reading <span class="screen-reader-text">Venturing into Scaling a&#160;Monolith</span> <span class="meta-nav">&#8594;</span></a>]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">At <a href="https://www.timelog.com">TimeLog</a>, we are rapidly moving into a situation where we need to discuss how we will keep up customer growth, both in terms of new and existing ones. TimeLog is a single-tenant web application, so we scaling both horizontally and vertically. However, our monolith of an application requires us to scale for peaks. It is all good and well, but it puts an overhead on the cost of operation. Currently, I am looking into ways for us to 1) reduce peaks on our main servers, and 2) allow us to dynamically scale even higher when our customers are super active.</p>



<p class="wp-block-paragraph">The peaks at TimeLog happens around month end where our customers build invoices based on the time registrations, and even more so in January where our customers analyses the last year and consolidating numbers to their ERP. Additionally, we see peaks when salary managers work out vacation and salary compensation packages.</p>



<p class="wp-block-paragraph">Microservices are still a hot topic, and for good reasons. I have used a couple of days venturing into the possibilities of TimeLog utilizing microservices and a message queue to break down our monolith &#8211; or at least release it from some of its burdens. To be honest, I don&#8217;t see us breaking our monolith in the foreseeable future, and right now I don&#8217;t think we need to. More about that later.</p>



<p class="wp-block-paragraph">Firstly in order to scale outside the actual application, we need a reliable message queue. This is the enabler for microservices. The message queue serves as a communications channel as well as a buffer. We put messages on it, it stores them for a given period of time and we can read messages from it and carry out the work. <a href="https://azure.microsoft.com/en-us/services/service-bus/">Service Bus</a>, <a href="https://aws.amazon.com/message-queue/">Message Queue</a>, <a href="https://kafka.apache.org">Distributed Streaming Platform</a>, <a href="https://azure.microsoft.com/en-us/services/event-hubs/">Event Hub</a>, <a href="https://azure.microsoft.com/en-us/services/event-grid/">Event Grid</a>. It comes in various flavors, each with different capabilities and options. There are a few terms that I found useful to describe:</p>



<ul class="wp-block-list"><li>Events &#8211; Lightweight, a notification that something happened, no expectation on how it is handled, primarily for telemetry and data streaming</li><li>Messages &#8211; Raw data, fixed expectation on how it is handled, primarily for transactions</li><li>Topic &#8211; Categorizing messages/events in the queue</li><li>Partition &#8211; Logical categorization on the server</li></ul>



<p class="wp-block-paragraph">As TimeLog is mainly driven by Microsoft technology, it was naturally for me to start looking into the possibilities in Azure. Microsoft have documented nicely how to compare the <a href="https://docs.microsoft.com/en-us/azure/event-grid/compare-messaging-services">different messaging options</a>. Summarized: Azure Event Hubs are for events (fast, at least once, no sorting), Azure Event Grid is for events (serverless, at least once, no sorting) and Azure Service Bus is for messages (heavy on config, but has all options). For completeness, Apache Kafka is for events. A found a few good <a href="https://blogs.msdn.microsoft.com/opensourcemsft/2015/08/08/choosing-between-azure-event-hub-and-kafka-what-you-need-to-know/">comparison</a> <a href="https://blog.scottlogic.com/2018/04/17/comparing-big-data-messaging.html">posts</a>.</p>



<p class="wp-block-paragraph">There are a few interesting attributes to consider for a message queue:</p>



<ul class="wp-block-list"><li>Messaging guarantee &#8211; At-least-once delivery is the supported by all the services and is easy to understand. This should also work for TimeLog.</li><li>Ordering guarantee &#8211; Default is no ordering, only the Azure Service Bus supports it native. My natural response would be that ordering is needed, however, it strikes me that it might only be because it is the same assumptions our monolith works under. In any case, if the default is no ordering, TimeLog would need to work with that premise.</li><li>Throughput and latency &#8211; With the amount of messages/events I anticipate, then none of these two are an issue. I would probably see the processing being the bottleneck instead.</li><li>Persisted storage &#8211; Up to 7 days for Azure Service Bus. I would assume that TimeLog would never need so long, customers expect data to be processed way faster anyway.</li><li>Message size &#8211; The lower the better. Azure Service Bus recommends between 10 and 256 KB. It is not for data, it is for messages.</li></ul>



<p class="wp-block-paragraph">Azure Service Bus seems to be the tool for the job in our case. However, it is important to figure out which characteristics a microservice needs to fulfill to work in this environment. Pulling a bit from the <a href="https://docs.aws.amazon.com/aws-technical-content/latest/microservices-on-aws/characteristics-of-microservices.html">AWS definition</a>: Decentralized, independent, do one thing well and a black box. Additionally, idempotent would also be a nice property especially in a at-least-once delivery model as well as in no-ordering guarantee system.</p>



<p class="wp-block-paragraph">In the traditionally sense, a microservice handles data/functionality for a particular bounded context. This means that it exposes both reads and writes API endpoints to its consumers. As I mentioned earlier for TimeLog, I don&#8217;t see us breaking up the bounded contexts just yet, but we could break functionality and let microservices handle part of the work load. This leads me to this definition:</p>



<ul class="wp-block-list"><li>Microservice = The actual functionality we need (within a certain bounded context)</li><li>A node = An instance that executes the functionality (multiple nodes doing the same thing should be possible)</li></ul>



<p class="wp-block-paragraph">This got me thinking that we would need to gradually move into this:</p>



<ul class="wp-block-list"><li>1. generation: Calculation-nodes</li><li>2. generation: Bulk-nodes</li><li>3. generation: The Real Microservice(tm)</li></ul>



<p class="wp-block-paragraph">Calculation-nodes requires the type of action and the simple input of an ID of the domain it needs to aggregate or calculate based on. It will fetch the data it needs from the database to do the calculation and manipulate the records the calculation affects. Idempotent at its core. Duplication: Fine. Out-of-order: Fine. Outage: Retry.</p>



<p class="wp-block-paragraph">Bulk-nodes requires the type of action, a list of IDs to process and parameters for the operation. Like with the calculation-node, it fetches the data it needs and starts performing the necessary action and manipulates the records according to the parameters. Only idempotent if the actual implementation allows it. Duplication and ordering now kicks in as something to consider. There are different options: Adding timestamps to messages, letting the service bus handle it and/or locking data for the application before passing the message to the queue and let the node release the data after it is done.</p>



<p class="wp-block-paragraph">The Real Microservice(tm) would need a read API and a data store of its own to handle the specific bounded context. At this point, there is no need for me to venture into that.</p>



<p class="wp-block-paragraph">A final consideration would be for <a href="https://docs.microsoft.com/en-us/azure/service-bus-messaging/service-bus-geo-dr">outages and disasters</a>, where I really like the definition by the Azure Team.&nbsp;An&nbsp;<em>outage</em>&nbsp;is the temporary unavailability without data loss.&nbsp;A&nbsp;<em>disaster</em>&nbsp;is defined as the permanent loss of the queue and with potential data loss. In both cases, messages cannot be delivered to the queue and the effect is that data is not updated for the customers. Not an ideal situation. Of course, Azure have geo-replication build-in, but (for me) a even more natural approach is to do a standard try-catch statement and let the catch store the message in a temporary queue in the database and wait for the queue to be back again. The worst-case scenario is that all calculations and aggregations will have to re-executed, but putting in both measures the risk should be very low.</p>



<p class="wp-block-paragraph">The last structural piece of the puzzle is how the data flows. I like to physically write down notes as I work my way through research and concepts, so I ended up with a drawing like this:</p>



<figure class="wp-block-image"><a href="https://oexenhave.dk/wp-content/uploads/2018/12/2018_12_12-15_48-office-lens.jpg" target="_blank" rel="noreferrer noopener"><img width="1024" height="764" data-attachment-id="79" data-permalink="https://oexenhave.dk/2018_12_12-15_48-office-lens/" data-orig-file="https://oexenhave.dk/wp-content/uploads/2018/12/2018_12_12-15_48-office-lens.jpg" data-orig-size="2143,1600" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;1&quot;}" data-image-title="Service Bus and Microservices" data-image-description="" data-image-caption="" data-large-file="https://oexenhave.dk/wp-content/uploads/2018/12/2018_12_12-15_48-office-lens.jpg?w=1024" src="https://oexenhave.dk/wp-content/uploads/2018/12/2018_12_12-15_48-office-lens.jpg?w=1024" alt="" class="wp-image-79" srcset="https://oexenhave.dk/wp-content/uploads/2018/12/2018_12_12-15_48-office-lens.jpg?w=1024 1024w, https://oexenhave.dk/wp-content/uploads/2018/12/2018_12_12-15_48-office-lens.jpg?w=2048 2048w, https://oexenhave.dk/wp-content/uploads/2018/12/2018_12_12-15_48-office-lens.jpg?w=150 150w, https://oexenhave.dk/wp-content/uploads/2018/12/2018_12_12-15_48-office-lens.jpg?w=300 300w, https://oexenhave.dk/wp-content/uploads/2018/12/2018_12_12-15_48-office-lens.jpg?w=768 768w, https://oexenhave.dk/wp-content/uploads/2018/12/2018_12_12-15_48-office-lens.jpg?w=1440 1440w" sizes="(max-width: 1024px) 100vw, 1024px" /></a></figure>



<p class="wp-block-paragraph">I plan on publishing more about this venture in the future. Let me know if you have questions or feedback on things I have missed.</p>
]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">36</post-id>
		<media:thumbnail url="https://oexenhave.dk/wp-content/uploads/2018/12/20181212_154942.jpg" />
		<media:content url="https://oexenhave.dk/wp-content/uploads/2018/12/20181212_154942.jpg" medium="image">
			<media:title type="html">20181212_154942</media:title>
		</media:content>

		<media:content url="https://1.gravatar.com/avatar/46cfe6a6b80d60aa0ced71fc175493dc90d03a6fcab7a5540c70d9cbc060a70e?s=96&#38;d=https%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">oexenhave</media:title>
		</media:content>

		<media:content url="https://oexenhave.dk/wp-content/uploads/2018/12/2018_12_12-15_48-office-lens.jpg?w=1024" medium="image" />
	</item>
		<item>
		<title>Finding places to optimize your SQL like a pro</title>
		<link>https://oexenhave.dk/2018/04/10/finding-places-to-optimize-your-sql-like-a-pro/</link>
		
		<dc:creator><![CDATA[oexenhave]]></dc:creator>
		<pubDate>Tue, 10 Apr 2018 10:55:11 +0000</pubDate>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[profiler]]></category>
		<category><![CDATA[sql]]></category>
		<guid isPermaLink="false">http://oexenhave740096776.wordpress.com/?p=27</guid>

					<description><![CDATA[Recently, I had the chance to sit down with a former colleague of mine that is now working full time as a Microsoft SQL database administrator and have a few certifications under his belt. The reason for the meet up was to help me dive deeper into some specific slow pages in our app. This &#8230; <a href="https://oexenhave.dk/2018/04/10/finding-places-to-optimize-your-sql-like-a-pro/" class="more-link">Continue reading <span class="screen-reader-text">Finding places to optimize your SQL like a&#160;pro</span> <span class="meta-nav">&#8594;</span></a>]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">Recently, I had the chance to sit down with a former colleague of mine that is now working full time as a Microsoft SQL database administrator and have a few certifications under his belt. The reason for the meet up was to help me dive deeper into some specific slow pages in our app. This blog is as much a documentation for myself as for others.</p>



<h2 class="wp-block-heading" id="looking-for-issues">Looking for issues</h2>



<p class="wp-block-paragraph">First fire up the SQL Server Profiler from the “Tools” menu.</p>



<figure class="wp-block-image"><a href="https://oexenhave.dk/wp-content/uploads/2018/12/SqlOptimize01.png" target="_blank" rel="noreferrer noopener"><img data-attachment-id="89" data-permalink="https://oexenhave.dk/sqloptimize01/" data-orig-file="https://oexenhave.dk/wp-content/uploads/2018/12/SqlOptimize01.png" data-orig-size="600,300" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="SqlOptimize01" data-image-description="" data-image-caption="" data-large-file="https://oexenhave.dk/wp-content/uploads/2018/12/SqlOptimize01.png?w=600" src="https://oexenhave.dk/wp-content/uploads/2018/12/SqlOptimize01.png" alt="" class="wp-image-89" /></a></figure>



<p class="wp-block-paragraph">Connect the profiler to the database server and customize the included events as shown below. Only Stored Procedures and TSQL completed events should be necessary for this. Click the “Show all columns” checkbox and find the column with “Row counts” as this might be usefull in order to find the queries taking up time.</p>



<figure class="wp-block-image"><a href="https://oexenhave.dk/wp-content/uploads/2018/12/SqlOptimize02.png" target="_blank" rel="noreferrer noopener"><img data-attachment-id="90" data-permalink="https://oexenhave.dk/sqloptimize02/" data-orig-file="https://oexenhave.dk/wp-content/uploads/2018/12/SqlOptimize02.png" data-orig-size="844,541" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="SqlOptimize02" data-image-description="" data-image-caption="" data-large-file="https://oexenhave.dk/wp-content/uploads/2018/12/SqlOptimize02.png?w=844" src="https://oexenhave.dk/wp-content/uploads/2018/12/SqlOptimize02.png" alt="" class="wp-image-90" /></a></figure>



<p class="wp-block-paragraph">Click the “Column Filters…” button and add in the name of the specific database by selecting the “DatabaseName” as the filter.</p>



<figure class="wp-block-image"><a href="https://oexenhave.dk/wp-content/uploads/2018/12/SqlOptimize03.png" target="_blank" rel="noreferrer noopener"><img data-attachment-id="91" data-permalink="https://oexenhave.dk/sqloptimize03/" data-orig-file="https://oexenhave.dk/wp-content/uploads/2018/12/SqlOptimize03.png" data-orig-size="842,538" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="SqlOptimize03" data-image-description="" data-image-caption="" data-large-file="https://oexenhave.dk/wp-content/uploads/2018/12/SqlOptimize03.png?w=842" src="https://oexenhave.dk/wp-content/uploads/2018/12/SqlOptimize03.png" alt="" class="wp-image-91" /></a></figure>



<p class="wp-block-paragraph">Now the trick is to pause the trace. Clear the trace. Both from the toolbar menu. Navigate to the page you want to profile. To make it easier for yourself make sure no one else is using the database. Start the trace and perform the action(s) you want to profile. Pause the trace.</p>



<p class="wp-block-paragraph">Two things to look for in the log.</p>



<ol class="wp-block-list"><li>Number of rows (bottom right corner) &#8211; which is somewhat equal to the number of single requests to the database required for the action(s). Too many requests obviously slow down the performance. Look for duplicate requests (add single request cache). Look for patterns, like fetching a lot of single records instead of fetching them in bulk.</li><li>Look for events with high numbers in “Reads”, “Duration” and/or “RowCounts”. Naturally, duration is the one hurting your performance but the two others might also pinpoint potential issues with high CPU and memory on the server.</li></ol>



<h2 class="wp-block-heading" id="diving-deeper">Diving deeper</h2>



<p class="wp-block-paragraph">After identifying a request, you want to dive deeper into, copy the request including parameters and paste it into Microsoft SQL Server Management Studio. Add the extra line for the magic of getting request statistics and time. Also ensure you include the execution plan (CTRL+M or “Query &gt; Include Actual Execution Plan…”) and client statistics (SHIFT+ALT+S or “Query &gt; Include Client Statistics”).</p>



<figure class="wp-block-image"><a href="https://oexenhave.dk/wp-content/uploads/2018/12/SqlOptimize04.png" target="_blank" rel="noreferrer noopener"><img data-attachment-id="92" data-permalink="https://oexenhave.dk/sqloptimize04/" data-orig-file="https://oexenhave.dk/wp-content/uploads/2018/12/SqlOptimize04.png" data-orig-size="579,208" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="SqlOptimize04" data-image-description="" data-image-caption="" data-large-file="https://oexenhave.dk/wp-content/uploads/2018/12/SqlOptimize04.png?w=579" src="https://oexenhave.dk/wp-content/uploads/2018/12/SqlOptimize04.png" alt="" class="wp-image-92" /></a></figure>



<figure class="wp-block-image"><a href="https://oexenhave.dk/wp-content/uploads/2018/12/SqlOptimize05.png" target="_blank" rel="noreferrer noopener"><img data-attachment-id="93" data-permalink="https://oexenhave.dk/sqloptimize05/" data-orig-file="https://oexenhave.dk/wp-content/uploads/2018/12/SqlOptimize05.png" data-orig-size="705,236" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="SqlOptimize05" data-image-description="" data-image-caption="" data-large-file="https://oexenhave.dk/wp-content/uploads/2018/12/SqlOptimize05.png?w=705" src="https://oexenhave.dk/wp-content/uploads/2018/12/SqlOptimize05.png" alt="" class="wp-image-93" /></a></figure>



<p class="wp-block-paragraph">Execute the command. Notice the new tabs in the results pane. The “Messages” tab now include timings and data statistics for the command. In particular, look for high “Scan count” and “Logical reads”. You may use&nbsp;<a href="http://statisticsparser.com/">statisticsparser.com</a>&nbsp;to make it easier to read. The table associated with a high number should spark your interest. It could be due to a bad join, an inner select or missing indexes.</p>



<p class="wp-block-paragraph">Additionally, look in the “Execution Plan” tab. Look through each of the inline parts and look for large graphs and in them look for the element with the highest cost percent. Also, you want to look for “Missing Index” notes. If it appears, right click that line and choose the “Missing Index Details…”. Examine the index and the fields it includes. Give it a name and try adding it, then profile again.</p>



<p class="wp-block-paragraph">Just a few pointers about indexes. Only one clustered index per table and should only be used for integers – never ever guids. Non-clustered indexes can either have an INCLUDE part or not. If you do not specify which fields to include it will just be an index for quick searches, but after a successful find it will do a SELECT to get the fields it needs for the rest of the query. However, to eliminate that additional SELECT then the index needs the INCLUDE part and all fields required in the original query. If you have a SELECT * FROM then you need all the fields in the include as well. It also means that is expensive in terms of hard drive space keeping the index and processor power needed to update the index upon inserting new records. So it is necessary to consider both options. Also, before adding indexes everywhere after a few iterations of performance optimizing do consider that some of them might overlap so they are not all necessary.</p>



<p class="wp-block-paragraph">That is the essence of my takeaways. Are there more I should have added?</p>
]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">27</post-id>
		<media:content url="https://1.gravatar.com/avatar/46cfe6a6b80d60aa0ced71fc175493dc90d03a6fcab7a5540c70d9cbc060a70e?s=96&#38;d=https%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">oexenhave</media:title>
		</media:content>

		<media:content url="https://oexenhave.dk/wp-content/uploads/2018/12/SqlOptimize01.png" medium="image" />

		<media:content url="https://oexenhave.dk/wp-content/uploads/2018/12/SqlOptimize02.png" medium="image" />

		<media:content url="https://oexenhave.dk/wp-content/uploads/2018/12/SqlOptimize03.png" medium="image" />

		<media:content url="https://oexenhave.dk/wp-content/uploads/2018/12/SqlOptimize04.png" medium="image" />

		<media:content url="https://oexenhave.dk/wp-content/uploads/2018/12/SqlOptimize05.png" medium="image" />
	</item>
		<item>
		<title>Running Jekyll on Ubuntu on Windows</title>
		<link>https://oexenhave.dk/2017/01/22/running-jekyll-on-ubuntu-on-windows/</link>
		
		<dc:creator><![CDATA[oexenhave]]></dc:creator>
		<pubDate>Sun, 22 Jan 2017 10:20:35 +0000</pubDate>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[jekyll]]></category>
		<guid isPermaLink="false">http://oexenhave740096776.wordpress.com/?p=45</guid>

					<description><![CDATA[Last year, I moved my site to use Jekyll and hosted it on Github pages. It works really well, but it took me several attempts to actually run the compilation and serving on my Windows machine. It sounds like a simple task, after all entering development mode in Windows 10 and installling the Linux subsystem &#8230; <a href="https://oexenhave.dk/2017/01/22/running-jekyll-on-ubuntu-on-windows/" class="more-link">Continue reading <span class="screen-reader-text">Running Jekyll on Ubuntu on&#160;Windows</span> <span class="meta-nav">&#8594;</span></a>]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">Last year, I moved my site to use Jekyll and hosted it on Github pages. It works really well, but it took
me several attempts to actually run the compilation and serving on my Windows machine. It sounds like a 
simple task, after all entering development mode in Windows 10 and installling the Linux subsystem should
allow easier access to libraries normally only easily available for Linux users. However, I have had issues
installing the jekyll bundle every time I have tried on a new PC. This time, I have had similar issues, so
I decided to note down the links and resources I have used &#8211; if nothing else, then just for next time I
have to do it myself.</p>



<h2 class="wp-block-heading" id="getting-started">Getting started</h2>



<p class="wp-block-paragraph"><a href="http://daverupert.com/2016/04/jekyll-on-windows-with-bash/]">Jekyll on Bash on Ubuntu on Windows</a> has been my
goto guide this time and combined with this <a href="http://michaelchelen.net/81fa/install-jekyll-2-ubuntu-14-04/">Install Jekyll 2 on Ubuntu 14.04</a>.
Just for reference, I have copied part of the commands to this page. <a href="https://msdn.microsoft.com/en-us/commandline/wsl/install_guide">The official Microsoft
reference for installing</a>.</p>



<ol class="wp-block-list"><li>In Windows 10 &gt; Settings &gt; Updates &amp; Security &gt; For developers &gt; Check “Developer Mode”</li><li>Open “Windows Features” &gt; Check “Windows Subsystem for Linux”. Restart.</li><li>From the run dialog, run “bash”</li><li>Run the following commands:</li></ol>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">
$ sudo -s
$ apt update
$ apt install make gcc
$ apt-add-repository ppa:brightbox/ruby-ng
$ apt update
$ apt install ruby2.3 ruby2.3-dev ruby-switch
$ ruby -v
$ ruby-switch --set ruby2.3
$ gem install jekyll
</pre></div>


<h2 class="wp-block-heading" id="various-install-issues">Various install issues</h2>



<p class="wp-block-paragraph">I got some pointers from the general install guide from the <a href="http://www.nokogiri.org/tutorials/installing_nokogiri.html">official install guide of nokogiri</a>.</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">
Building nokogiri using system libraries.
libxml2 version 2.6.21 or later is required!
*** extconf.rb failed ***
</pre></div>


<p class="wp-block-paragraph">Solution (<a href="https://github.com/sparklemotion/nokogiri/issues/1099">reference</a>): bundle config build.nokogiri –use-system-libraries –with-xml2-include=/usr/local/opt/libxml2/include/libxml2</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">
/var/lib/gems/2.3.0/gems/bundler-1.14.1/lib/bundler/runtime.rb:40:in 'block in setup': You have already activated addressable 2.5.0, but your Gemfile requires addressable 2.4.0. Prepending `bundle exec` to your command may solve this. (Gem::LoadError)

or

jekyll 3.0.5 | Error:  Invalid argument - Failed to watch "/mnt/c/Projects/Oexenhave/.git/hooks": the given event mask contains no legal events; or fd is not an inotify file descriptor.
</pre></div>


<p class="wp-block-paragraph">Solution (<a href="https://github.com/jekyll/jekyll/issues/5233">reference</a>): bundle exec jekyll serve &#8211; -force_polling</p>
]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">45</post-id>
		<media:content url="https://1.gravatar.com/avatar/46cfe6a6b80d60aa0ced71fc175493dc90d03a6fcab7a5540c70d9cbc060a70e?s=96&#38;d=https%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">oexenhave</media:title>
		</media:content>
	</item>
		<item>
		<title>Entity Framework Adventures &#8211; Concurrency Troubles</title>
		<link>https://oexenhave.dk/2016/10/31/entity-framework-adventures-concurrency-troubles/</link>
		
		<dc:creator><![CDATA[oexenhave]]></dc:creator>
		<pubDate>Mon, 31 Oct 2016 10:23:53 +0000</pubDate>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[entity framework]]></category>
		<guid isPermaLink="false">http://oexenhave740096776.wordpress.com/?p=49</guid>

					<description><![CDATA[I’m building a new project to automate various DevOps tasks, I decided to go for Entity Framework as handling the database. I have a standard SSDT project for the actual database structure, but in the service-project the code part of it is through an EDMX file. Out of the box, the T4 template generates data &#8230; <a href="https://oexenhave.dk/2016/10/31/entity-framework-adventures-concurrency-troubles/" class="more-link">Continue reading <span class="screen-reader-text">Entity Framework Adventures &#8211; Concurrency&#160;Troubles</span> <span class="meta-nav">&#8594;</span></a>]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">I’m building a new project to automate various DevOps tasks, I decided to go for Entity Framework as handling the database. I have a standard SSDT project for the actual database structure, but in the service-project the code part of it is through an EDMX file. Out of the box, the T4 template generates data classes and a class inheriting from DbContext. No news here. I also decided to go for Autofac for dependency injection and wire up the whole thing. It should be a straight forward task and many blog posts are available for making this happen. However, I ran into some non-trivial issues when I added a few extra background threads to the mix.</p>



<p class="wp-block-paragraph">The idea behind the application is to handle daily routines like patching and provisioning new sites in a 
seemingly old-school application server provider model aka. each customer has its own virtual IIS site and 
database. A silo structure. This structure has benefits and drawbacks. The main drawback is that it makes 
it a bit more cumbersome to for example update all of them with a new patch or provide the necessary tools 
for developers to access and debug production data. This is where this application has its place. Its 
construction and various innerworkings would be interesting for another write up.</p>



<p class="wp-block-paragraph">Anyway, the jobs need to run in the background so a few extra threads need be spun up. The most used ways 
setting the DbContext up does not work for multithreading scenarios where they are not all tied directly 
to a IIS request thread (InstancePerLifetimeScope) – or at least that’s the combinations I have found. The 
go to guide for the various usages of the DbContext would be the blog post “Managing DbContext the right 
way with Entity Framework 6: an in-depth guide” by Mehdi El Gueddari.</p>



<p class="wp-block-paragraph">The solution, I ended up with was to instantiate the DbContext in a using construct as often as necessary. 
Even multiple times in the same request. Creating the same instance again and again is that efficient? 
Apparently for this object it is according to <a href="https://blogs.msdn.microsoft.com/alexj/2009/05/07/tip-18-how-to-decide-on-a-lifetime-for-your-objectcontext/">How to decide on a lifetime for your ObjectContext</a>.
No worries. I wanted to have a custom setup of the connection string and lazy loading settings, so I ended 
up constructing a partial class that handles the instance creation like below:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">
public partial class TCAMEntities
{
    public TCAMEntities(DbConnection nameOrConnectionString) : base(nameOrConnectionString, true) 
    {
    }

    public static TCAMEntities Instance
    {
        get
        {
            EntityConnectionStringBuilder _entityBuilder = new EntityConnectionStringBuilder
            {
                Provider = "System.Data.SqlClient",
                // E.g. data source=localhost;initial catalog=tcam;persist security info=True;user id=sa;password=sa;multipleactiveresultsets=True;application name=EntityFramework
                ProviderConnectionString = MachineConfigurationManager.AppSettings&#91;"ConnectionString"],
                Metadata = @"res://*/DAL.TCAMModel.csdl|res://*/DAL.TCAMModel.ssdl|res://*/DAL.TCAMModel.msl"
            };

            var _result = new TCAMEntities(new EntityConnection(_entityBuilder.ToString()));
            _result.Configuration.LazyLoadingEnabled = false;
            return _result;
        }
    }
}
</pre></div>


<p class="wp-block-paragraph">And it simplifies the actual usage to a setup like:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">
public IEnumerable&lt;IClientView&gt; GetAll()
{
    using (var _entities = TCAMEntities.Instance)
    {
        return _entities.Clients.Where(c =&gt; c.IsActive).Select(Convert).ToArray();
    }
}
</pre></div>


<p class="wp-block-paragraph">However, the drawback is that in some situations the nature of EF would lazy load stuff, but as the context 
is disposed that’s not possible. To get around it, I use ToArray() or similar. The upside is that I don’t by 
accident lazy load all kinds of stuff in controllers.</p>



<p class="wp-block-paragraph">This works reasonable well for the current load of the application. I have one place where I execute two ajax 
calls at the same time targeting the same table, this gives deadlock issues. Therefore, I implemented a simple 
lock for that call for now.</p>



<p class="wp-block-paragraph">In case you wonder, the <a href="https://gist.github.com/oexenhave/6502176cb2987632896342ec03d64f2f">MachineConfigurationManager</a> 
class is a custom class that generates a machine specific config file that can be ignored when committing, 
but still falls back to web.config for debug values.</p>
]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">49</post-id>
		<media:content url="https://1.gravatar.com/avatar/46cfe6a6b80d60aa0ced71fc175493dc90d03a6fcab7a5540c70d9cbc060a70e?s=96&#38;d=https%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">oexenhave</media:title>
		</media:content>
	</item>
		<item>
		<title>Proposed SCRUM Retrospective Agenda</title>
		<link>https://oexenhave.dk/2016/05/17/proposed-scrum-retrospective-agenda/</link>
		
		<dc:creator><![CDATA[oexenhave]]></dc:creator>
		<pubDate>Tue, 17 May 2016 09:25:34 +0000</pubDate>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[agile]]></category>
		<category><![CDATA[retrospective]]></category>
		<category><![CDATA[scrum]]></category>
		<guid isPermaLink="false">http://oexenhave740096776.wordpress.com/?p=53</guid>

					<description><![CDATA[As a working ScrumMaster at TimeLog, I have tried to come up with an agenda for each of meetings in a Scrum cycle. At the moment, I find the retrospective meeting the hardest to keep a good pace in order to not exceed 2 hours and make sure that the team covers the most important &#8230; <a href="https://oexenhave.dk/2016/05/17/proposed-scrum-retrospective-agenda/" class="more-link">Continue reading <span class="screen-reader-text">Proposed SCRUM Retrospective&#160;Agenda</span> <span class="meta-nav">&#8594;</span></a>]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">As a working ScrumMaster at TimeLog, I have tried to come up with an agenda for each of meetings in a Scrum cycle. At the moment, I find the retrospective meeting the hardest to keep a good pace in order to not exceed 2 hours and make sure that the team covers the most important items each time.In this blog post, I’ll try to outline our model for getting through the retrospective in an orderly fashion.</p>



<p class="wp-block-paragraph">Currently, we have been using the proposed agenda for the last dozen sprints and for now it works for us.
We are also using the agenda in its raw format for doing a summary. At the moment, I simply create
additional sub bullets for comments and discussions as the team goes along. We store the agenda on a
SharePoint wiki and the ScrumMaster (me) creates a new wiki for each retrospective including the next
retrospective meeting coming up.</p>



<ol class="wp-block-list"><li>How was the sprint? (<a href="http://whatis.techtarget.com/definition/fist-to-five-fist-of-five​">Fist-to-five-method</a>)</li><li>Positive stories from the sprint (from each team member)</li><li>Looking back at decisions from last retrospective. Rollback or keep?</li><li>What is the number one challenge this sprint or what are number 
one thing that is holding us back from performing better? (from each 
team member)</li><li>Reflect on possible reasons for these challenge. (<a href="https://en.wikipedia.org/wiki/5_Whys">5-Whys-method</a>)</li><li>Identify possible solutions and decide on which to do in the next sprint</li><li>Any of them requires a future backlog item due to its size?</li><li>Discuss and vote for change requests to any Scrum artifact (from any team member)​</li><li>Ideas for discussion</li><li>​Feedback on the retrospective​</li></ol>



<p class="wp-block-paragraph"><strong>Item 1</strong> &#8211; Provides a super quick feedback from the entire team about the sprint just completed. Everyone
shares their thoughts without any bias. We write down each number to calculate an average (however, for now
we just store it as such without looking at the averages over time). The team member with the highest vote
gives a brief explanation of why that is, and so does the lowest. Quickly everyone is one the same page
and it opens everyone’s minds about the current team spirit.</p>



<p class="wp-block-paragraph"><strong>Item 2</strong> &#8211; Each team member in the team must share one positive story or leaning from the sprint. This
helps setting a positive focus to kick of the retrospective (which easily focuses on all the bad stuff).
I have experienced it being hard to get everyone to participate, so I have introduced tagging each story
with initials and this implicitly introduces some peer pressure to participate.</p>



<p class="wp-block-paragraph"><strong>Item 3</strong> &#8211; ScrumMaster before the meeting appends any decisions or trial as sub bullets and each item
is discussed again in order to determine if the effect was good or bad. If the team are holding back 
on an item, I introduce a simple <a href="http://www.conferencesthatwork.com/index.php/event-design/2012/06/testing-consensus-using-roman-voting/">Roman vote</a>
to get to a consensus. Currently, we don’t have a fixed procedure for keepers, but if an initiative
last for more than two sprints the idea is to turn it into a rule in the Working Agreement or Definition
of Done.</p>



<p class="wp-block-paragraph"><strong>Item 4</strong> &#8211; The core question for the retrospective, we need to improve, but we need to find the best spot.
Each team member should present at least one challenge. The trick is to avoid going too quickly into “why”
and solutions for a given challenge. Each team member should have a change to add an item or add on to an
existing one. Again tagging each challenge with initials might be needed.</p>



<p class="wp-block-paragraph"><strong>Item 5</strong> &#8211; The ScrumMaster picks items from the list of challenges based on number of mentions or gut
feel at this point. The number of items to go through is chosen based on time and extend. The ScrumMaster
should steer the team towards finding reasons, not solutions. Keep asking “why?” is an interesting
exercise for getting concrete and quantifiable reasons.</p>



<p class="wp-block-paragraph"><strong>Item 6</strong> &#8211; This item might run simultaneous with item 5 in order to tie the knots after getting to good
reasons to a challenge. Each item should end up with a couple of suggested actions. The team must vote
on which of the suggestions to try out in the coming sprint. Voting could be done with Roman Vote or 
<a href="https://en.wikipedia.org/wiki/Dotmocracy">Dot-voting</a>. The ScrumMaster is responsible to ensure the
team remembers them in the sprint.</p>



<p class="wp-block-paragraph"><strong>Item 7</strong> &#8211; A solution to a challenge might end up being a spike/research backlog item. The team 
and Product Owner should establish on a case-by-case basis if it needs to be prioritized with everything
else or it could be pushed to any sprint as a team task (a backlog item created and prioritized by the team).</p>



<p class="wp-block-paragraph"><strong>Item 8</strong> &#8211; During the sprint each team member may add sub items to this list and state which Scrum
artifact the change should be done to. Each item is taken in turn and voted to be included in an artifact.</p>



<p class="wp-block-paragraph"><strong>Item 9</strong> &#8211; During the sprint subjects might have been raised during the Daily Scrums that require more
discussions and time. These are added here a head of time and taken in turn during the meeting. They could
also end with backlog items, artifact elements or trials for the next sprint.</p>



<p class="wp-block-paragraph"><strong>Item 10</strong> &#8211; Slot for giving feedback to the ScrumMaster about the agenda and the retrospective meeting in
general.</p>



<p class="wp-block-paragraph">I would be happy to hear from other Scrum teams if they are going through other agendas in their retrospectives.</p>
]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">53</post-id>
		<media:content url="https://1.gravatar.com/avatar/46cfe6a6b80d60aa0ced71fc175493dc90d03a6fcab7a5540c70d9cbc060a70e?s=96&#38;d=https%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">oexenhave</media:title>
		</media:content>
	</item>
	</channel>
</rss>
