<?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/"
	>

<channel>
	<title>Freek Paans</title>
	<atom:link href="https://www.freekpaans.nl/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.freekpaans.nl</link>
	<description>Opinions on DDD, distributed systems and developing better software</description>
	<lastBuildDate>Wed, 30 Jan 2019 14:03:57 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=5.3.21</generator>
	<item>
		<title>Zabbix + ElasticSearch monitoring</title>
		<link>https://www.freekpaans.nl/2019/01/zabbix-es-monitoring/</link>
				<comments>https://www.freekpaans.nl/2019/01/zabbix-es-monitoring/#respond</comments>
				<pubDate>Wed, 30 Jan 2019 14:03:50 +0000</pubDate>
		<dc:creator><![CDATA[Freek Paans]]></dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.freekpaans.nl/?p=3300</guid>
				<description><![CDATA[<p>At my current client, we use a combination of ElasticSearch and Zabbix for system and application monitoring. For your pleasure, I wrote a quick tutorial on how to set up both, and have them talk to each other. Enjoy.</p>
<p>The post <a rel="nofollow" href="https://www.freekpaans.nl/2019/01/zabbix-es-monitoring/">Zabbix + ElasticSearch monitoring</a> appeared first on <a rel="nofollow" href="https://www.freekpaans.nl">Freek Paans</a>.</p>
]]></description>
								<content:encoded><![CDATA[<p>At my current client, we use a combination of ElasticSearch and Zabbix for system and application monitoring. For your pleasure, I wrote <a href="https://github.com/FreekPaans/zabbix-elastic-tutorial">a quick tutorial</a> on how to set up both, and have them talk to each other. Enjoy.</p>
<p>The post <a rel="nofollow" href="https://www.freekpaans.nl/2019/01/zabbix-es-monitoring/">Zabbix + ElasticSearch monitoring</a> appeared first on <a rel="nofollow" href="https://www.freekpaans.nl">Freek Paans</a>.</p>
]]></content:encoded>
							<wfw:commentRss>https://www.freekpaans.nl/2019/01/zabbix-es-monitoring/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
							</item>
		<item>
		<title>Bitcoin multinode / multiwallet test network</title>
		<link>https://www.freekpaans.nl/2018/04/bitcoin-multinode-multiwallet-test-network/</link>
				<comments>https://www.freekpaans.nl/2018/04/bitcoin-multinode-multiwallet-test-network/#respond</comments>
				<pubDate>Fri, 13 Apr 2018 19:49:36 +0000</pubDate>
		<dc:creator><![CDATA[Freek Paans]]></dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.freekpaans.nl/?p=3297</guid>
				<description><![CDATA[<p>I put together a small repo which allows you to run a private bitcoin network. It works on top of bitcoin&#8217;s regtest capability, and uses docker to put together a small network that links a couple of bitcoin nodes. This allows you to test some bitcoin functionality that a single bitcoin regtest node can&#8217;t such... <span class="more"><a class="more-link" href="https://www.freekpaans.nl/2018/04/bitcoin-multinode-multiwallet-test-network/">Continue reading <span class="meta-nav">&#8594;</span></a></span></p>
<p>The post <a rel="nofollow" href="https://www.freekpaans.nl/2018/04/bitcoin-multinode-multiwallet-test-network/">Bitcoin multinode / multiwallet test network</a> appeared first on <a rel="nofollow" href="https://www.freekpaans.nl">Freek Paans</a>.</p>
]]></description>
								<content:encoded><![CDATA[<p>I put together a small repo which allows you to run <a href="https://github.com/FreekPaans/bitcoin-multi-node-regtest">a private bitcoin network</a>. It works on top of bitcoin&#8217;s regtest capability, and uses docker to put together a small network that links a couple of bitcoin nodes. This allows you to test some bitcoin functionality that a single bitcoin regtest node can&#8217;t such as testing what happens when a transaction does not affect your wallet.</p>
<p>The post <a rel="nofollow" href="https://www.freekpaans.nl/2018/04/bitcoin-multinode-multiwallet-test-network/">Bitcoin multinode / multiwallet test network</a> appeared first on <a rel="nofollow" href="https://www.freekpaans.nl">Freek Paans</a>.</p>
]]></content:encoded>
							<wfw:commentRss>https://www.freekpaans.nl/2018/04/bitcoin-multinode-multiwallet-test-network/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
							</item>
		<item>
		<title>Anatomy of a geth full sync</title>
		<link>https://www.freekpaans.nl/2018/04/anatomy-of-a-geth-full-sync/</link>
				<comments>https://www.freekpaans.nl/2018/04/anatomy-of-a-geth-full-sync/#respond</comments>
				<pubDate>Fri, 13 Apr 2018 05:11:54 +0000</pubDate>
		<dc:creator><![CDATA[Freek Paans]]></dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.freekpaans.nl/?p=3279</guid>
				<description><![CDATA[<p>Last week I blogged about my experiences doing a geth fast sync. The last thing I did back then was start a full sync on the same hardware. Things took a bit longer: whereas the fast sync completed in about 8 hours, the full sync took a little over 9 days. In this post my... <span class="more"><a class="more-link" href="https://www.freekpaans.nl/2018/04/anatomy-of-a-geth-full-sync/">Continue reading <span class="meta-nav">&#8594;</span></a></span></p>
<p>The post <a rel="nofollow" href="https://www.freekpaans.nl/2018/04/anatomy-of-a-geth-full-sync/">Anatomy of a geth full sync</a> appeared first on <a rel="nofollow" href="https://www.freekpaans.nl">Freek Paans</a>.</p>
]]></description>
								<content:encoded><![CDATA[<style type="text/css">
table.left * {
  text-align: left;
}
</style>
<p><a href="http://www.freekpaans.nl/2018/04/anatomy-geth-fast-sync/">Last week</a> I blogged about my experiences doing a geth fast sync. The last thing I did back then was start a <strong>full sync</strong> on the same hardware. Things took a bit longer: whereas the fast sync completed in about 8 hours, the full sync took a little over 9 days. In this post my report.</p>
<h2>Specs</h2>
<p>I used an Azure Standard_L16s storage optimized VM. This beast has 16 cores, 128 gigs of memory and 80,000 IOPS and 800MBps throughput on its temporary storage disk. Ought to be enough you&#8217;d say. I started geth with <code>./geth --maxpeers 25 --cache 64000 --verbosity 4 --syncmode full &gt;&gt; geth.log 2&gt;&amp;1</code></p>
<h3>Overview</h3>
<table class="left">
<tbody>
<tr>
<td>Azure VM Instance</td>
<td>Standard_L16s</td>
</tr>
<tr>
<td>OS</td>
<td>Ubuntu 16.04.4 LTS</td>
</tr>
<tr>
<td>CPU</td>
<td>16 cores</td>
</tr>
<tr>
<td>Memory</td>
<td>128GB</td>
</tr>
<tr>
<td>Disk IOPS (spec)</td>
<td>80,000</td>
</tr>
<tr>
<td>Disk throughput (spec)</td>
<td>800 MBps</td>
</tr>
<tr>
<td>Geth version</td>
<td>geth-linux-amd64-1.8.3-329ac18e</td>
</tr>
<tr>
<td>Geth maxpeers</td>
<td>25</td>
</tr>
<tr>
<td>Geth cache</td>
<td>64,000MB</td>
</tr>
<tr>
<td>Sync mode</td>
<td><strong>full</strong></td>
</tr>
</tbody>
</table>
<h2>Results</h2>
<table class="left">
<tbody>
<tr>
<td>Start time</td>
<td>3 apr 2018 06:26:58 UTC</td>
</tr>
<tr>
<td>End time *</td>
<td>12 apr 2018 08:02:37 UTC</td>
</tr>
<tr>
<td>Total duration</td>
<td>9d 1h 35m 39s</td>
</tr>
<tr>
<td>Imported blocks at catch up time</td>
<td>5,426,156</td>
</tr>
<tr>
<td>Total imported state trie entries</td>
<td>? (Don&#8217;t know how to check and if that&#8217;s even relevant for full sync)</td>
</tr>
<tr>
<td>du -s ~/.ethereum</td>
<td>244,752,908 (234G)</td>
</tr>
</tbody>
</table>
<p>* End time defined as first single-block &#8220;Imported new chain segment&#8221; log message for which al subsequent &#8220;Imported new chain segment&#8221; log messages have blocks=1</p>
<h3>CPU/Load/Memory</h3>
<p>(It&#8217;s too much of an effort to cut off the chart up until the actual start, so please bear in mind that it starts at 3 apr 6 utc (graph is in UTC+02:00). Sorry, let me know if someone needs more high res charts.) </p>
<p><img src="http://www.freekpaans.nl/wp-content/uploads/2018/04/full-cpu-util.png" alt="" width="1658" height="438" class="alignnone size-full wp-image-3284" srcset="https://www.freekpaans.nl/wp-content/uploads/2018/04/full-cpu-util.png 1658w, https://www.freekpaans.nl/wp-content/uploads/2018/04/full-cpu-util-300x79.png 300w, https://www.freekpaans.nl/wp-content/uploads/2018/04/full-cpu-util-768x203.png 768w, https://www.freekpaans.nl/wp-content/uploads/2018/04/full-cpu-util-1024x271.png 1024w, https://www.freekpaans.nl/wp-content/uploads/2018/04/full-cpu-util-600x159.png 600w, https://www.freekpaans.nl/wp-content/uploads/2018/04/full-cpu-util-780x206.png 780w, https://www.freekpaans.nl/wp-content/uploads/2018/04/full-cpu-util-1200x317.png 1200w" sizes="(max-width: 1658px) 100vw, 1658px" /></p>
<p><img src="http://www.freekpaans.nl/wp-content/uploads/2018/04/full-memory.png" alt="" width="1658" height="438" class="alignnone size-full wp-image-3290" srcset="https://www.freekpaans.nl/wp-content/uploads/2018/04/full-memory.png 1658w, https://www.freekpaans.nl/wp-content/uploads/2018/04/full-memory-300x79.png 300w, https://www.freekpaans.nl/wp-content/uploads/2018/04/full-memory-768x203.png 768w, https://www.freekpaans.nl/wp-content/uploads/2018/04/full-memory-1024x271.png 1024w, https://www.freekpaans.nl/wp-content/uploads/2018/04/full-memory-600x159.png 600w, https://www.freekpaans.nl/wp-content/uploads/2018/04/full-memory-780x206.png 780w, https://www.freekpaans.nl/wp-content/uploads/2018/04/full-memory-1200x317.png 1200w" sizes="(max-width: 1658px) 100vw, 1658px" /></p>
<p><img src="http://www.freekpaans.nl/wp-content/uploads/2018/04/full-load.png" alt="" width="1658" height="396" class="alignnone size-full wp-image-3287" srcset="https://www.freekpaans.nl/wp-content/uploads/2018/04/full-load.png 1658w, https://www.freekpaans.nl/wp-content/uploads/2018/04/full-load-300x72.png 300w, https://www.freekpaans.nl/wp-content/uploads/2018/04/full-load-768x183.png 768w, https://www.freekpaans.nl/wp-content/uploads/2018/04/full-load-1024x245.png 1024w, https://www.freekpaans.nl/wp-content/uploads/2018/04/full-load-600x143.png 600w, https://www.freekpaans.nl/wp-content/uploads/2018/04/full-load-780x186.png 780w, https://www.freekpaans.nl/wp-content/uploads/2018/04/full-load-1200x287.png 1200w" sizes="(max-width: 1658px) 100vw, 1658px" /></p>
<h3>Disk</h3>
<p><img src="http://www.freekpaans.nl/wp-content/uploads/2018/04/full-disk-ops.png" alt="" width="1658" height="368" class="alignnone size-full wp-image-3285" srcset="https://www.freekpaans.nl/wp-content/uploads/2018/04/full-disk-ops.png 1658w, https://www.freekpaans.nl/wp-content/uploads/2018/04/full-disk-ops-300x67.png 300w, https://www.freekpaans.nl/wp-content/uploads/2018/04/full-disk-ops-768x170.png 768w, https://www.freekpaans.nl/wp-content/uploads/2018/04/full-disk-ops-1024x227.png 1024w, https://www.freekpaans.nl/wp-content/uploads/2018/04/full-disk-ops-600x133.png 600w, https://www.freekpaans.nl/wp-content/uploads/2018/04/full-disk-ops-780x173.png 780w, https://www.freekpaans.nl/wp-content/uploads/2018/04/full-disk-ops-1200x266.png 1200w" sizes="(max-width: 1658px) 100vw, 1658px" /></p>
<p><img src="http://www.freekpaans.nl/wp-content/uploads/2018/04/full-disk-throughput.png" alt="" width="1658" height="368" class="alignnone size-full wp-image-3286" srcset="https://www.freekpaans.nl/wp-content/uploads/2018/04/full-disk-throughput.png 1658w, https://www.freekpaans.nl/wp-content/uploads/2018/04/full-disk-throughput-300x67.png 300w, https://www.freekpaans.nl/wp-content/uploads/2018/04/full-disk-throughput-768x170.png 768w, https://www.freekpaans.nl/wp-content/uploads/2018/04/full-disk-throughput-1024x227.png 1024w, https://www.freekpaans.nl/wp-content/uploads/2018/04/full-disk-throughput-600x133.png 600w, https://www.freekpaans.nl/wp-content/uploads/2018/04/full-disk-throughput-780x173.png 780w, https://www.freekpaans.nl/wp-content/uploads/2018/04/full-disk-throughput-1200x266.png 1200w" sizes="(max-width: 1658px) 100vw, 1658px" /></p>
<h3>Network</h3>
<p><img src="http://www.freekpaans.nl/wp-content/uploads/2018/04/full-network.png" alt="" width="1658" height="382" class="alignnone size-full wp-image-3288" srcset="https://www.freekpaans.nl/wp-content/uploads/2018/04/full-network.png 1658w, https://www.freekpaans.nl/wp-content/uploads/2018/04/full-network-300x69.png 300w, https://www.freekpaans.nl/wp-content/uploads/2018/04/full-network-768x177.png 768w, https://www.freekpaans.nl/wp-content/uploads/2018/04/full-network-1024x236.png 1024w, https://www.freekpaans.nl/wp-content/uploads/2018/04/full-network-600x138.png 600w, https://www.freekpaans.nl/wp-content/uploads/2018/04/full-network-780x180.png 780w, https://www.freekpaans.nl/wp-content/uploads/2018/04/full-network-1200x276.png 1200w" sizes="(max-width: 1658px) 100vw, 1658px" /></p>
<h3>Peers</h3>
<p><img src="http://www.freekpaans.nl/wp-content/uploads/2018/04/peercount.png" alt="" width="1082" height="354" class="alignnone size-full wp-image-3273" srcset="https://www.freekpaans.nl/wp-content/uploads/2018/04/peercount.png 1082w, https://www.freekpaans.nl/wp-content/uploads/2018/04/peercount-300x98.png 300w, https://www.freekpaans.nl/wp-content/uploads/2018/04/peercount-768x251.png 768w, https://www.freekpaans.nl/wp-content/uploads/2018/04/peercount-1024x335.png 1024w, https://www.freekpaans.nl/wp-content/uploads/2018/04/peercount-600x196.png 600w, https://www.freekpaans.nl/wp-content/uploads/2018/04/peercount-780x255.png 780w" sizes="(max-width: 1082px) 100vw, 1082px" /></p>
<p><img src="http://www.freekpaans.nl/wp-content/uploads/2018/04/full-peer-count.png" alt="" width="1658" height="354" class="alignnone size-full wp-image-3289" srcset="https://www.freekpaans.nl/wp-content/uploads/2018/04/full-peer-count.png 1658w, https://www.freekpaans.nl/wp-content/uploads/2018/04/full-peer-count-300x64.png 300w, https://www.freekpaans.nl/wp-content/uploads/2018/04/full-peer-count-768x164.png 768w, https://www.freekpaans.nl/wp-content/uploads/2018/04/full-peer-count-1024x219.png 1024w, https://www.freekpaans.nl/wp-content/uploads/2018/04/full-peer-count-600x128.png 600w, https://www.freekpaans.nl/wp-content/uploads/2018/04/full-peer-count-780x167.png 780w, https://www.freekpaans.nl/wp-content/uploads/2018/04/full-peer-count-1200x256.png 1200w" sizes="(max-width: 1658px) 100vw, 1658px" /></p>
<h3>Blocks</h3>
<p><img src="http://www.freekpaans.nl/wp-content/uploads/2018/04/full-blocks.png" alt="" width="1658" height="382" class="alignnone size-full wp-image-3283" srcset="https://www.freekpaans.nl/wp-content/uploads/2018/04/full-blocks.png 1658w, https://www.freekpaans.nl/wp-content/uploads/2018/04/full-blocks-300x69.png 300w, https://www.freekpaans.nl/wp-content/uploads/2018/04/full-blocks-768x177.png 768w, https://www.freekpaans.nl/wp-content/uploads/2018/04/full-blocks-1024x236.png 1024w, https://www.freekpaans.nl/wp-content/uploads/2018/04/full-blocks-600x138.png 600w, https://www.freekpaans.nl/wp-content/uploads/2018/04/full-blocks-780x180.png 780w, https://www.freekpaans.nl/wp-content/uploads/2018/04/full-blocks-1200x276.png 1200w" sizes="(max-width: 1658px) 100vw, 1658px" /></p>
<p><img src="http://www.freekpaans.nl/wp-content/uploads/2018/04/full-blocks-rate.png" alt="" width="1658" height="354" class="alignnone size-full wp-image-3282" srcset="https://www.freekpaans.nl/wp-content/uploads/2018/04/full-blocks-rate.png 1658w, https://www.freekpaans.nl/wp-content/uploads/2018/04/full-blocks-rate-300x64.png 300w, https://www.freekpaans.nl/wp-content/uploads/2018/04/full-blocks-rate-768x164.png 768w, https://www.freekpaans.nl/wp-content/uploads/2018/04/full-blocks-rate-1024x219.png 1024w, https://www.freekpaans.nl/wp-content/uploads/2018/04/full-blocks-rate-600x128.png 600w, https://www.freekpaans.nl/wp-content/uploads/2018/04/full-blocks-rate-780x167.png 780w, https://www.freekpaans.nl/wp-content/uploads/2018/04/full-blocks-rate-1200x256.png 1200w" sizes="(max-width: 1658px) 100vw, 1658px" /></p>
<h2>Notes</h2>
<p>I guess the notes around peers still stand, though I didn&#8217;t test that explicitly for full sync:</p>
<ul>
<li>Firewall needs to be open for port 30303 (I opened both UDP and TCP). Otherwise you won&#8217;t get enough peers.</li>
<li>Syncing actually seems to take more time with more peers. I settled on the default of 25. With 100 peers it was much slower.</li>
</ul>
<h2>Conclusions</h2>
<p>Clearly, doing a full sync takes much longer than a fast sync: over 9 days vs about 8 hours. From my data, it looks like CPU is the bottleneck here. What surprises me is that the block rate is very &#8220;bursty&#8221;. The following patterns repeats itself over the course of the entire sync:</p>
<p><img src="http://www.freekpaans.nl/wp-content/uploads/2018/04/full-block-sync-irregular.png" alt="" width="1658" height="354" class="alignnone size-full wp-image-3291" srcset="https://www.freekpaans.nl/wp-content/uploads/2018/04/full-block-sync-irregular.png 1658w, https://www.freekpaans.nl/wp-content/uploads/2018/04/full-block-sync-irregular-300x64.png 300w, https://www.freekpaans.nl/wp-content/uploads/2018/04/full-block-sync-irregular-768x164.png 768w, https://www.freekpaans.nl/wp-content/uploads/2018/04/full-block-sync-irregular-1024x219.png 1024w, https://www.freekpaans.nl/wp-content/uploads/2018/04/full-block-sync-irregular-600x128.png 600w, https://www.freekpaans.nl/wp-content/uploads/2018/04/full-block-sync-irregular-780x167.png 780w, https://www.freekpaans.nl/wp-content/uploads/2018/04/full-block-sync-irregular-1200x256.png 1200w" sizes="(max-width: 1658px) 100vw, 1658px" /></p>
<p>I would expect the block rate to be fairly constant if the CPU is the bottleneck. I don&#8217;t think the availability of blocks on the network is the problem here since the fast sync also needs all the blocks, and that happened within 8 hours. I do see some correlation with memory activity, but I didn&#8217;t dive in it any more. If someone has any ideas, I&#8217;d love to hear! </p>
<p>What also surprises me is that all the Ethereum data is already larger than the entire Bitcoin data directory (about 200GB), while Bitcoin is almost 3 times older than Ethereum. Clearly, Ethereum grows much faster than Bitcoin. I guess that it&#8217;ll become even harder to do full syncs in the future, and that will probably mean the number of full nodes will decrease. That can&#8217;t be good.</p>
<p>Hope this post was of some help. If you have results to share, please let me know.</p>
<p>The post <a rel="nofollow" href="https://www.freekpaans.nl/2018/04/anatomy-of-a-geth-full-sync/">Anatomy of a geth full sync</a> appeared first on <a rel="nofollow" href="https://www.freekpaans.nl">Freek Paans</a>.</p>
]]></content:encoded>
							<wfw:commentRss>https://www.freekpaans.nl/2018/04/anatomy-of-a-geth-full-sync/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
							</item>
		<item>
		<title>Anatomy of a geth &#8211;fast sync</title>
		<link>https://www.freekpaans.nl/2018/04/anatomy-geth-fast-sync/</link>
				<comments>https://www.freekpaans.nl/2018/04/anatomy-geth-fast-sync/#respond</comments>
				<pubDate>Tue, 03 Apr 2018 06:19:45 +0000</pubDate>
		<dc:creator><![CDATA[Freek Paans]]></dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.freekpaans.nl/?p=3259</guid>
				<description><![CDATA[<p>I&#8217;ve been reading up on Ethereum for the last couple of days. Apparently, doing the initial sync is one of the major issues people run into (at least with geth). That includes me. I first tried syncing on an HDD, and that didn&#8217;t work. I then used a mediocre machine with SSD, but it still... <span class="more"><a class="more-link" href="https://www.freekpaans.nl/2018/04/anatomy-geth-fast-sync/">Continue reading <span class="meta-nav">&#8594;</span></a></span></p>
<p>The post <a rel="nofollow" href="https://www.freekpaans.nl/2018/04/anatomy-geth-fast-sync/">Anatomy of a geth &#8211;fast sync</a> appeared first on <a rel="nofollow" href="https://www.freekpaans.nl">Freek Paans</a>.</p>
]]></description>
								<content:encoded><![CDATA[<style type="text/css">
table.left * {
  text-align: left;
}
</style>
<p>I&#8217;ve been reading up on Ethereum for the last couple of days. Apparently, doing the <a href="https://github.com/ethereum/go-ethereum/issues/14647">initial sync</a> is one of the <a href="https://github.com/ethereum/go-ethereum/issues/15001">major issues</a> people run into (at least with geth). That includes me. I first tried syncing on an HDD, and that didn&#8217;t work. I then used a mediocre machine with SSD, but it still kept on running with no apparent end in sight. So I decided to use a ridiculously large machine on Azure and sync there. Turns out that with this machine is was able to do a &#8211;fast sync in a little under 8 hours.</p>
<h2>Specs</h2>
<p>I used an Azure Standard_L16s storage optimized VM. This beast has 16 cores, 128 gigs of memory and 80,000 IOPS and 800MBps throughput on its temporary storage disk. Ought to be enough you&#8217;d say. I started geth with <code>./geth --maxpeers 25 --cache 64000 --verbosity 4  &gt;&gt; geth.log 2&gt;&amp;1</code></p>
<h3>Overview</h3>
<table class="left">
<tbody>
<tr>
<td>Azure VM Instance</td>
<td>Standard_L16s</td>
</tr>
<tr>
<td>OS</td>
<td>Ubuntu 16.04.4 LTS</td>
</tr>
<tr>
<td>CPU</td>
<td>16 cores</td>
</tr>
<tr>
<td>Memory</td>
<td>128GB</td>
</tr>
<tr>
<td>Disk IOPS (spec)</td>
<td>80,000</td>
</tr>
<tr>
<td>Disk throughput (spec)</td>
<td>800 MBps</td>
</tr>
<tr>
<td>Geth version</td>
<td>geth-linux-amd64-1.8.3-329ac18e</td>
</tr>
<tr>
<td>Geth maxpeers</td>
<td>25</td>
</tr>
<tr>
<td>Geth cache</td>
<td>64,000MB</td>
</tr>
</tbody>
</table>
<h2>Results</h2>
<p><a href="https://github.com/ethereum/go-ethereum/issues/14647#issuecomment-371375187">Sync phases description.</a></p>
<table class="left">
<tbody>
<tr>
<td>Start time</td>
<td>2 apr 2018 20:46:43 UTC</td>
</tr>
<tr>
<td>End time *</td>
<td>3 apr 2018 04:27:15 UTC</td>
</tr>
<tr>
<td>Total duration</td>
<td>7h 40m 32s</td>
</tr>
<tr>
<td>Imported blocks at catch up time</td>
<td>5,369,956</td>
</tr>
<tr>
<td>Blocks caught up</td>
<td>3 apr 2018 00:11:08 (3h 24m 25s)</td>
</tr>
<tr>
<td>Total imported state trie entries</td>
<td>114,566,252</td>
</tr>
<tr>
<td>State caught up</td>
<td>3 apr 2018 04:24:07 (7h 37m 24s)</td>
</tr>
<tr>
<td>du -s ~/.ethereum</td>
<td>77,948,852</td>
</tr>
</tbody>
</table>
<p>* End time defined as first single-block &#8220;Imported new chain segment&#8221; log message</p>
<h3>CPU/Load/Memory</h3>
<p><img src="http://www.freekpaans.nl/wp-content/uploads/2018/04/cpu-util.png" alt="" width="1082" height="438" class="alignnone size-full wp-image-3267" srcset="https://www.freekpaans.nl/wp-content/uploads/2018/04/cpu-util.png 1082w, https://www.freekpaans.nl/wp-content/uploads/2018/04/cpu-util-300x121.png 300w, https://www.freekpaans.nl/wp-content/uploads/2018/04/cpu-util-768x311.png 768w, https://www.freekpaans.nl/wp-content/uploads/2018/04/cpu-util-1024x415.png 1024w, https://www.freekpaans.nl/wp-content/uploads/2018/04/cpu-util-600x243.png 600w, https://www.freekpaans.nl/wp-content/uploads/2018/04/cpu-util-780x316.png 780w" sizes="(max-width: 1082px) 100vw, 1082px" /></p>
<p><img src="http://www.freekpaans.nl/wp-content/uploads/2018/04/memory.png" alt="" width="1082" height="438" class="alignnone size-full wp-image-3271" srcset="https://www.freekpaans.nl/wp-content/uploads/2018/04/memory.png 1082w, https://www.freekpaans.nl/wp-content/uploads/2018/04/memory-300x121.png 300w, https://www.freekpaans.nl/wp-content/uploads/2018/04/memory-768x311.png 768w, https://www.freekpaans.nl/wp-content/uploads/2018/04/memory-1024x415.png 1024w, https://www.freekpaans.nl/wp-content/uploads/2018/04/memory-600x243.png 600w, https://www.freekpaans.nl/wp-content/uploads/2018/04/memory-780x316.png 780w" sizes="(max-width: 1082px) 100vw, 1082px" /></p>
<p><img src="http://www.freekpaans.nl/wp-content/uploads/2018/04/load.png" alt="" width="1082" height="396" class="alignnone size-full wp-image-3270" srcset="https://www.freekpaans.nl/wp-content/uploads/2018/04/load.png 1082w, https://www.freekpaans.nl/wp-content/uploads/2018/04/load-300x110.png 300w, https://www.freekpaans.nl/wp-content/uploads/2018/04/load-768x281.png 768w, https://www.freekpaans.nl/wp-content/uploads/2018/04/load-1024x375.png 1024w, https://www.freekpaans.nl/wp-content/uploads/2018/04/load-600x220.png 600w, https://www.freekpaans.nl/wp-content/uploads/2018/04/load-780x285.png 780w" sizes="(max-width: 1082px) 100vw, 1082px" /></p>
<h3>Disk</h3>
<p><img src="http://www.freekpaans.nl/wp-content/uploads/2018/04/disk-ops.png" alt="" width="1082" height="368" class="alignnone size-full wp-image-3268" srcset="https://www.freekpaans.nl/wp-content/uploads/2018/04/disk-ops.png 1082w, https://www.freekpaans.nl/wp-content/uploads/2018/04/disk-ops-300x102.png 300w, https://www.freekpaans.nl/wp-content/uploads/2018/04/disk-ops-768x261.png 768w, https://www.freekpaans.nl/wp-content/uploads/2018/04/disk-ops-1024x348.png 1024w, https://www.freekpaans.nl/wp-content/uploads/2018/04/disk-ops-600x204.png 600w, https://www.freekpaans.nl/wp-content/uploads/2018/04/disk-ops-780x265.png 780w" sizes="(max-width: 1082px) 100vw, 1082px" /></p>
<p><img src="http://www.freekpaans.nl/wp-content/uploads/2018/04/disk-throughput.png" alt="" width="1082" height="368" class="alignnone size-full wp-image-3269" srcset="https://www.freekpaans.nl/wp-content/uploads/2018/04/disk-throughput.png 1082w, https://www.freekpaans.nl/wp-content/uploads/2018/04/disk-throughput-300x102.png 300w, https://www.freekpaans.nl/wp-content/uploads/2018/04/disk-throughput-768x261.png 768w, https://www.freekpaans.nl/wp-content/uploads/2018/04/disk-throughput-1024x348.png 1024w, https://www.freekpaans.nl/wp-content/uploads/2018/04/disk-throughput-600x204.png 600w, https://www.freekpaans.nl/wp-content/uploads/2018/04/disk-throughput-780x265.png 780w" sizes="(max-width: 1082px) 100vw, 1082px" /></p>
<h3>Network</h3>
<p><img src="http://www.freekpaans.nl/wp-content/uploads/2018/04/network.png" alt="" width="1082" height="382" class="alignnone size-full wp-image-3272" srcset="https://www.freekpaans.nl/wp-content/uploads/2018/04/network.png 1082w, https://www.freekpaans.nl/wp-content/uploads/2018/04/network-300x106.png 300w, https://www.freekpaans.nl/wp-content/uploads/2018/04/network-768x271.png 768w, https://www.freekpaans.nl/wp-content/uploads/2018/04/network-1024x362.png 1024w, https://www.freekpaans.nl/wp-content/uploads/2018/04/network-600x212.png 600w, https://www.freekpaans.nl/wp-content/uploads/2018/04/network-780x275.png 780w" sizes="(max-width: 1082px) 100vw, 1082px" /></p>
<h3>Peers</h3>
<p><img src="http://www.freekpaans.nl/wp-content/uploads/2018/04/peercount.png" alt="" width="1082" height="354" class="alignnone size-full wp-image-3273" srcset="https://www.freekpaans.nl/wp-content/uploads/2018/04/peercount.png 1082w, https://www.freekpaans.nl/wp-content/uploads/2018/04/peercount-300x98.png 300w, https://www.freekpaans.nl/wp-content/uploads/2018/04/peercount-768x251.png 768w, https://www.freekpaans.nl/wp-content/uploads/2018/04/peercount-1024x335.png 1024w, https://www.freekpaans.nl/wp-content/uploads/2018/04/peercount-600x196.png 600w, https://www.freekpaans.nl/wp-content/uploads/2018/04/peercount-780x255.png 780w" sizes="(max-width: 1082px) 100vw, 1082px" /></p>
<h3>Blocks</h3>
<p><img src="http://www.freekpaans.nl/wp-content/uploads/2018/04/blocks.png" alt="" width="1082" height="382" class="alignnone size-full wp-image-3266" srcset="https://www.freekpaans.nl/wp-content/uploads/2018/04/blocks.png 1082w, https://www.freekpaans.nl/wp-content/uploads/2018/04/blocks-300x106.png 300w, https://www.freekpaans.nl/wp-content/uploads/2018/04/blocks-768x271.png 768w, https://www.freekpaans.nl/wp-content/uploads/2018/04/blocks-1024x362.png 1024w, https://www.freekpaans.nl/wp-content/uploads/2018/04/blocks-600x212.png 600w, https://www.freekpaans.nl/wp-content/uploads/2018/04/blocks-780x275.png 780w" sizes="(max-width: 1082px) 100vw, 1082px" /></p>
<p><img src="http://www.freekpaans.nl/wp-content/uploads/2018/04/block-rate.png" alt="" width="1082" height="354" class="alignnone size-full wp-image-3265" srcset="https://www.freekpaans.nl/wp-content/uploads/2018/04/block-rate.png 1082w, https://www.freekpaans.nl/wp-content/uploads/2018/04/block-rate-300x98.png 300w, https://www.freekpaans.nl/wp-content/uploads/2018/04/block-rate-768x251.png 768w, https://www.freekpaans.nl/wp-content/uploads/2018/04/block-rate-1024x335.png 1024w, https://www.freekpaans.nl/wp-content/uploads/2018/04/block-rate-600x196.png 600w, https://www.freekpaans.nl/wp-content/uploads/2018/04/block-rate-780x255.png 780w" sizes="(max-width: 1082px) 100vw, 1082px" /></p>
<h3>State trie</h3>
<p><img src="http://www.freekpaans.nl/wp-content/uploads/2018/04/states.png" alt="" width="1082" height="368" class="alignnone size-full wp-image-3275" srcset="https://www.freekpaans.nl/wp-content/uploads/2018/04/states.png 1082w, https://www.freekpaans.nl/wp-content/uploads/2018/04/states-300x102.png 300w, https://www.freekpaans.nl/wp-content/uploads/2018/04/states-768x261.png 768w, https://www.freekpaans.nl/wp-content/uploads/2018/04/states-1024x348.png 1024w, https://www.freekpaans.nl/wp-content/uploads/2018/04/states-600x204.png 600w, https://www.freekpaans.nl/wp-content/uploads/2018/04/states-780x265.png 780w" sizes="(max-width: 1082px) 100vw, 1082px" /></p>
<p><img src="http://www.freekpaans.nl/wp-content/uploads/2018/04/state-rate.png" alt="" width="1082" height="368" class="alignnone size-full wp-image-3274" srcset="https://www.freekpaans.nl/wp-content/uploads/2018/04/state-rate.png 1082w, https://www.freekpaans.nl/wp-content/uploads/2018/04/state-rate-300x102.png 300w, https://www.freekpaans.nl/wp-content/uploads/2018/04/state-rate-768x261.png 768w, https://www.freekpaans.nl/wp-content/uploads/2018/04/state-rate-1024x348.png 1024w, https://www.freekpaans.nl/wp-content/uploads/2018/04/state-rate-600x204.png 600w, https://www.freekpaans.nl/wp-content/uploads/2018/04/state-rate-780x265.png 780w" sizes="(max-width: 1082px) 100vw, 1082px" /></p>
<h2>Notes</h2>
<ul>
<li>Firewall needs to be open for port 30303 (I opened both UDP and TCP). Otherwise you won&#8217;t get enough peers.</li>
<li>Syncing actually seems to take more time with more peers. I settled on the default of 25. With 100 peers it was much slower.</li>
<li>Importing the chain segments did not take significant time, contrary to the <a href="https://github.com/ethereum/go-ethereum/issues/14647#issuecomment-371375187">comment mentioned in the github issue</a>.</li>
</ul>
<h2>Conclusions</h2>
<p>Disk IO is mostly used while fetching the blocks. After that, the system&#8217;s resources are barely used, which makes me think the bottleneck is the network. Though even during block syncing, the resources are barely maxed out, so probably the process is constrained by the network the entire time. I&#8217;m not familiar enough with Geth/Ethereum to ascertain this for sure though. As stated above, increasing the number of peers didn&#8217;t improve the situation, but made it worse.</p>
<p>Hope this post was of some help. If you have results to share, please let me know.</p>
<p>The post <a rel="nofollow" href="https://www.freekpaans.nl/2018/04/anatomy-geth-fast-sync/">Anatomy of a geth &#8211;fast sync</a> appeared first on <a rel="nofollow" href="https://www.freekpaans.nl">Freek Paans</a>.</p>
]]></content:encoded>
							<wfw:commentRss>https://www.freekpaans.nl/2018/04/anatomy-geth-fast-sync/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
							</item>
		<item>
		<title>Turning Apache Authentication in an OpenID Connect Provider</title>
		<link>https://www.freekpaans.nl/2016/05/turning-apache-authentication-openid-connect-provider/</link>
				<comments>https://www.freekpaans.nl/2016/05/turning-apache-authentication-openid-connect-provider/#respond</comments>
				<pubDate>Fri, 06 May 2016 10:59:01 +0000</pubDate>
		<dc:creator><![CDATA[Freek Paans]]></dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.freekpaans.nl/?p=3104</guid>
				<description><![CDATA[<p>I wrote a small PHP application to turn Apache into an OpenID Connect Provider: https://github.com/FreekPaans/apache-openid-connect. This is useful if you have an existing environment where you authenticate via HTTP Basic Authentication, and want to use that authentication in other environments as well.</p>
<p>The post <a rel="nofollow" href="https://www.freekpaans.nl/2016/05/turning-apache-authentication-openid-connect-provider/">Turning Apache Authentication in an OpenID Connect Provider</a> appeared first on <a rel="nofollow" href="https://www.freekpaans.nl">Freek Paans</a>.</p>
]]></description>
								<content:encoded><![CDATA[<p>I wrote a small PHP application to turn Apache into an OpenID Connect Provider: <a href="https://github.com/FreekPaans/apache-openid-connect">https://github.com/FreekPaans/apache-openid-connect</a>. This is useful if you have an existing environment where you authenticate via HTTP Basic Authentication, and want to use that authentication in other environments as well.</p>
<p>The post <a rel="nofollow" href="https://www.freekpaans.nl/2016/05/turning-apache-authentication-openid-connect-provider/">Turning Apache Authentication in an OpenID Connect Provider</a> appeared first on <a rel="nofollow" href="https://www.freekpaans.nl">Freek Paans</a>.</p>
]]></content:encoded>
							<wfw:commentRss>https://www.freekpaans.nl/2016/05/turning-apache-authentication-openid-connect-provider/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
							</item>
		<item>
		<title>DDD Layered architecture in Clojure: A first try</title>
		<link>https://www.freekpaans.nl/2016/03/layered-architecture-in-clojure/</link>
				<comments>https://www.freekpaans.nl/2016/03/layered-architecture-in-clojure/#comments</comments>
				<pubDate>Fri, 11 Mar 2016 08:54:15 +0000</pubDate>
		<dc:creator><![CDATA[Freek Paans]]></dc:creator>
				<category><![CDATA[Architecture]]></category>
		<category><![CDATA[Clojure]]></category>
		<category><![CDATA[DDD]]></category>

		<guid isPermaLink="false">http://www.freekpaans.nl/?p=3057</guid>
				<description><![CDATA[<p>The first step in my effort to freshen up our time tracker using DDD &#38; Clojure has been finding a way to structure my code. Since I don&#8217;t have that much Clojure experience yet, I decided to take the DDD layered architecture and port it as directly as possible. This probably isn&#8217;t really idiomatic Clojure,... <span class="more"><a class="more-link" href="https://www.freekpaans.nl/2016/03/layered-architecture-in-clojure/">Continue reading <span class="meta-nav">&#8594;</span></a></span></p>
<p>The post <a rel="nofollow" href="https://www.freekpaans.nl/2016/03/layered-architecture-in-clojure/">DDD Layered architecture in Clojure: A first try</a> appeared first on <a rel="nofollow" href="https://www.freekpaans.nl">Freek Paans</a>.</p>
]]></description>
								<content:encoded><![CDATA[<p>The first step in <a href="http://www.freekpaans.nl/2016/01/moving-away-from-legacy-using-ddd/">my effort to freshen up our time tracker using DDD &amp; Clojure</a> has been finding a way to structure my code. Since I don&#8217;t have that much Clojure experience yet, I decided to take the DDD layered architecture and port it as directly as possible. This probably isn&#8217;t really idiomatic Clojure, but it gives me a familiar start. This post should be regarded as such, my first try. If you know better ways, don&#8217;t hesitate to let me know. </p>
<h2>The architecture</h2>
<p>
As a picture is worth a thousend words:<br />
<img src="http://www.freekpaans.nl/wp-content/uploads/2016/03/layered.png" alt="layered" width="588" height="390" class="alignnone size-full wp-image-3058" srcset="https://www.freekpaans.nl/wp-content/uploads/2016/03/layered.png 588w, https://www.freekpaans.nl/wp-content/uploads/2016/03/layered-300x199.png 300w" sizes="(max-width: 588px) 100vw, 588px" /><br />
This architecture is mostly the same as the one advocated in the DDD Blue Book, except that the Domain Layer does not depend on any data-related infrastructure and there&#8217;s a little CQRS mixed in. I think this is mostly standard these days. In this design, the application layer is responsible for transaction management. The &#8216;Setup&#8217; part of the UI layer means setting up things like dependency injection.
</p>
<p>In this post I&#8217;ll focus on the interaction between application services, domain objects, repositories and the data layer. I&#8217;ll blog about other parts (such as validation) in later posts.</p>
<h2>The domain</h2>
<p>
Unfortunately, I&#8217;m not able to release the code for the time tracker just yet (due to some issues with the legacy code). So for this post I&#8217;ll use an example domain with curently just one entity&#8230; Cargo <img src="https://s.w.org/images/core/emoji/12.0.0-1/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /> The Cargo currently has one operation: being booked onto a Voyage.
</p>
<h2>The approach</h2>
<p>
Let&#8217;s start with the Domain Layer. Here, we need to define an &#8220;object&#8221; and an &#8220;interface&#8221;: the <em>Cargo</em> and <em>CargoRepository</em> respectively.
</p>
<h3>Cargo entity</h3>
<p>
The Cargo entity is implemented as a simple record containing the fields <em>cargo-id</em>, <em>size</em> and <em>voyage-id</em>. I&#8217;ve defined a constructor <em>create-new-voyage</em> which does its input validations use pre-conditions.
</p>
<p>There&#8217;s one domain operation, <em>book-onto-voyage</em> which books the cargo on a voyage. For now, the requirement is that it can&#8217;t already be booked on another Voyage. (Remember this post is about overall architecture, not the domain logic itself, which is for a next post).
</p>
<p>Furthermore, there is a method for setting the the <em>cargo-id</em> since we rely on the data store to generate it for us, which means we don&#8217;t have it yet when creating a new cargo.
</p>
<p>
Here&#8217;s the code:
</p>
<p><script src="https://gist.github.com/FreekPaans/895469b88314ddffe7aa.js"></script></p>
<h3>Cargo Repository</h3>
<p>
The Cargo Repository consists of 2 parts: the interface which lives in the domain layer, and the implementation which lives in the data layer. The interface is very simple and implemented using a Clojure protocol. It has 3 functions, <em>-find</em>, <em>-add!</em> and <em>-update!</em>.
</p>
<p>
A note about concurrency: <em>-find</em> returns both the cargo entity and the version as it exists in the database in a map: <code>{:version a-version :cargo the-cargo}</code>. When doing an <em>-update!</em> you need to pass in the version so you can do your optimistic concurrency check. (I&#8217;m thinking of returning a vector <code>[version cargo]</code> instead of a map because destructuring the map every time hurts readability in client code, I think.)
</p>
<p>
Furthermore, I&#8217;ve defined convenience methods <em>find</em>, <em>add!</em> and <em>update!</em>, which are globally reachable and rely on a call to <em>set-implementation!</em> when setting up the application. This is to avoid needing to pass (read: dependency inject) the correct repository implementation along the stack. This is probably a bit controversial (global state, pure functions, etc), and I look forward to exploring and hearing about alternatives.
</p>
<p><script src="https://gist.github.com/FreekPaans/059eb47fa7c868bae2e4.js"></script></p>
<h3>Cargo repository MySQL implementation</h3>
<p>
I&#8217;m using MySQL as the data store, and <em>clojure.java.jdbc</em> for interaction with it. The cargoes are mapped to one table, surprisingly called <em>cargoes</em>. I don&#8217;t think there&#8217;s anything particular to the implementation, so here it goes:
</p>
<p><script src="https://gist.github.com/FreekPaans/82b680d381295c08dae7.js"></script></p>
<p>
The final parts are the Application Services and the UI.
</p>
<h3>The Application Service</h3>
<p>I never have good naming conventions (or, almost equivalently, partitioning criteria) for application services. So I&#8217;ve just put it in a namespace called application-service, containing functions for all domain operations. The operations can be taken directly from the Cargo entity: creating a new one, and booking it onto a voyage. I use the <em>apply</em> construct to invoke the entity functions to avoid repeating all parameters.
</p>
<p>Code:</p>
<p><script src="https://gist.github.com/FreekPaans/002bac86f0f488ee52d9.js"></script></p>
<h3><span style="text-decoration: line-through;">The UI</span> The tests</h3>
<p>
To not make this post any longer than it already is I&#8217;m not going to show a full UI, but a couple of tests exercising the Application Service instead. This won&#8217;t show how to do queries for screens, but for now just assume that I more or less directly query the database for those.</p>
<p>There isn&#8217;t much to tell about the tests. If you are not that familiar with Clojure, look for the lines starting with <em>deftest</em>, they define the actual tests. The tests show how to use the application service API to handle commands. They test the end result of the commands by fetching the cargo from the repository and checking its state. I use the MySQL implementation for the database, since I already have it and it performs fine (for now).
</p>
<p><script src="https://gist.github.com/FreekPaans/0ac96992a7e29c97b14a.js"></script></p>
<h2>Conclusion</h2>
<p>The code in this post is pretty much a one-to-one mapping from an OO kind of language to Clojure, which is probably not ideal. Yet, I haven&#8217;t been able to find some good resources on how you would structure a business application in a more Clojure idiomatic way, so this will have to do. Nevertheless, I still like the structure I have now. I think it&#8217;s pretty clean and I don&#8217;t see any big problems (yet). I look forward to exploring more alternatives in the next couple of months, and I&#8217;ll keep you updated.</p>
<p><a href="https://github.com/FreekPaans/clojure-ddd-layered-example">All code (including tests) is available on GitHub.</a></p>
<p>The post <a rel="nofollow" href="https://www.freekpaans.nl/2016/03/layered-architecture-in-clojure/">DDD Layered architecture in Clojure: A first try</a> appeared first on <a rel="nofollow" href="https://www.freekpaans.nl">Freek Paans</a>.</p>
]]></content:encoded>
							<wfw:commentRss>https://www.freekpaans.nl/2016/03/layered-architecture-in-clojure/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
							</item>
		<item>
		<title>The Logical vs the Physical: Layered Architecture</title>
		<link>https://www.freekpaans.nl/2016/02/the-logical-vs-the-physical-business-rules/</link>
				<comments>https://www.freekpaans.nl/2016/02/the-logical-vs-the-physical-business-rules/#respond</comments>
				<pubDate>Thu, 25 Feb 2016 12:21:44 +0000</pubDate>
		<dc:creator><![CDATA[Freek Paans]]></dc:creator>
				<category><![CDATA[Architecture]]></category>
		<category><![CDATA[Logical vs Phyiscal]]></category>

		<guid isPermaLink="false">http://www.freekpaans.nl/?p=3010</guid>
				<description><![CDATA[<p>A lot of mistakes and confusion in software development arise from conflating logical and physical concerns. For example, an object in a conceptual (logical) object model would usually be implemented by multiple objects in the implementation (physical) model. Not knowing this distinction might entice you to include all the implementation classes into the conceptual model,... <span class="more"><a class="more-link" href="https://www.freekpaans.nl/2016/02/the-logical-vs-the-physical-business-rules/">Continue reading <span class="meta-nav">&#8594;</span></a></span></p>
<p>The post <a rel="nofollow" href="https://www.freekpaans.nl/2016/02/the-logical-vs-the-physical-business-rules/">The Logical vs the Physical: Layered Architecture</a> appeared first on <a rel="nofollow" href="https://www.freekpaans.nl">Freek Paans</a>.</p>
]]></description>
								<content:encoded><![CDATA[<p>A lot of mistakes and confusion in software development arise from conflating logical and physical concerns. For example, an object in a conceptual (logical) object model would usually be implemented by multiple objects in the implementation (physical) model. Not knowing this distinction might entice you to include all the implementation classes into the conceptual model, or not factor your implementation classes neatly. One layer down, this mistake is made again when mapping your objects to a data model.</p>
<p>This kind of mistake is so common, that I decided to try to write a little bit about it whenever I see this happening in practice. In this first post about it, I&#8217;ll talk about it in the context of <a href="https://en.wikipedia.org/wiki/Multilayered_architecture" target="_blank">Layered Architecture</a>.
</p>
<h2>Layered architecture</h2>
<p>
I don&#8217;t think the layered architecture style (or its cousin, hexagonal architecture) needs much of an introduction:<br />
<img src="http://www.freekpaans.nl/wp-content/uploads/2016/02/layered.png" alt="layered" width="184" height="201" class="aligncenter size-full wp-image-3014" /><br />
The UI layer is responsible for visualizing stuff, the application layer for managing the application state, the domain layer for enforcing business rules and the data layer manages the data. Every layer builds on top of the layers below it. It can know about those lower layers, but not about the layers above it. Depending on your point of view the data layer is sometimes thought of as an infrastructure layer which runs besides all the other layers. For the purpose of this discussion, that doesn&#8217;t matter much.
</p>
<h2>Logical vs Physical</h2>
<p>
So is the separation of layers a logical or a physical separation? This question raises another question: what it means to belong in a certain layer. Am I in the application layer because my code is in a namespace called <code>MyAwesomeApp.AppLayer</code>, or am I in the application layer because I behave according to its rules: I don&#8217;t know about the UI layer, and I don&#8217;t enforce business rules or do data management.
</p>
<p>
When it&#8217;s stated like that, you&#8217;re probably going to agree that it <em>should</em> be the latter. It doesn&#8217;t matter that much where you&#8217;re physically located, but only what you logically do. Yet, this is completely contrary to what I encounter in a lot of code bases.
</p>
<p>
A common sign is having your projects (or JARS, or packages, or namespaces, or whatever) named after their layers: <code>MyAwesomeApp.UI</code>, <code>MyAwesomeApp.Application</code>, <code>MyAwesomeApp.Domain</code>, <code>MyAwesomeApp.DAL</code>, etc. The UI package would contain your HTML, JavaScript and web endpoint code. The application layer would contain a couple of application services. The Domain layer would host our business rule code, presumably through a domain model. Finally, the DAL would do all the interactions with a given database.
</p>
<p>So when is this a problem? Well, it doesn&#8217;t really have to be a problem, as long as you don&#8217;t need to do any, say, business logic in your UI or DAL package. But how often is this the case? In almost every project I work in there&#8217;s at least a bit of client-side (JavaScript) validation going on, which is definitely a business rule. Yet, this code lives in the UI layer. Or, I might have a unique username constraint in my database (which is part of the DAL), which is also a business rule. I&#8217;m pretty sure this happens in any project of practical size.
</p>
<p>
Now, this isn&#8217;t really a big problem in itself either. There&#8217;s the problem of the naming being off since there&#8217;s business logic in the UI and DAL package, which you would expect in the domain layer and this probably causes some confusion to new-comers. Secondly, we might &#8216;forget&#8217; applying a layered design inside the individual layers since it looks like we&#8217;ve given up on this architecture for this feature anyway (since we&#8217;re not putting it in the appropriate package). That causes that part of the code to be less well-designed.
</p>
<p>
A real problem occurs, however, when we dogmatically try to put the business rules in the domain layer anyway, an idea often strengthened by the (dogmatic) need to keep things DRY. Ways I&#8217;ve seen this gone and done wrong are at least the following:</p>
<ul>
<li>Putting JavaScript code in our domain package, and somehow merging that to the rest of JS code at build time. The causes major infra-headaches.</li>
<li>Enforcing unique constraints and the like in memory. This doesn&#8217;t perform.</li>
<li>Refrain from using purely client-side validations, and always go through the backend via ajax. Users won&#8217;t like the latency.</li>
<li>Doing a lot of pub/sub with very generic types to be able to talk to another layer you shouldn&#8217;t know about anyway. In this code base, I have no idea what&#8217;s going on at runtime anymore.</li>
<li>Endless discussions among developers to agree on where a given piece of code should go. This is just a waste of time.
</ul>
<p>And these are probably just the tip of the iceberg.
</p>
<p>
We can prevent this problem by allowing our packages to not map 1-to-1 to the physical layers. In this case it&#8217;s an easy discussion where code should go. Now, we need to apply a little more discipline within this package to still apply a layered architecture, but at least it will be an honest story. Another method is to package based on the role a given set of code has: one package has to do with client facing concerns, another with database concerns and yet another with a domain model. You might think these correspond very closely to UI/APP/Domain/Data layer, and you&#8217;d be right, but the intention is different. The fact that one package handles database concerns also means it can be responsible for handle business rules that can most efficiently be implemented in a database.
</p>
<p>
This way, your physical package structure doesn&#8217;t have to reflect the logical layers of your layered architecture. It&#8217;s OK to have some business rules in your JavaScript or database, and they still belong to the domain layer when you do. However, make sure you still maintain the constraints of the layered architecture within that physical package as well.
</p>
<h2>Conclusion</h2>
<p>
This is just one example where conflating logical and physical concerns can cause big problems in your code base. By untangling both, we can feel less dirty about ourselves when we put a certain piece of code in the &#8216;wrong&#8217; layer and at the same time build more effective software.</p>
<p>The post <a rel="nofollow" href="https://www.freekpaans.nl/2016/02/the-logical-vs-the-physical-business-rules/">The Logical vs the Physical: Layered Architecture</a> appeared first on <a rel="nofollow" href="https://www.freekpaans.nl">Freek Paans</a>.</p>
]]></content:encoded>
							<wfw:commentRss>https://www.freekpaans.nl/2016/02/the-logical-vs-the-physical-business-rules/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
							</item>
		<item>
		<title>Moving away from legacy, DDD style</title>
		<link>https://www.freekpaans.nl/2016/01/moving-away-from-legacy-using-ddd/</link>
				<comments>https://www.freekpaans.nl/2016/01/moving-away-from-legacy-using-ddd/#respond</comments>
				<pubDate>Fri, 15 Jan 2016 15:30:19 +0000</pubDate>
		<dc:creator><![CDATA[Freek Paans]]></dc:creator>
				<category><![CDATA[Clojure]]></category>
		<category><![CDATA[DDD]]></category>

		<guid isPermaLink="false">http://www.freekpaans.nl/?p=2926</guid>
				<description><![CDATA[<p>One of the things I like about DDD is that it has solutions for a wide variety of problems. One of those is how to handle legacy software, and specifically how to move away from those. There&#8217;s a passage in the book about this subject, as well as some additional material online. This year I&#8217;m... <span class="more"><a class="more-link" href="https://www.freekpaans.nl/2016/01/moving-away-from-legacy-using-ddd/">Continue reading <span class="meta-nav">&#8594;</span></a></span></p>
<p>The post <a rel="nofollow" href="https://www.freekpaans.nl/2016/01/moving-away-from-legacy-using-ddd/">Moving away from legacy, DDD style</a> appeared first on <a rel="nofollow" href="https://www.freekpaans.nl">Freek Paans</a>.</p>
]]></description>
								<content:encoded><![CDATA[<p>One of the things I like about DDD is that it has solutions for a wide variety of problems. One of those is how to handle legacy software, and specifically how to move away from those. There&#8217;s a passage in the book about this subject, as well as <a href="http://domainlanguage.com/ddd/strategy/GettingStartedWithDDDWhenSurroundedByLegacySystemsV1.pdf">some</a> <a href="https://skillsmatter.com/skillscasts/1948-talk-from-eric-evans#video">additional</a> <a href="https://skillsmatter.com/skillscasts/506-keynote-domain-drive-design">material</a> online.</p>
<p>This year I&#8217;m planning to apply some of these principles and techniques to a project we&#8217;ve developed and use internally at <a href="http://www.infi.nl">Infi</a>: our time tracker. This tool has been under development for 8+ years now, and throughout the years it&#8217;s become ever harder to add new functionality. There are various reasons for this, such as outdated technology, a missing vision on the design and the software trying to solve many separate problems with just one model. So there&#8217;s been pressure to replace this system for a while now, and doing so via DDD-practices seems both natural and fun.</p>
<p>This is going to be more of a journey than a project, so I&#8217;ll try to keep you updated during the year.</p>
<h2>DDD style legacy replacement</h2>
<p>The DDD style approach to moving away from legacy is to first and foremost focus on the core domain. We shouldn&#8217;t try to redesign the whole system at once, or try to refactor ourselves out of the mess, since that hardly ever works. Besides, there is probably a lot of value hidden in the current non-core legacy systems, and it doesn&#8217;t make sense to rewrite that since it&#8217;s been working more or less fine for years and we don&#8217;t actually need new features in these areas.</p>
<p>Instead, we should identify the actual reasons why we want to move away from the legacy system, and what value it&#8217;s going to bring us when doing so. More often than not, the reason will be deeply rooted in the core domain: maybe we&#8217;re having problems delivering new features due to an inappropriate model, maybe the code is just really bad, etc. Whatever the reason, the current system is holding back development in the core domain, and that&#8217;s hurting the business.</p>
<p>So how <em>do</em> we approach this? The aforementioned resources provide a couple of strategies, and they all revolve around a basic idea: create a nice clean, isolated environment for developing a new bounded context. This new bounded context won&#8217;t be encumbered by existing software or models, and we can develop a new model that addresses the problems we&#8217;d like solve in our core domain.</p>
<h2>The goal</h2>
<p>
So what are <em>our</em> reasons for wanting replace our current application? Well, you can probably imagine that time tracking is very important to us since this is what we use to bill our clients. Also, we use it internally to measure all sorts of stuff and make management decisions based on that data. These issues make time tracking a key process in our organization. To be fair, it&#8217;s not mission critical, but still important enough to consider Core Domain.</p>
<p>For our goals, time tracking is only effective if it&#8217;s both <em>accurate</em> and <em>entered  timely</em>. I think the number one way to stimulate this is making tracking your time as easy and convenient as possible. I think we can improve on this by creating a model of the way that people actually spend in our company. By having deep knowledge about the way the time is spent, I envision the model being able to, for example, provide context-sensitive suggestions or notify people at sensible times that time-entry is due. Having these kind of features would make tracking your time a little less of a burden.
</p>
<h2>The plan</h2>
<p>Let&#8217;s look at our current context map:</p>
<p><img src="http://www.freekpaans.nl/wp-content/uploads/2016/01/initial-context-map-1.png" alt="initial-context-map" width="412" height="319" class="aligncenter size-full wp-image-2998" srcset="https://www.freekpaans.nl/wp-content/uploads/2016/01/initial-context-map-1.png 412w, https://www.freekpaans.nl/wp-content/uploads/2016/01/initial-context-map-1-300x232.png 300w" sizes="(max-width: 412px) 100vw, 412px" /></p>
<p>
There are currently 4 Bounded Contexts
</p>
<ul>
<li><strong>Time database</strong>. This is the current application. I&#8217;ve declared it a big ball of mud since I don&#8217;t think there&#8217;s a consistent model hidden in there, and frankly I don&#8217;t care. This application is currently used for entering your times, generating exports, managing users, etc.</li>
<li><strong>Client reporting</strong>. Client reporting is concerned with regularly giving updates to our clients about how we spend our time. It gets its data from TTA, but uses a different model for the actual reporting step, which is why it&#8217;s a separate BC. Most of the work with this model is manual, in Excel.</li>
<li><strong>Invoicing</strong>. While the TTA currently has functionality for generating invoices, we don&#8217;t directly use that for sending invoices to our customers. We use data from the TTA, but then model that differently in this context. Again, this is mostly manual work. </li>
<li><strong>Management reporting</strong>. This is what we use to make week-to-week operational decisions, and uses yet another model. This is actually an API that directly queries the TTA database.</li>
</ul>
<p>
I&#8217;m not planning on replacing the entire existing application for now, just the parts that have to do with time entry. Reporting, for example, is out of scope.
</p>
<p>
We see all BCs partners because functions are required to successfully run the company. It&#8217;s probably possible to unify the &#8220;satellite&#8221; models, but we don&#8217;t care about that now since we want to focus on the actual core domain of actually doing the time tracking.
</p>
<p>For the new system, we&#8217;re going to try the &#8220;Bubble Context with an ACL-backed repository&#8221; strategy, and hope we can later evolve it to one of the other strategies. The destination context map will look like this:<br />
<img src="http://www.freekpaans.nl/wp-content/uploads/2016/01/new-context-map-1.png" alt="new-context-map" width="567" height="258" class="aligncenter size-full wp-image-3002" srcset="https://www.freekpaans.nl/wp-content/uploads/2016/01/new-context-map-1.png 567w, https://www.freekpaans.nl/wp-content/uploads/2016/01/new-context-map-1-300x137.png 300w" sizes="(max-width: 567px) 100vw, 567px" /><br />
The new BC will contain all the new code: an implementation of the model as well as a new GUI. For a lack of a better name I&#8217;ve called it Time-entry for now.
</p>
<h2>A final twist</h2>
<p>
Just to make things more interesting, I&#8217;m planning on doing the new code in Clojure. There are a couple of reasons for this:
</p>
<ul>
<li>I just like learning new stuff, and Clojure is new for me.</li>
<li>I&#8217;ve been encountering Lisps more and more over the last couple of years, and people that I highly respect often speak about Lisps in high regard. So it&#8217;s about time I figure out what all the fuss is about.</li>
<li>I&#8217;d like to try something outside of .NET, for numerous reasons.</li>
<li>Lisps are known for their ability to nicely do DSLs, and that seems a good fit for DDD.</li>
<li>I want to see how DDD patterns map to a more functional language, and specifically what impact that has on modeling.</li>
<li>I wonder how interactive programming (with a REPL) works in real-life</li>
</ul>
<p>
My experience with Clojure thus far has been some toy projects and I read the <a href="https://www.manning.com/books/the-joy-of-clojure-second-edition">Joy of Clojure</a>, but that&#8217;s about it. So expect me to make a lot of rookie mistakes, and please tell me when I do <img src="https://s.w.org/images/core/emoji/12.0.0-1/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" />
</p>
<h2>Next steps</h2>
<p>
All the new code will be open source and on Github. I probably won&#8217;t be able to open source the code for the original application, but I hope I can publish enough to be able to run the ACL. This should be enough to get the entire application running. I hope to get the first code out in a couple of weeks.</p>
<p>The post <a rel="nofollow" href="https://www.freekpaans.nl/2016/01/moving-away-from-legacy-using-ddd/">Moving away from legacy, DDD style</a> appeared first on <a rel="nofollow" href="https://www.freekpaans.nl">Freek Paans</a>.</p>
]]></content:encoded>
							<wfw:commentRss>https://www.freekpaans.nl/2016/01/moving-away-from-legacy-using-ddd/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
							</item>
		<item>
		<title>.NET is slowing me down</title>
		<link>https://www.freekpaans.nl/2015/08/net-is-slowing-me-down/</link>
				<comments>https://www.freekpaans.nl/2015/08/net-is-slowing-me-down/#respond</comments>
				<pubDate>Thu, 27 Aug 2015 08:07:52 +0000</pubDate>
		<dc:creator><![CDATA[Freek Paans]]></dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[Architecture]]></category>

		<guid isPermaLink="false">http://www.freekpaans.nl/?p=2877</guid>
				<description><![CDATA[<p>.NET has been my primary development environment for a little over 5 years now. I&#8217;ve always really liked it, had a lot of success with it, and learned a lot while using it. The tooling and maturity of the platform is, and has been, right where it had to be for me. In a lot... <span class="more"><a class="more-link" href="https://www.freekpaans.nl/2015/08/net-is-slowing-me-down/">Continue reading <span class="meta-nav">&#8594;</span></a></span></p>
<p>The post <a rel="nofollow" href="https://www.freekpaans.nl/2015/08/net-is-slowing-me-down/">.NET is slowing me down</a> appeared first on <a rel="nofollow" href="https://www.freekpaans.nl">Freek Paans</a>.</p>
]]></description>
								<content:encoded><![CDATA[<p>.NET has been my primary development environment for a little over 5 years now. I&#8217;ve always really liked it, had a lot of success with it, and learned a lot while using it. The tooling and maturity of the platform is, and has been, right where it had to be for me.  In a lot of projects, it allowed me to really focus on the domain and I seldom have to write custom tooling for doing standard stuff, which I had to on other platforms. This allowed me to deliver a lot of value to my clients, and they&#8217;re happy about that. </p>
<p>There is, however, a problem that&#8217;s growing bigger and bigger with .NET: it&#8217;s getting slow to develop on. This doesn&#8217;t mean .NET itself is getting slow, it means the developer experience is getting slower. To illustrate my point, I&#8217;ve measured the times to the very first byte (that is, the time after a rebuild) for the template application for various MVC versions:</p>
<table>
<thead>
<tr>
<td>.NET Version</td>
<td>MVC Version</td>
<td>First available date</td>
<td>Time to very first byte (seconds)</td>
</tr>
</thead>
<tbody>
<tr>
<td>4.0</td>
<td>2</td>
<td>March 2010</td>
<td>1.00</td>
</tr>
<tr>
<td>4.0</td>
<td>3</td>
<td>January 2011</td>
<td>1.12</td>
</tr>
<tr>
<td>4.5.2</td>
<td>3</td>
<td>May 2014</td>
<td>1.45</td>
</tr>
<tr>
<td>4.0</td>
<td>4</td>
<td>August 2012</td>
<td>2.63</td>
</tr>
<tr>
<td>4.5.2</td>
<td>4</td>
<td>May 2014</td>
<td>2.89</td>
</tr>
<tr>
<td>4.5.2</td>
<td>5.2.3</td>
<td>January 2015</td>
<td>3.47</td>
</tr>
<tr>
<td>4.6</td>
<td>5.2.3</td>
<td>July 2015</td>
<td>3.58</td>
</tr>
<tr>
<td>4.6</td>
<td>6.0.0-beta5</td>
<td>July 2015</td>
<td>1.89</td>
</tr>
</tbody>
</table>
<p>So, over the course of 5 years the time to load the first page has increased by a factor 3.5, and 2.5 seconds in absolute terms. Now, it seems ASP.NET 5 is going to reduce times a bit, but still not to the 2010 level. </p>
<p>To make matters worse: something like Entity Framework is getting equally slower, and hitting a page that goes to the database might easily take somewhere between 5-10 seconds. The same goes for tests: running the first easily takes a couple of seconds due to EF only.</p>
<h2>Environmental Viscosity</h2>
<p>So, what&#8217;s the problem? <strong>Environmental viscosity.</strong> To quote Uncle Bob from <a href="http://www.amazon.com/Software-Development-Principles-Patterns-Practices/dp/0135974445">PPP</a>:</p>
<p><em>Viscosity of the environment comes about when the development environment is slow and inefficient. For example, if compile times are very long, developers will be tempted to make changes that don&#8217;t force large recompiles, even though those changes don&#8217;t preserve the design.</em></p>
<p>This is exactly what&#8217;s going on here. Because load times are slow, I tend to:</p>
<ul>
<li>Make bigger changes before reloading</li>
<li>Write less tests</li>
<li>Write tests that test larger portions of functionality</li>
<li>Implement back-end code in the front-end (HTML/JavaScript)</li>
<li>Visit reddit while the page loads</li>
</ul>
<p>All these things are undesirable. They slow me down, and compromise the quality of the software. If you ever worked with &#8220;enterprise&#8221; CMS software, you&#8217;ve seen this happen to the extreme (I sure have): there might be <em>minutes</em> between writing a change and the page actually being loaded.</p>
<p>Even if you don&#8217;t do all the above the things, and slavishly wait for the page to load/test to run every time, you&#8217;re still wasting your time, which isn&#8217;t good. You might not recognize it as being a big deal, but imagine making 500 changes every day, that translates to 500 x 5s = 2500 seconds of waiting. That&#8217;s more than 40 minutes of waiting, every day. </p>
<h2>Architecture</h2>
<p>To reiterate: <strong>slow feedback compromises software quality.</strong> What I want, therefore, is feedback on my changes <strong>under a second</strong>, preferably under 500ms. My choice of technology/tools will definitely factor in this requirement, and it will be a strong factor.</p>
<p>For example, my choice for data access defaults to <a href="https://github.com/StackExchange/dapper-dot-net">Dapper</a> these days, because it&#8217;s just much faster than EF (tbf, I also rely less on &#8220;advanced&#8221; mappings). Even something like PHP, for all its faults, tends to have a time-to-very-first-byte that&#8217;s an order of magnitude faster than .NET apps, and therefore be something I might consider when other .NET qualities aren&#8217;t that important.</p>
<p>To me, the development experience is as much part of software architecture as anything else: I consider anything related to building software a part of architecture and since slow feedback compromises software quality, the development experience is certainly part of architecture.</p>
<h2>The future of .NET</h2>
<p>I certainly hope Microsoft is going to improve on these matters. There is some hope: ASP.NET 5 and Entity Framework 7 are right around the corner, and they promise to be lighter-weight, which I hope translates in faster start-up times. Also, Visual Studio 2015 seems to be a bit faster than 2013 (which was and is terrible), but not as fast a VS2012. I guess we&#8217;ll have to wait and see. For the time being, though, I&#8217;ll keep weighing my options.</p>
<p>The post <a rel="nofollow" href="https://www.freekpaans.nl/2015/08/net-is-slowing-me-down/">.NET is slowing me down</a> appeared first on <a rel="nofollow" href="https://www.freekpaans.nl">Freek Paans</a>.</p>
]]></content:encoded>
							<wfw:commentRss>https://www.freekpaans.nl/2015/08/net-is-slowing-me-down/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
							</item>
		<item>
		<title>Start closing the end user feedback loop!</title>
		<link>https://www.freekpaans.nl/2015/08/start-closing-the-end-user-feedback-loop/</link>
				<comments>https://www.freekpaans.nl/2015/08/start-closing-the-end-user-feedback-loop/#respond</comments>
				<pubDate>Thu, 20 Aug 2015 13:27:48 +0000</pubDate>
		<dc:creator><![CDATA[Freek Paans]]></dc:creator>
				<category><![CDATA[Process]]></category>

		<guid isPermaLink="false">http://www.freekpaans.nl/?p=2836</guid>
				<description><![CDATA[<p>The most important feedback loop in any software development project is the feedback you get from end users. The reason for this is simple: since they&#8217;re the ones actually using the product, it&#8217;s them paying for it, either directly or indirectly. If your product isn&#8217;t being used, I can guarantee you development on it is... <span class="more"><a class="more-link" href="https://www.freekpaans.nl/2015/08/start-closing-the-end-user-feedback-loop/">Continue reading <span class="meta-nav">&#8594;</span></a></span></p>
<p>The post <a rel="nofollow" href="https://www.freekpaans.nl/2015/08/start-closing-the-end-user-feedback-loop/">Start closing the end user feedback loop!</a> appeared first on <a rel="nofollow" href="https://www.freekpaans.nl">Freek Paans</a>.</p>
]]></description>
								<content:encoded><![CDATA[<p>The most important feedback loop in any software development project is the feedback you get from end users. The reason for this is simple: since they&#8217;re the ones actually using the product, it&#8217;s them paying for it, either directly or indirectly. If your product isn&#8217;t being used, I can guarantee you development on it is going to end sooner than later. </p>
<p>Unfortunately, it seems this isn&#8217;t common knowledge. Instead, we tend to focus on the feedback of the client and (implicitly) assume that when the client is happy, the end user will be happy. Also, since it&#8217;s the client that pays us, it only seems reasonable that it&#8217;s only their feedback that counts. Well, it turns out clients in general aren&#8217;t that much better in figuring out what their users want. Instead, they rely on feedback from those actual users to decide what the next feature is going to be, or what needs to be improved. </p>
<p>Having efficient ways to gather such feedback is therefore of extreme importance, yet often overlooked. In a lot of cases, feedback is only being gathered by physically talking to the users. While this results in high quality feedback, it&#8217;s not very efficient and the probability of missing things is very high. </p>
<p>Luckily, we, as developers, can help: there are a lot of technological ways to gather feedback more efficiently, and it&#8217;s our responsibility to make those methods available to our clients. Below are 5 techniques you can use to start shortening the feedback loop today.</p>
<h2>Five things you can start doing today</h2>
<h3>Analyse web server log files</h3>
<p>The web server logs contain a wealth of information. For example, it can help you:</p>
<ul>
<li>Find out which features are used a most-often by looking at the request path</li>
<li>Look for bad user experiences by seeing which requests have high response times or error responses</li>
<li>See when your users use the product most. Does that map to what you expect?</li>
<li>Figure out which users are heavy users</li>
<li>Track individual users as they browse through your site/app</li>
</ul>
<p>It&#8217;s easy to analyze log files with some custom code, or you can use something like <a href="http://www.microsoft.com/en-us/download/details.aspx?id=24659">Log Parser</a>.</p>
<h3>Setup Google Analytics events</h3>
<p>If you&#8217;re using GA you can use events to track user actions. Use this to see what buttons they&#8217;re clicking, whether they&#8217;re scrolling, etc. Use this to figure out if users are actually interacting with your site/app as expected.</p>
<h3>Install chat software</h3>
<p>In-page chat widgets are popping up everywhere. You can install one to provide an easily accessible way for users to contact you. Make sure someone is actually answering the chat, though, or you might leave a bad impression.</p>
<h3>Investigate abandoned funnels</h3>
<p>Funnels can be abandoned for many reasons: it might indicate a use case you didn&#8217;t expect, maybe there was a technical problem or the user changed their mind. Either way, it&#8217;s interesting for you to know why. Use any method you have available to figure out why they happen: correlate logs, events, chats, etc. If you have an e-mail address, send them an e-mail to ask why.</p>
<h3>A/B testing</h3>
<p>A/B testing can help you figure out what your users care and don&#8217;t care about. Both are equally important: if they care about something, do it more. If they don&#8217;t care about something: don&#8217;t try it again and focus on things that do work. You can write the infrastructure yourself, but there are off-the-shelf solutions available as well.</p>
<h2>Truly care</h2>
<p>Just setting things up is not enough; you should also deeply care about the results. If anything looks inconsistent, you should investigate it. If data isn&#8217;t being collected, you should find out why. If some hypothesis is not coming true, you should think of ways to figure out why that is. Do whatever you can to learn more about your users.</p>
<p>Every person on a development team should be aware about who the users are, why they&#8217;re using your product, why they keep coming back, etc. It&#8217;s not just for one single role within the team (think Product Owner) to care about this stuff; everybody should feel responsible. If everybody in the team cares deeply about the users, the product will become much better, there will be more alignment and your work will be more satisfying.</p>
<p>The post <a rel="nofollow" href="https://www.freekpaans.nl/2015/08/start-closing-the-end-user-feedback-loop/">Start closing the end user feedback loop!</a> appeared first on <a rel="nofollow" href="https://www.freekpaans.nl">Freek Paans</a>.</p>
]]></content:encoded>
							<wfw:commentRss>https://www.freekpaans.nl/2015/08/start-closing-the-end-user-feedback-loop/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
							</item>
	</channel>
</rss>

<!--
Performance optimized by W3 Total Cache. Learn more: https://www.w3-edge.com/products/

Page Caching using disk: enhanced (Page is feed) 

Served from: www.freekpaans.nl @ 2026-09-08 19:56:00 by W3 Total Cache
-->