<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <id>https://chodounsky.net/</id>
  <title>The diary of a software developer :: Jakub Chodounský</title>
  <updated>2020-01-14T02:56:07Z</updated>
  <link rel="alternate" href="https://chodounsky.net/"/>
  <link rel="self" href="https://chodounsky.net/feed/index.xml"/>
  <author>
    <name>Jakub Chodounský</name>
    <uri>https://chodounsky.net</uri>
  </author>
  <entry>
    <id>tag:chodounsky.net,2020-01-14:/2020/01/14/suggesting-email-address-using-string-similarity-algorithm/</id>
    <title type="html">Suggesting email address using string similarity algorithm</title>
    <published>2020-01-14T02:56:07Z</published>
    <updated>2020-01-14T02:56:07Z</updated>
    <link rel="alternate" href="https://chodounsky.net/2020/01/14/suggesting-email-address-using-string-similarity-algorithm/"/>
    <content type="html">
&lt;p&gt;&lt;img src="/resources/img/posts/2020-01-13-suggesting-correct-email-address-with-trigrams.png" alt="Suggesting a correct domain for mistyped email address with trigrams" /&gt;&lt;/p&gt;

&lt;p&gt;Recently, we noticed a large number of unconfirmed accounts. Those were not spam accounts they looked like legit users. Are we losing customers that early in the funnel? When we looked closely we noticed a similar pattern:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;john.doe@gnail.com
jane.doe@yahoo.co.nz
tim@outlook.con
susan@gmail.co.nz
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;All of those email addresses have a mistyped domain. That’s not great. I could imagine a customer refreshing their inbox, waiting for a confirmation email, and cursing the internet.&lt;/p&gt;

&lt;p&gt;What could we do to improve the onboarding experience? What if we could detect typos and suggest a correct email for them?&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Did you mean john.doe@gmail.com?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That would be really cool. And luckily for us there is a few neat algorithms that can help us with that.&lt;/p&gt;

&lt;p&gt;In computer science this is an exercise of approximate string matching. And we will use a &lt;a href="https://en.wikipedia.org/wiki/String_metric"&gt;string distance&lt;/a&gt; (or sometimes called a string metric) to quantify how close two words – email domains in our case – are to each other.&lt;/p&gt;

&lt;h2 id="levensthein-distance"&gt;Levensthein Distance&lt;/h2&gt;

&lt;p&gt;The most common string metric is &lt;a href="https://en.wikipedia.org/wiki/Levenshtein_distance"&gt;Levenshtein distance&lt;/a&gt; (also called edit distance). It tells you the minimum number of edits – insertion, deletion, substitution – that need to take place to get to the same word.&lt;/p&gt;

&lt;p&gt;For example &lt;code&gt;gnail.com&lt;/code&gt; and &lt;code&gt;gmail.com&lt;/code&gt; would have Levensthein distance of 1. You need to substitute one character to get to the same word. Those two strings are very similar.&lt;/p&gt;

&lt;p&gt;We can normalise the distance between 0.0 and 1.0 where 0.0 is not similar at all and 1.0 is an exact match. That’s a good idea to do for different string lengths. For that, we divide the edit distance by the length of the longest string and subtract that from 1. For our example it would end up to be 0.88.&lt;/p&gt;

&lt;p&gt;Levensthein distance is usually implemented with &lt;a href="https://en.wikipedia.org/wiki/Dynamic_programming"&gt;dynamic programming&lt;/a&gt; using a variation of &lt;a href="https://en.wikipedia.org/wiki/Wagner%E2%80%93Fischer_algorithm"&gt;Wagner-Fischer algorithm&lt;/a&gt;. Below is a Javascript version from &lt;a href="https://gist.github.com/andrei-m/982927"&gt;Andrei Mackenzie&lt;/a&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;var getEditDistance = function(a, b){
  if(a.length == 0) return b.length;
  if(b.length == 0) return a.length;

  var matrix = [];
  var i;

  for(i = 0; i &amp;lt;= b.length; i++){
    matrix[i] = [i];
  }

  var j;
  for(j = 0; j &amp;lt;= a.length; j++){
    matrix[0][j] = j;
  }

  for(i = 1; i &amp;lt;= b.length; i++){
    for(j = 1; j &amp;lt;= a.length; j++){
      if(b.charAt(i-1) == a.charAt(j-1)){
        matrix[i][j] = matrix[i-1][j-1];
      } else {
        matrix[i][j] = Math.min(matrix[i-1][j-1] + 1,
                                Math.min(matrix[i][j-1] + 1,
                                         matrix[i-1][j] + 1));
      }
    }
  }

  return matrix[b.length][a.length];
};
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id="trigram"&gt;Trigram&lt;/h2&gt;

&lt;p&gt;Levensthein distance is a nifty algorithm but we found it didn’t work particularly well for our dataset. Also, it not easy to scale but for this use case it doesn’t matter.&lt;/p&gt;

&lt;p&gt;There is a few other alternatives. We decided to go for &lt;a href="https://en.wikipedia.org/wiki/Jaccard_index"&gt;Jaccard distance&lt;/a&gt; over &lt;a href="https://en.wikipedia.org/wiki/Trigram"&gt;Trigram&lt;/a&gt; vectors. It sounds scary but don’t be afraid.&lt;/p&gt;

&lt;p&gt;Trigrams are three consecutive letter groups from a string. They are often used in natural language processing as they are relatively cheap to make and provide you with additional context of neighbouring characters.&lt;/p&gt;

&lt;p&gt;Firstly, we decompose a string into trigrams.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;trigram('hello');
['  h', ' he', 'hel', 'ell', 'llo', 'lo ']
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And the code for the above.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;var trigram = function(string) {
  const padded = `  ${string} `.toLowerCase();

  let gramStart = 0;
  let gramEnd = 3;
  const grams = [];

  while (gramEnd &amp;lt;= padded.length) {
    grams.push(padded.substring(gramStart, gramEnd));
    gramStart += 1;
    gramEnd += 1;
  }

  return grams;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;After that, we can calculate the distance. It is a ratio of matching trigrams to their union.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;var distance = function(aGrams, bGrams) {
  const matches = aGrams.filter(value =&amp;gt; bGrams.includes(value));
  const uniqueGrams = [...new Set(aGrams.concat(bGrams))];
  return Number((matches.length / uniqueGrams.length).toFixed(2));
}

var compare = function(a, b) {
  const aGrams = trigram(a);
  const bGrams = trigram(b);
  return distance(aGrams, bGrams);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;With the final number we need to decide what threshold is a possible match. I’d like to say that we did an extensive testing on our dataset to get the perfect distance but we haven’t.&lt;/p&gt;

&lt;p&gt;Instead, we looked at Postgres &lt;a href="https://www.postgresql.org/docs/current/pgtrgm.html"&gt;pg_trgm&lt;/a&gt; extension and used their default of &lt;code&gt;0.3&lt;/code&gt;. And it worked out great.&lt;/p&gt;

&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Last step is hooking these functions up to our registration form. We extract the domain from the input, lowercase it, and remove any white space.&lt;/p&gt;

&lt;p&gt;Then, we run it against a dictionary of our confirmed email domains that have at least a few users registered. That covers most of our basis and runs pretty quickly on a client.&lt;/p&gt;

&lt;p&gt;And with that, we save a customer or two from abandoning the registration.&lt;/p&gt;

&lt;h2 id="resources"&gt;Resources&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="https://medium.com/@ethannam/understanding-the-levenshtein-distance-equation-for-beginners-c4285a5604f0"&gt;Understanding Levensthein Distance for Beginners&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="https://www.npmjs.com/package/js-levenshtein"&gt;js-levensthein&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.67.9369&amp;amp;rep=rep1&amp;amp;type=pdf"&gt;N-gram similarity and distance&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="https://pganalyze.com/blog/similarity-in-postgres-and-ruby-on-rails-using-trigrams"&gt;Similarity in Postgres and Rails using Trigrams&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="https://www.postgresql.org/docs/current/pgtrgm.html"&gt;pg_trgm&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="https://bergvca.github.io/2017/10/14/super-fast-string-matching.html"&gt;Super fast string matching in Python&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="https://medium.com/@appaloosastore/string-similarity-algorithms-compared-3f7b4d12f0ff"&gt;String Similarity Algorithms Compared&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="https://www.cs.cmu.edu/~wcohen/postscript/ijcai-ws-2003.pdf"&gt;A Comparison of String Distance Metrics for Name-Matching Tasks&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="https://www.joyofdata.de/blog/comparison-of-string-distance-algorithms/"&gt;Comparison of String Distance Algorithms&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <id>tag:chodounsky.net,2019-10-21:/2019/10/21/the-great-computer-experiment-ruby-edition/</id>
    <title type="html">The Great Computer Experiment: Ruby Edition</title>
    <published>2019-10-21T08:53:19Z</published>
    <updated>2019-10-21T08:53:19Z</updated>
    <link rel="alternate" href="https://chodounsky.net/2019/10/21/the-great-computer-experiment-ruby-edition/"/>
    <content type="html">
&lt;p&gt;Can a second-hand desktop computer from 2013 run specs? How much does a touch bar speed up an integration suite? Do I need 6 cores to run &lt;code&gt;rails new blog&lt;/code&gt;?&lt;/p&gt;

&lt;p&gt;In this article I’ll put 4 machines and 5 different operating systems through a true test. What am I trying to achieve? I don’t know. But I intend to share my experience with you.&lt;/p&gt;

&lt;h2 id="computers"&gt;Computers&lt;/h2&gt;

&lt;p&gt;Recently, I’ve been playing with different computers and operating systems. I used to be a C# developer on Windows for quite a few years and after switching to Ruby I started using Macs. The direction Apple took with its latest laptops made me explore other options and I tried Linux on a desktop PC. And I was surprised how powerful and cheap desktops are these days.&lt;/p&gt;

&lt;p&gt;Here are the machines that feature in the showdown. Prices are for New Zealand.&lt;/p&gt;

&lt;h3 id="custom-built-pc-2019"&gt;Custom-built PC (2019)&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;i7-8700 (3.2-4.6Ghz, 6 cores with 12 threads)&lt;/li&gt;
  &lt;li&gt;32GB RAM&lt;/li&gt;
  &lt;li&gt;Samsung 970 EVO Plus NVMe SSD&lt;/li&gt;
  &lt;li&gt;Ubuntu 18.04&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Price: $1 500 ($950 USD) new&lt;/p&gt;

&lt;p&gt;This is my main office workstation. It’s custom-built with decent components but nothing lavishly outrageous. It’s a perfect compromise of snappy performance and cost. It runs basic Ubuntu 18.04 installation with no customisations. Good reliable work horse.&lt;/p&gt;

&lt;h3 id="macbook-pro-13-2013"&gt;Macbook Pro 13” (2013)&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;i7-4558U (2.8-3.2GHz, 2 cores with 4 threads)&lt;/li&gt;
  &lt;li&gt;8GB RAM&lt;/li&gt;
  &lt;li&gt;macOS 10.14 Mojave&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Price: ~$700 ($450 USD) second-hand&lt;/p&gt;

&lt;p&gt;The price is for a similar machine on the second-hand market in New Zealand. This has been my day-to-day machine for the last 6 years. I still use it when working from home or on the go.&lt;/p&gt;

&lt;p&gt;Double amount of RAM would be better and maybe more cores but I’m not planning replacing it any time soon. It is a solid laptop with a great keyboard and beautiful screen. Recently, I was tempted by some of the new ThinkPads but I’m too scared of Linux on a laptop. If there is something I don’t want to do it’s tinkering with touchpad drivers, keyboard backlighting, and wonky wi-fi.&lt;/p&gt;

&lt;h3 id="budget-dell-2013"&gt;Budget Dell (2013)&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;i5-4570 (3.2-3.6GHz, 4 cores with 4 threads)&lt;/li&gt;
  &lt;li&gt;Crucial MX500 SATA 3 SSD&lt;/li&gt;
  &lt;li&gt;16GB RAM&lt;/li&gt;
  &lt;li&gt;Windows 10 WSL 2 Ubuntu 18.04&lt;/li&gt;
  &lt;li&gt;Ubuntu 18.04&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Price: $250 + $70 RAM + $95 SSD ($260 USD) second-hand with new SSD and RAM&lt;/p&gt;

&lt;p&gt;This PC is Dell OptiPlex 9020 that was released mid 2013 – close to my Macbook Pro. Machines like this are great if you are short on budget. They are build to last and cheap. I was lucky and got mine for free from an office giveaway and immediately replaced HDD for SSD. It came with Windows and I started using it for photo editing with Adobe Lightroom and Photoshop at home. Since then I added extra RAM and GPU to make Lightroom snappier (GPU is not included in the price though).&lt;/p&gt;

&lt;p&gt;I will use it as a guinea pig for WSL 2 and bare metal Linux to compare the two. Is it worthy alternative for my trustworthy Macbook? Is WSL ready for serious work? Can we finally develop Rails on Windows?&lt;/p&gt;

&lt;h3 id="macbook-pro-13-2018"&gt;Macbook Pro 13” (2018)&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;i7-8559U (2.7-4.5Ghz, 4 cores with 4 threads)&lt;/li&gt;
  &lt;li&gt;16GB RAM&lt;/li&gt;
  &lt;li&gt;macOS 10.14 Mojave&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Price: ~$4 800 ($3 000 USD) new&lt;/p&gt;

&lt;p&gt;Last year’s top of the line Macbook comes with a hefty price tag. I’m not a big fan of the keyboard and touch bar and this nugget belongs to my friend who helped me out with running some of the benchmarks.&lt;/p&gt;

&lt;p&gt;It will be interesting to compare it to the custom-built PC.&lt;/p&gt;

&lt;h2 id="benchmarks"&gt;Benchmarks&lt;/h2&gt;

&lt;p&gt;For each test I ran it 4 times, then discarded the worst value, and averaged the rest. While running the tests I was doing some light web browsing (if there is such a thing) and ran Slack to simulate happy developers’ day.&lt;/p&gt;

&lt;p&gt;These are not your typical synthetic benchmarks but a real world performance. Including hackernews and epilepsy-inducing giphies.&lt;/p&gt;

&lt;p&gt;&lt;img src="https://imgs.xkcd.com/comics/compiling.png" alt="XKCD compiling classic" /&gt;&lt;/p&gt;

&lt;h3 id="internal-project"&gt;Internal project&lt;/h3&gt;

&lt;p&gt;This is the most important test. The codebase that I work on day to day is &lt;strong&gt;the&lt;/strong&gt; benchmark. It is a standard Rails monolith with React front-end and the suite is a combination of&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;rubocop,&lt;/li&gt;
  &lt;li&gt;webpacker,&lt;/li&gt;
  &lt;li&gt;rspec (single-threaded),&lt;/li&gt;
  &lt;li&gt;feature specs (headless chrome) and&lt;/li&gt;
  &lt;li&gt;jest.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src="/resources/img/posts/2019-10-21-internal-project-benchmark.png" alt="Bare metal Linux is the winner here followed closely by the expensive Macbook" /&gt;&lt;/p&gt;

&lt;p&gt;Linux is the clear winner here. The 2018 Macbook Pro is ~10% slower than the PC. And WSL 2 is 1.4x slower than running native Linux. What a bummer.&lt;/p&gt;

&lt;p&gt;What surprised me is how good the old Dell with native Linux is. It ran the suite in almost the same time as the custom-built PC from 2019. I don’t have a good explanation for it – I was expecting it to be worse. The CPU is slower (3.6GHz vs 4.6GHz) and the disk is slower (budget SATA 3 SSD vs NVMe).&lt;/p&gt;

&lt;h3 id="ruby"&gt;Ruby&lt;/h3&gt;

&lt;p&gt;Next task is CPU intensive Ruby 2.6.5 compilation.&lt;/p&gt;

&lt;p&gt;&lt;img src="/resources/img/posts/2019-10-21-ruby-2.6.5-benchmark.png" alt="Linux PC dominates this test with 2013 Macbook showing its age" /&gt;&lt;/p&gt;

&lt;p&gt;The 2013 Macbook Pro is showing its age here. The combination of 3.2Ghz with macOS are not cutting it. Again the bare metal Linux dominates and surprisingly the new 2018 Macbook Pro is lagging behind.&lt;/p&gt;

&lt;h3 id="devise"&gt;Devise&lt;/h3&gt;

&lt;p&gt;The popular gem for rails authentication has a small set of unit and integration tests. No parallelisation here either.&lt;/p&gt;

&lt;p&gt;&lt;img src="/resources/img/posts/2019-10-21-devise-benchmark.png" alt="WSL 2 on a budget machine is beating $4 800 Macbook Pro" /&gt;&lt;/p&gt;

&lt;p&gt;Linux PC is up by a mile but the WSL 2 on a budget hardware is beating 2018 Macbook Pro.&lt;/p&gt;

&lt;h3 id="activeadmin"&gt;ActiveAdmin&lt;/h3&gt;

&lt;p&gt;This suite is a good mix of unit, integration, and UI specs. Also, it makes use of some parallelisation so the results might be interesting.&lt;/p&gt;

&lt;p&gt;&lt;img src="/resources/img/posts/2019-10-21-active-admin-benchmark.png" alt="First win for 2018 Macbook Pro just by a second from Linux PC" /&gt;&lt;/p&gt;

&lt;p&gt;First win for macOS on the 2018 Macbook Pro – just by a second ahead of the Linux PC. Solid performance with budget Dell and WSL 2 is acceptable.&lt;/p&gt;

&lt;h3 id="mastodon"&gt;Mastodon&lt;/h3&gt;

&lt;p&gt;Last one is running the social network test suite with a mix of unit, integration, and UI tests. It is a good representation of standard Rails project.&lt;/p&gt;

&lt;p&gt;Unfortunately, it’s missing numbers from the 2018 Macbook Pro but let’s compare the remaining.&lt;/p&gt;

&lt;p&gt;&lt;img src="/resources/img/posts/2019-10-21-mastodon-benchmark.png" alt="Linux PC claiming the title again with budget PC lagging by 40s" /&gt;&lt;/p&gt;

&lt;p&gt;The Linux PC is claiming the title back here and budget PC is lagging behind by more than 40s. There is a performance hit on the WSL 2. With 2013 Macbook Pro you are better off running the suite in your CI pipeline.&lt;/p&gt;

&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Firstly, all these machines are perfectly capable of developing Ruby and Rails applications. While coding you might be running a spec or two and leave the whole suite to your CI. That makes even a 6 years old laptop acceptable while on the road.&lt;/p&gt;

&lt;p&gt;What surprised me is how good the old Dell with bare metal Linux performed. You can get this machine for so little money and have an excellent PC for work.&lt;/p&gt;

&lt;p&gt;Linux in general is not such a hassle as it used to be. As long as you keep things simple and stick to the vanilla settings. I’m not too demanding and I avoid common pitfalls (high DPI displays, power management, customising UI, etc.) so it works for me. Not having an official OneDrive client and Office sucks though.&lt;/p&gt;

&lt;p&gt;WSL 2, while still in preview, is a decent option and I didn’t run into any issues with it. In combination with the new Windows Terminal and Visual Studio Code it is a joy to work with. It might be the end of Macbook domination in the laptop space for web developers. Still you are getting a performance hit but Windows ecosystem might be worth the trade (or not … depending on your personal preferences).&lt;/p&gt;

</content>
  </entry>
  <entry>
    <id>tag:chodounsky.net,2019-03-24:/2019/03/24/progressive-web-application-as-a-share-option-in-android/</id>
    <title type="html">Progressive web application as a share option in Android</title>
    <published>2019-03-23T21:28:57Z</published>
    <updated>2019-03-23T21:28:57Z</updated>
    <link rel="alternate" href="https://chodounsky.net/2019/03/24/progressive-web-application-as-a-share-option-in-android/"/>
    <content type="html">
&lt;p&gt;&lt;a href="/2016/12/23/progressive-web-applications/"&gt;Progressive Web Applications&lt;/a&gt; are becoming more and more powerful and now can be registered as a share intent on Android devices. This means that any Android application can share directly to your web app through the standard native sharing dialog.&lt;/p&gt;

&lt;p&gt;&lt;img src="/resources/img/posts/2019-03-24-share-dialog.png" alt="Website in the native share intent dialog" /&gt;&lt;/p&gt;

&lt;p&gt;It also works the other way around. Your &lt;a href="https://developers.google.com/web/updates/2016/09/navigator-share"&gt;PWA can trigger&lt;/a&gt; the native share dialog and send data to other applications. This brings them one step closer to native apps.&lt;/p&gt;

&lt;p&gt;In this article we will focus on becoming the share target.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Can a progressive web app be registered as a share option in Android?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For a long time this wasn’t an option. But with the release of &lt;a href="https://www.chromestatus.com/features/5662315307335680"&gt;Chrome 71&lt;/a&gt; on Android there is an experimental support of the &lt;a href="https://github.com/WICG/web-share-target"&gt;Web Share Target API&lt;/a&gt;. Your PWA can appear in the sharing menu. How cool is that?&lt;/p&gt;

&lt;p&gt;Let’s have a look at what you need to get your website into the Android sharing dialog:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Manifest&lt;/li&gt;
  &lt;li&gt;Service Worker&lt;/li&gt;
  &lt;li&gt;Share target&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id="becoming-progressive"&gt;Becoming progressive&lt;/h2&gt;

&lt;p&gt;The first steps are really about becoming a progressive web application. The share intent will be registered when the user “installs” the app by saving it to the &lt;a href="https://developers.google.com/web/fundamentals/app-install-banners/"&gt;home screen&lt;/a&gt; – either from a popup or manually.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Important note: &lt;strong&gt;Your website needs to be served over HTTPS&lt;/strong&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src="/resources/img/posts/2019-03-24-add-home.png" alt="Add to home screen popup dialog" /&gt;&lt;/p&gt;

&lt;p&gt;For that you will need a website manifest and a registered service worker. Firstly, let’s have a look at a simple &lt;code&gt;manifest.json&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;{
  "short_name": "Sharing Demo",
  "name": "Web Target Sharing Demo",
  "icons": [
    {
      "src": "/android-chrome-192x192.png",
      "type": "image/png",
      "sizes": "192x192"
    },
    {
      "src": "/android-chrome-512x512.png",
      "type": "image/png",
      "sizes": "512x512"
    }
  ],
  "start_url": "/",
  "background_color": "#ffffff",
  "display": "standalone",
  "theme_color": "#ffffff"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You can read about all the different values and options in more detail &lt;a href="https://developers.google.com/web/fundamentals/web-app-manifest/"&gt;here&lt;/a&gt;. After that, we will need to link to our manifest in our HTML files. So add the following into &lt;code&gt;head&lt;/code&gt; section of your page.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;link rel="manifest" href="/manifest.json"&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The Second thing for an app to become a PWA is a registered service worker with a &lt;code&gt;fetch&lt;/code&gt; event. It doesn’t need to do much, it just has to be there. The simplest way to do that is to create &lt;code&gt;service-worker.js&lt;/code&gt; with an empty fetch listener.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;self.addEventListener('fetch', function(event) {});
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It won’t do anything but it is everything we need for now. Next, we will register the service worker in our page.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;if ('serviceWorker' in navigator) {
    navigator.serviceWorker.register('/service-worker.js')
      .then(function(reg){
        console.log("Service worker registered.");
     }).catch(function(err) {
        console.log("Service worker not registered. This happened:", err)
    });
 }
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Nice work! It wasn’t too hard and we changed a simple website into a progressive web app. If you are using HTTPS you should be able to see the &lt;em&gt;Add to home screen&lt;/em&gt; popup when you visit your website.&lt;/p&gt;

&lt;p&gt;&lt;img src="/resources/img/posts/2019-03-24-add-home-2.png" alt="Add to home screen prompt for progressive web apps" /&gt;&lt;/p&gt;

&lt;p&gt;You can use Chrome Dev Tools to check on the manifest and see if the app can be installed. Go to &lt;code&gt;Application -&amp;gt; Manifest&lt;/code&gt; or use &lt;a href="https://developers.google.com/web/tools/lighthouse/"&gt;Lighthouse&lt;/a&gt; and see the &lt;em&gt;Installable&lt;/em&gt; section of the report.&lt;/p&gt;

&lt;h2 id="adding-web-share-target"&gt;Adding web share target&lt;/h2&gt;

&lt;p&gt;Converting your website to a progressive web application was actually the hard part. Registering the share intent so your app will appear in the native dialog is super easy.&lt;/p&gt;

&lt;p&gt;You need to add the following lines into your &lt;code&gt;manifest.json&lt;/code&gt; that we created previously.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;  "share_target":
  {
    "action": "/share",
    "params":
    {
      "title": "title",
      "text": "text",
      "url": "url"
    }
  },
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Every time a user will share something through the dialog the request will go to &lt;code&gt;/share&lt;/code&gt; endpoint of your website with query parameters of title, text, and url.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: If you are sharing something from mobile Chrome the URL actually comes through as a text.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Now we put everything together and this is the final version of the &lt;code&gt;manifest.json&lt;/code&gt; file with registered &lt;code&gt;share_target&lt;/code&gt; section.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;{
  "short_name": "Sharing Demo",
  "name": "Web Target Sharing Demo",
  "icons": [
    {
      "src": "/android-chrome-192x192.png",
      "type": "image/png",
      "sizes": "192x192"
    },
    {
      "src": "/android-chrome-512x512.png",
      "type": "image/png",
      "sizes": "512x512"
    }
  ],
  "share_target":
  {
    "action": "/share",
    "params":
    {
      "title": "title",
      "text": "text",
      "url": "url"
    }
  },
  "start_url": "/",
  "background_color": "#ffffff",
  "display": "standalone",
  "theme_color": "#ffffff"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;After that, you can use any method of reading the query parameters that suits your needs. Either server-side like this with Ruby on Rails:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;def share
  @url = params[:url]
  @title = params[:title]
  @text = params[:text]
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;or client-side with a bit of good old javascript:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;var parsedUrl = new URL(window.location.toString());
console.log('Title shared: ' + parsedUrl.searchParams.get('name'));
console.log('Text shared: ' + parsedUrl.searchParams.get('description'));
console.log('URL shared: ' + parsedUrl.searchParams.get('link'));
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I’m a big fan of progressive web apps and the web share target makes the integration with your mobile workflow much smoother. It comes with a few caveats of being experimental so the API will most likely change or it could totally disappear. Also, keep in mind that (at the moment) it’s supported only on Android devices and your Apple users won’t benefit from it
. The proposal takes iOS into account though so maybe some time in the future. I’ve been waiting for this feature for a while and I’m super-excited that it made it to the Android community.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <id>tag:chodounsky.net,2018-03-25:/2018/03/25/reading-list-2017/</id>
    <title type="html">Reading list 2017</title>
    <published>2018-03-24T20:26:40Z</published>
    <updated>2018-03-24T20:26:40Z</updated>
    <link rel="alternate" href="https://chodounsky.net/2018/03/25/reading-list-2017/"/>
    <content type="html">
&lt;p&gt;As I shared my &lt;a href="/2017/01/12/reading-diary-of-2016/"&gt;reading list&lt;/a&gt; last year I’d like to do the same for 2017. Hopefully, you’ll find an interesting book or two to add to your list.&lt;/p&gt;

&lt;h2 id="technology"&gt;Technology&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/6713575-coders-at-work"&gt;Coders at Work&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This book is full of interviews with people that were influential for computer science, algorithms, and operating systems. I was expecting more people closer to application programmer’s reality. Don’t get me wrong, I have a huge respect for people like Donald Knuth or Guy Steele, but it’s not what the majority of us do every day. I was seeking some inspiration and found none. Well, at least I got some insight into a few groundbreaking projects like Netscape, Javascript, Erlang, or Unix.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/34076755-the-complete-redux-book"&gt;The Complete Redux Book&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This book is, more or less, a written version of Dan Abramov’s &lt;a href="https://egghead.io/courses/getting-started-with-redux"&gt;Redux course&lt;/a&gt; where he builds the library  from scratch. It’s a quick read that helps you understand the core principles of Redux architecture.&lt;/p&gt;

&lt;h2 id="business-and-self-development"&gt;Business and self-development&lt;/h2&gt;

&lt;p&gt;I’ve read too many junk business and self-help books over the last few years. The ones that give you an insight into an unknown field are worth reading. But the ones that are like &lt;em&gt;“I have it all figured out”&lt;/em&gt;, &lt;em&gt;“What worked for me will work for you”&lt;/em&gt;, and &lt;em&gt;“(Don’t or Do) Follow your passion”&lt;/em&gt; seems to be a waste of time. Read one and skip the rest.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/141850.The_Ten_Day_MBA_"&gt;Ten-Day MBA&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The book looks at various aspects of the business—from marketing, ethics, accounting to operations, finance, strategy, and others. It’s a great read for a programmer as you are usually working with those teams and the book will give you a common language and a better understanding of each other. And also, MBAs really like to use acronyms and things like the plan of five P or a five S strategy—mention it (or a quote The Art of War) in a meeting and you’ll be taken seriously.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/13525945-so-good-they-can-t-ignore-you"&gt;So Good They Can’t Ignore You&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A book that tells you that you won’t be happy by following your passion. That is a good news for people who are not sure what their passion is. You pick something, get better in it, build a career capital that allows you to get more freedom, and find a mission that you can fulfill with the capital you built. That’s how you gonna love what you do. It makes sense, more sense than blindly following your passion and dreaming of becoming a lumberjack or a farmer in your cubicle.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/28257707-the-subtle-art-of-not-giving-a-f-ck"&gt;The Subtle Art of Not Giving a F*ck&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;An antidote to all of those self-help be happy books—you are not special, you need to lose, you need negative experiences. You won’t achieve much by only being positive. Care about things that are dear to you and ignore what TV and social media tell you, etc, etc.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Buddhism dressed up a little for millennials&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And it’s orange and has a swear word in the title so it’s gonna be a best-seller.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/22091581-traction"&gt;Traction: A Startup Guide to Getting Customers&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A book with concrete advice on how to grow your audience through different channels. Each channel has a small case study and tells you at what stage and type of startup it worked. Not all the channels will be applicable to your business but this gives you an idea which ones to try out.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/8549192-traction"&gt;Traction&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I’m gonna admit it. I wanted to read the startup Traction but I picked up this one instead by mistake. And I realized that there is something fishy going on when I was already in a third of the book. Sunk cost fallacy kicked in and I finished the book.&lt;/p&gt;

&lt;p&gt;The result of that is gaining better vocabulary when talking with C-level execs. Apart from that, it gives you a framework to apply in your company to improve the company. If you are a CEO. Oh well, I’m not a CEO. So I can’t really tell you if it’s working or not. Sorry.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/368593.The_4_Hour_Workweek"&gt;The 4-Hour Week&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Firstly, the tone of this book makes you cringe. And apart from that, there is not really much that would stick with me. It tells you to define your goals, take mini-retirements/sabbaticals, be effective, cut out unimportant, automate, don’t multitask, and many other things that I can’t argue with.&lt;/p&gt;

&lt;p&gt;Also, it tells you to learn to leave things unfinished—I should’ve read that before accidentally going through the CEO Traction, hey?&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/62085.Corporate_Confidential"&gt;Corporate Confidential&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;An eye-opening introspection into a corporate culture and HR practices that is both chilling and depressing to read. But, it’s still better to know the other side than to ignore it. You can decide whether you want to play along or face the consequences. It’s coming from an American background but it applies to Europe and New Zealand to a certain extent as well.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/33121747-the-barefoot-investor"&gt;The Barefoot Investor&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With a cheesy title comes a book with cheesy text and big letters. I’ve read this one because of work. The style might suit some and the general advice is not too bad. The benefit of the book is targeting Australians and capturing the specifics of their retirement plans, taxes, and others. Oh boy, and those testimonials at the end of each chapter—does anyone apart from the author likes to read them?&lt;/p&gt;

&lt;h2 id="non-fiction"&gt;Non-fiction&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/96110.Vietnam?ac=1&amp;amp;from_search=true"&gt;Vietnam: A History&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A long and very thorough description of events that lead to the US involvement in Vietnam and, eventually, to the war. Stanley Karnow lived there through those years and worked there as a journalist. The book is filled with personal experience with key actors and gives a lot of detailed background but doesn’t really go into many details of why.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/21856367-the-innovators"&gt;Innovators&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A decent audiobook to listen to—well narrated. Isaacson describes stories around the major breakthroughs that led to the current state of computer technology. From Ada Lovelace to the internet. He focuses on the people and teams and gives lots of details about the personality of each inventor.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/21.A_Short_History_of_Nearly_Everything"&gt;The Short History of Nearly Everything&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;An interesting book covering the history of various fields of science from physics, cosmology, to chemistry, and paleontology. It tells you how we’ve came to know as much as we do now. The style is accessible and, despite the range of the topics, you are not getting lost. It is fascinating and informative read.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/7865083-liar-s-poker"&gt;Liar’s Poker&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It is an account of greed in the investment banking industry in the 80s at Wall Street that the author lived through. The story is told by a graduate, the author, joining Salomon Brothers and becoming a bond salesman. He hated investment bankers but he still kept screwing the clients and getting the “fat paychecks with bonuses” coming each year to his bank account.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Never before have so many unskilled twenty-four-year-olds made so much money in so little time as we did …&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;There is a slight hint of what led to the financial crisis in 2008 which is described in another of the author’s books—The Big Short. Lastly, Lewis has a real talent for explaining complex financial instruments with simple and easy to understand analogies (e.g. mortgage-backed securities).&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/2715.Salt"&gt;Salt: A World History&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I didn’t have any idea how much a common thing like salt influenced the world history. Back in the day, having access to enough salt allowed you to preserve more food. More food led to feeding more people. Feeding more people get you bigger armies. Armies won wars. Winning wars gave you more power.&lt;/p&gt;

&lt;p&gt;Another interesting part of the book is how different cultures used different means of salting and preserving the food. From fish sauce in the Roman empire and still in use in Asian cuisines with soy sauce to a plain use of crystals.&lt;/p&gt;

&lt;p&gt;Salt was worth more than gold.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/222146.Masters_of_Doom"&gt;Masters of Doom&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A book that goes to the roots of id Software and takes you to the journey of the most influential games of the 90s—Wolfenstein 3D, Doom, and Quake. It draws the relationship between John Carmack, John Romero, and Tom Hall. It’s a great story and if you played those games at that time you won’t be able to put the book down. I listened to an audiobook and it was perfectly narrated.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/16131090-eating-on-the-wild-side"&gt;Eating on the Wild Side&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is probably the geekiest book that I read last year. It tells you where our modern vegetable came from, what we lost and gained through the selection and breeding, and how to choose the most nutritional varieties. Also, it shares many other tips like how to store it (don’t put tomatoes in the fridge), or what is the best way to prepare so you get the most nutrients (cook your tomatoes). I love learning about things that you can use (and eat) every day.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/28512671-everybody-lies"&gt;Everybody Lies&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It shows you what random facts you can learn by studying Google searches dataset. Those would be presented with some funny and some quirky moments. At the end, there is a discussion about the limitation of the data analysis.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/18600.Touching_the_Void"&gt;Touching the Void&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A chilling story about two climbers facing a tough decision. It goes to a description of what goes through one’s head in an almost impossible situation. It’s a raw encounter with powerful unforgiving mountains.&lt;/p&gt;

&lt;h2 id="fiction"&gt;Fiction&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/41804.I_Robot"&gt;I, Robot&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A few short stories from a near future about robots—it is an entertaining book filled with logic around three laws of robotics that Asimov defined. The book was written in 1950 but somehow feels up to date.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/7745.Fear_and_Loathing_in_Las_Vegas"&gt;Fear and Loathing in Las Vegas&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A surreal story of seeking American Dream by going to Las Vegas with a pack full of drugs. Two guys on drugs doing crazy things described in a great style and language. I loved the book but I hope it is not based on a true story. I’m slightly suspicious that it is (at least partially). There is a movie version with Benicio Del Toro and Johny Depp—a great adaptation of the book.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/2108198.Odd_and_the_Frost_Giants"&gt;Odd and the Frost Giants&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/10256723-ghost-in-the-wires"&gt;Ghost in the Wires&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/32144990-norse-mythology"&gt;Norse Mythology&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/19494.The_Spy_Who_Came_In_from_the_Cold"&gt;The Spy Who Came In from the Cold&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/28481481-the-little-pocket-book-of-pug-wisdom"&gt;The Little Pocket Book of Pug Wisdom&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id="recommendation"&gt;Recommendation&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/141850.The_Ten_Day_MBA_"&gt;Ten-Day MBA&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/62085.Corporate_Confidential"&gt;Corporate Confidential&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those two are not very entertaining but they will help your career. The Ten-Day MBA gives you a solid understanding of different parts of a company. It will help you make better decisions as a programmer and have more empathy for others.&lt;/p&gt;

&lt;p&gt;The latter was depressing but if you aim to climb a corporate ladder it’s an eye-opening experience into a big companys’ culture and politics.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/222146.Masters_of_Doom"&gt;Masters of Doom&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I just loved that book — totally recommended if you haven’t read or listened to it yet. Growing up with these games and following the authors in the game magazines throughout the 90s makes it even more fun.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/21.A_Short_History_of_Nearly_Everything"&gt;The Short History of Nearly Everything&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/2715.Salt"&gt;Salt: A World History&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I love learning about ordinary things and I would have never thought that salt had so much impact on the history of mankind. And Bryson’s book gives you an entertaining peek into the history of science with lots of details presented in a cohesive way.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/7745.Fear_and_Loathing_in_Las_Vegas"&gt;Fear and Loathing in Las Vegas&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/18600.Touching_the_Void"&gt;Touching the Void&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One is a surreal road trip to a pop culture of the 70s filled with substance abuse, and the other is a cruel raw encounter with a mountain. Both books are like a bizarre car wreck — you are chilled to the bone but unable to turn away.&lt;/p&gt;

&lt;p&gt;And what have you read last year? What book would you recommend to put on the reading list for the next one?&lt;/p&gt;
</content>
  </entry>
  <entry>
    <id>tag:chodounsky.net,2018-03-13:/2018/03/13/tips-for-getting-a-programming-job-abroad/</id>
    <title type="html">Tips for getting a programming job abroad</title>
    <published>2018-03-13T06:42:38Z</published>
    <updated>2018-03-13T06:42:38Z</updated>
    <link rel="alternate" href="https://chodounsky.net/2018/03/13/tips-for-getting-a-programming-job-abroad/"/>
    <content type="html">
&lt;p&gt;&lt;img src="/resources/img/posts/2018-03-13-tips-for-getting-a-programming-job-abroad.jpg" alt="On the way to the most northern part of New Zealand --- Cape Reinga" /&gt;&lt;/p&gt;

&lt;p&gt;A few years ago I moved from the Czech Republic to New Zealand. I didn’t have a network, a job offer, or a scheduled interview.&lt;/p&gt;

&lt;p&gt;There are lots of benefits of moving to a different country. You are opening yourself to different ideas, mindset, and experience. You can learn the language, better understand a foreign culture, and adopt new ways of doing things. It is a scary step but one worth doing.&lt;/p&gt;

&lt;p&gt;I had never quit a job without another offer. And now I was moving across the globe with anything in my hands. In the end, I managed to find a great job. Sorted out a residency. And have an awesome career. I’d like to share a few tips that will make it easier if you decide to do the same.&lt;/p&gt;

&lt;h2 id="research"&gt;Research&lt;/h2&gt;

&lt;p&gt;It is important to do your own research. Firstly, you need to figure out how much the cost of living in your destination is and how much money you might earn.&lt;/p&gt;

&lt;p&gt;I found &lt;a href="https://www.numbeo.com/cost-of-living/in/Wellington"&gt;Numbeo&lt;/a&gt; to be a great source of information. You can compare the numbers in your current location and adjust them if they are not that accurate. Remember that you will learn by trial and error so the first few months might be more costly than you planned.&lt;/p&gt;

&lt;p&gt;Also, searching for &lt;em&gt;“Cost of living in [destination]”&lt;/em&gt; might lead you to other useful resources from expats, travel bloggers, and even &lt;a href="https://www.newzealandnow.govt.nz/living-in-nz/money-tax/comparable-living-costs"&gt;governments&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now it is time to figure out how much you might earn. There are heaps of global sources on this topic like &lt;a href="https://www.payscale.com/research/NZ/Job=Senior_Software_Engineer/Salary/e22c4d28/Wellington"&gt;PayScale&lt;/a&gt; or &lt;a href="https://www.glassdoor.com/Salaries/wellington-software-developer-salary-SRCH_IL.0,10_IM1179_KO11,29.htm"&gt;Glassdoor&lt;/a&gt; but the best place to start is a local job board. Some posts will have a salary range and you will get the feel on how many jobs are out there. For New Zealand there are two major boards: &lt;a href="https://seek.co.nz"&gt;Seek&lt;/a&gt; and &lt;a href="https://www.trademe.co.nz/jobs"&gt;TradeMe&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Another great place to get information about wages is a report from local recruiting agencies. A few of them publish salary reports for different IT positions and technologies.&lt;/p&gt;

&lt;p&gt;Money is important but don’t forget to take into account other factors that are dear to you. It could be pollution, commute time, work-life balance, ocean, mountains, sun, health care, active community, and many others. For that, I also recommend Numbeo’s indexes: &lt;a href="https://www.numbeo.com/quality-of-life/rankings.jsp"&gt;quality of life&lt;/a&gt;, &lt;a href="https://www.numbeo.com/pollution/rankings.jsp"&gt;pollution&lt;/a&gt;, and a bit more time spent on Google. Seriously, I didn’t know that Wellington is one of the windiest cities in the world.&lt;/p&gt;

&lt;p&gt;While you are scanning the job boards you will get an idea about the popularity of your tech stack. More opportunities equal to less stressful transition. And remember, your first position doesn’t have to be a dream job. A stable job that helps you with your visa situation and a good work-life balance can be a great choice for the first few years while you are settling in the new country. On the other hand, if you are highly specialized (e.g. research in computer graphics algorithms) and there would be a company that could use your skill (Wellington is a home of movie effects) it could be easier.&lt;/p&gt;

&lt;p&gt;When you want to work in another country you will need a work visa. If you are moving from one EU country to another it is very simple thanks to the Schengen area. Similarly, New Zealand has a &lt;a href="http://newzealand.embassy.gov.au/wltn/Visas_and_Immigration.html"&gt;pact&lt;/a&gt; with Australia and I bet other countries do as well.&lt;/p&gt;

&lt;p&gt;A few countries (&lt;a href="https://www.homeaffairs.gov.au/Trav/Visa-1/462-"&gt;Australia&lt;/a&gt;, &lt;a href="https://www.immigration.govt.nz/new-zealand-visas/options/work/thinking-about-coming-to-new-zealand-to-work/working-holiday-visa"&gt;New Zealand&lt;/a&gt;, &lt;a href="https://www.canada.ca/en/immigration-refugees-citizenship/services/work-canada/iec.html"&gt;Canada&lt;/a&gt;, and others) have a working holiday program which might be a good starting option if you match the entering criteria.&lt;/p&gt;

&lt;p&gt;Getting the visa can be the biggest hurdle but there is a shortage of good programmers all around the world so companies might go above and beyond to get your skills. Keep in mind that migrants are still a big risk for the company and getting them onboard is time-consuming and not that cheap.&lt;/p&gt;

&lt;h2 id="building-a-network"&gt;Building a network&lt;/h2&gt;

&lt;p&gt;To find a great job it helps to have a network. The best positions could come from your friends and colleagues you worked and built great relationships with. But how can you get around that when you have no connections and starting from the ground?&lt;/p&gt;

&lt;p&gt;There are a few things that you can do before you arrive at the new country. It won’t be as effective but it will do the trick.&lt;/p&gt;

&lt;p&gt;Start making connections by cold emailing a few people from local communities. Find out if there is a meetup group for your stack (an example could be the &lt;a href="https://www.meetup.com/WelliDotNet/"&gt;WelliDotNet&lt;/a&gt; group in Wellington). Another place where programmers hang out “locally” could be Slack channels, IRC, or Facebook groups. Do a bit of a legwork and find those places. If all fails there is always LinkedIn. People are generally pretty helpful even to a complete stranger. A polite and informed stranger though.&lt;/p&gt;

&lt;p&gt;Choose people that seem to be active in the community—explain your current situation and show them you did some research and put an effort into the message. Ask a few and easy to answer questions and start building that relationship. Best people to contact could be past presenters, organizers, administrators, or just the ones who seems to be answering others’ questions. Get in touch with at least a few different people to “diversify” so you limit a chance of reaching out people inside a bubble.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Hi Jane,&lt;/p&gt;

  &lt;p&gt;my name is John and I’m a .NET programmer from Prague. I’ve been programming for over 5 years and mostly in bigger companies in healthcare. I’m looking to move to New Zealand and was wondering if I could ask you a few questions.&lt;/p&gt;

  &lt;p&gt;I love working with diverse people that care, on a product that helps. Bigger companies might be a better choice for me as I’d like to have some stability to get my family settled first.&lt;/p&gt;

  &lt;p&gt;It seems that there are a few big .NET companies in Wellington. Xero, TradeMe, and Datacom. Are those nice places to work? Would you recommend any others? Should I stay away from some of the local companies?&lt;/p&gt;

  &lt;p&gt;There is also lots of opportunities in Auckland, but people seem to prefer Wellington. Would you recommend Wellington over Auckland as well?&lt;/p&gt;

  &lt;p&gt;Thank you for your time,&lt;br /&gt;
John&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Once you moved it’s nice to get in touch with those that helped and buy them a coffee or a beer. A simple “thank you” will also do if you run into them at one of the meetups.&lt;/p&gt;

&lt;h2 id="applying"&gt;Applying&lt;/h2&gt;

&lt;p&gt;From my experience companies and recruiters won’t take you seriously until you move (unless your destination is just a short flight away). You can start sending CVs and cover letters but don’t feel bad if you are not getting any response. It will change once you arrive.&lt;/p&gt;

&lt;p&gt;Always mention your visa situation in your CV and note it in your cover letter as well. If you have a work visa it will be to your advantage and if not at least you are not putting the company on the spot with an unpleasant surprise (some of them can’t afford to sort the visa out for you).&lt;/p&gt;

&lt;p&gt;When you are new to the country you might fall into a certain bias and getting your first job will be harder than the next one. Employers might worry that you don’t share the same work culture and ethics, and will have a language barrier. Because of that, you might not get jobs that you are a perfect fit. If that happens to you don’t worry too much about it and don’t get discouraged.&lt;/p&gt;

&lt;p&gt;Another point to consider is mentioning your family (or partner) situation. That’s a fair point because a common thing I’ve seen is that programmers (who get the job) arrive with their partners that can’t find any job. The partner becomes unhappy in a few months, and want to leave back to their country. The programmer will usually follow them and the employer loses a member of the team they invested in and need to start hiring again. To mitigate the risk show commitment to staying in the country and if you are not alone mention what’s the plan for your significant other. You don’t have to be too specific—just the fact that you thought about it shows a lot.&lt;/p&gt;

&lt;p&gt;Lastly, it is easier to follow up with the leads you gathered through remote networking than applying to recruiters and job ads. But don’t frown upon any of those and use all the channels that are available.&lt;/p&gt;

&lt;p&gt;It won’t be easy but if you persist you will find a good place to work for.&lt;/p&gt;

&lt;h2 id="tips"&gt;Tips&lt;/h2&gt;

&lt;p&gt;I can’t stress enough the importance of having enough money in your bank account. At least a few months worth of rent and food (and possibly a return ticket back home) will help your confidence and greatly reduce the already stressful experience. It will allow you to take your time to interview for different jobs, find a place to live that you will enjoy, and helps to settle in. You want to take enough time and don’t rush anything.&lt;/p&gt;

&lt;p&gt;Make sure you have a plan for your family and your significant other. If they are following you and they won’t have a job it will be very hard for them to be happy. Remember that they won’t have a network of longtime friends and family to lean on as they would in your original country.&lt;/p&gt;

&lt;p&gt;If you want this experience to be a success and not a stressful adventure do your research upfront and be prepared. And even if you do your homework there will be lots of surprises.&lt;/p&gt;

&lt;p&gt;Lastly, when you have multiple offers to choose from you should think about a few additional things then you’d normally do. If you are on a temporary work visa is the employer willing to help you with getting the permanent one? You might be better off joining a bigger team to expand your professional network than a small startup with just a handful of people. Also, don’t underestimate the social aspect of the job—it might be the place where some of your work relationships transform into your first local friendships. Maybe in a diverse environment that supports immigration you will find people in similar situation and that will bring you together.&lt;/p&gt;

&lt;p&gt;Working in a different country is hard, stressful, but in the end, it is worth it. Good luck!&lt;/p&gt;
</content>
  </entry>
  <entry>
    <id>tag:chodounsky.net,2017-05-02:/2017/05/03/garbage-collection-in-c-sharp/</id>
    <title type="html">Garbage collection in C#</title>
    <published>2017-05-01T21:06:59Z</published>
    <updated>2017-05-01T21:06:59Z</updated>
    <link rel="alternate" href="https://chodounsky.net/2017/05/03/garbage-collection-in-c-sharp/"/>
    <content type="html">
&lt;p&gt;When you are programming, no matter the task on hand, you are manipulating some data. These are stored in basic types and objects and they live inside computer memory. Eventually, the memory fills up and you need to make more room for new data and discard the old one.&lt;/p&gt;

&lt;p&gt;You can do it either by hand, like C and C++ programmers (used to) do, or use a languages with a mechanism that does it for you. In C# we are fortunate enough to have a &lt;a href="https://en.wikipedia.org/wiki/Garbage_collection_(computer_science)"&gt;garbage collector&lt;/a&gt; that takes care of our memory.&lt;/p&gt;

&lt;h2 id="basic-concepts"&gt;Basic concepts&lt;/h2&gt;

&lt;p&gt;In short, garbage collector tries to find objects that are no longer in use by the program and delete them from memory.&lt;/p&gt;

&lt;p&gt;The first garbage collected language was &lt;a href="https://en.wikipedia.org/wiki/Lisp_(programming_language)"&gt;LISP&lt;/a&gt; written by &lt;a href="https://en.wikipedia.org/wiki/John_McCarthy_(computer_scientist)"&gt;John McCarthy&lt;/a&gt; – one of the founders of artificial intelligence – around 1959. So the concept has been around for a while.&lt;/p&gt;

&lt;p&gt;When you have a garbage collector in place you are making a trade off of safe memory allocations and programmer’s productivity for performance overhead. Garbage collected language will never be suitable for real-time critical applications like air traffic control, but you can get solid performance out of it – I’ve seen successful high frequency trading platforms written in C#.&lt;/p&gt;

&lt;p&gt;Garbage collection is not only responsible for cleaning the memory and compacting it, but also allocating new objects.&lt;/p&gt;

&lt;p&gt;.NET and CLR are making use of tracing garbage collector. That means that on every collection the collector figures out whether the object is used by tracing every object from stack roots, GC handles and static data.&lt;/p&gt;

&lt;p&gt;Every object that could be traced is marked as live and at the end of tracing the ones without the mark are removed (swept) from the memory and it gets compacted. This is called a simple &lt;strong&gt;mark and sweep algorithm&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src="https://upload.wikimedia.org/wikipedia/commons/4/4a/Animation_of_the_Naive_Mark_and_Sweep_Garbage_Collector_Algorithm.gif" alt="Naive mark and sweep in action (source Wikipedia)" /&gt;&lt;/p&gt;

&lt;p&gt;It gets a bit &lt;a href="https://en.wikipedia.org/wiki/Tracing_garbage_collection"&gt;more complex&lt;/a&gt; than that but this is enough for having a simple mental model of what’s happening under the hood.&lt;/p&gt;

&lt;p&gt;If the garbage collector halts the program when running we call this event &lt;strong&gt;stop the world&lt;/strong&gt;. That guarantees that no new objects are allocated during collection, but it also means that there will be a delay in our program. To minimise that disruption &lt;strong&gt;incremental&lt;/strong&gt; and &lt;strong&gt;concurrent&lt;/strong&gt; garbage collectors has been designed.&lt;/p&gt;

&lt;p&gt;Incremental collection makes the pauses shorter and works in small increments and concurrent doesn’t stop the program at all. For that you are paying with the overall longer collection time and the use of more CPU and memory resources than traditional stop the world.&lt;/p&gt;

&lt;h2 id="generational-collection"&gt;Generational collection&lt;/h2&gt;

&lt;p&gt;In 1984 David Ungar came up with a &lt;a href="http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.122.4295&amp;amp;rep=rep1&amp;amp;type=pdf"&gt;generational hypothesis&lt;/a&gt; that layed the foundations of GC that are in use these days.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Young objects die young. Therefore reclamation algorithm should not waste time on old objects.&lt;br /&gt;
Copying survivors is cheaper than scanning corpses.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This hypothesis gave birth of the generational garbage collectors – first used in Smalltalk and used in all modern platforms today – C# is not an exception.&lt;/p&gt;

&lt;p&gt;The memory is divided into several generations based on the age of objects. The collection happens in the youngest generation and the surviving objects are promoted to the generation above.&lt;/p&gt;

&lt;p&gt;In C# we have 3 generations:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Generation 0&lt;/strong&gt; is the youngest generation with short-lived objects in which the collection happens the most often. New objects are placed here with the exception of large objects that go straight to the Generation 2.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Generation 1&lt;/strong&gt; serves as a buffer between the short-lived and long-lived objects.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Generation 2&lt;/strong&gt; is the place for the long-lived objects and it gets collected less often.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When there is a collection over Generation 2 we call it &lt;em&gt;full garbage collection&lt;/em&gt; as it goes through all objects in managed memory.&lt;/p&gt;

&lt;p&gt;To keep the balance between generations most modern platforms are using a hybrid approach of generational cycles (minor cycle) and some variation of full mark and sweep (major cycle).&lt;/p&gt;

&lt;p&gt;The CLR automatically adjusts itself between not letting the used memory get too big and not letting the garbage collection take too much time by setting thresholds for new object allocation.&lt;/p&gt;

&lt;p&gt;The collection gets triggered when&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;memory is low,&lt;/li&gt;
  &lt;li&gt;threshold is exceeded or&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;GC.Collect&lt;/code&gt; is called manually.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When the collection is triggered every thread is suspended, so it can’t allocate new memory, and the GC thread goes into action.&lt;/p&gt;

&lt;p&gt;&lt;img src="https://i-msdn.sec.s-msft.com/dynimg/IC393001.jpeg" alt="When a thread triggers Garbage Collection (source MSDN)" /&gt;&lt;/p&gt;

&lt;p&gt;As you already know the collector uses static data to know whether the object is alive or not. As the static fields are kept in memory forever (until the AppDomain gets unloaded) this might lead to a common memory leak when it refers to a collection and you keep adding objects to the collection. The static field keeps the collection alive and all the objects inside alive as well. Be careful about that and possibly avoid the usage of static fields if you can.&lt;/p&gt;

&lt;h2 id="characteristics"&gt;Characteristics&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://blog.plan99.net/modern-garbage-collection-911ef4f8bd8e"&gt;Modern garbage collectors&lt;/a&gt; have different characteristics and as with many things in programming – different trade offs. Based on the application requirements they could be tuned towards less interruptions and better user experience or maybe you want to run a fast server-side application that scales.&lt;/p&gt;

&lt;p&gt;What characterizes a Garbage Collector?&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Program throughput&lt;/strong&gt;: CPU time spent collecting vs CPU time doing useful work.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;GC throughput&lt;/strong&gt;: amount of data the collector can clear per CPU time.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Heap overhead&lt;/strong&gt;: additional memory the collector produced during collection.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Pause times&lt;/strong&gt;: time needed for collection.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Pause frequency&lt;/strong&gt;: how often does garbage collection happen?&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Pause distribution&lt;/strong&gt;: short pauses vs long pauses, and how consistent the pauses are.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Allocation performance&lt;/strong&gt;: how much time does the new object allocation take? Is it predictable?&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Concurrency&lt;/strong&gt;: does the collector make use of multicore CPUs?&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Scaling&lt;/strong&gt;: can your GC handle larger heaps?&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Warmup time&lt;/strong&gt;: can a collector adjust to the characteristics of your application? How long does it take to adjust?&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id="configuration"&gt;Configuration&lt;/h2&gt;

&lt;p&gt;You can influence the type and behavior of your application by setting garbage collection to a different type.&lt;/p&gt;

&lt;p&gt;There are two major types – workstation and server. They could be configured by setting &lt;code&gt;&amp;lt;gcServer enabled="true|false" /&amp;gt;&lt;/code&gt; element in your application configuration.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;configuration&amp;gt;
   &amp;lt;runtime&amp;gt;
       &amp;lt;gcServer enabled="true"/&amp;gt;
   &amp;lt;/runtime&amp;gt;
&amp;lt;/configuration&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The workstation setting is tuned for client-side applications. Low latency is preferred as you don’t want your forms in WPF application become unresponsive during a long pause caused by garbage collection. In this mode it favours user experience and less CPU usage.&lt;/p&gt;

&lt;p&gt;On the other hand, the server configuration is designed for high throughput and scalability of server-side applications and it uses multiple dedicated threads for garbage collection with the highest priority. It is faster than workstation but that also comes with more CPU and memory usage. This configuration assumes that no other applications are running on the server and prioritise the GC threads accordingly. Also, it splits the managed heap into sections based on the number of CPUs. There is one special GC thread per CPU that takes care of the collection of its section. You can run this mode only on a computer with multiple CPUs.&lt;/p&gt;

&lt;p&gt;By default, the workstation GC mode is active.&lt;/p&gt;

&lt;p&gt;Another option you can choose is to use concurrent collection by using the &lt;code&gt;&amp;lt;gcConcurrent enabled="true|false" /&amp;gt;&lt;/code&gt;. It will give you more responsive application with less pause frequency and time.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;configuration&amp;gt;
   &amp;lt;runtime&amp;gt;
       &amp;lt;gcConcurrent enabled="false"/&amp;gt;
   &amp;lt;/runtime&amp;gt;
&amp;lt;/configuration&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In concurrent mode, there will be an extra background thread that marks the objects alive when your application is executing its code. When it comes to collection, it will be faster as the set of dead objects has already been built.&lt;/p&gt;

&lt;p&gt;The concurrency only affects the generation 2. Generation 0 and 1 will always be non-concurrent as they both finish fast and are not worth the extra overhead. When concurrent option is set, a dedicated thread will be used for collection.&lt;/p&gt;

&lt;p&gt;&lt;img src="https://i-msdn.sec.s-msft.com/dynimg/IC393003.jpeg" alt="A dedicated thread is used for collection in concurrent mode (source MSDN)" /&gt;&lt;/p&gt;

&lt;p&gt;To improve performance of several processes running side by side, you can try using workstation garbage collection with the concurrent collection disabled. This will lead to less context switching and therefore better performance.&lt;/p&gt;

&lt;h2 id="performance"&gt;Performance&lt;/h2&gt;

&lt;p&gt;The memory is divided into small object heap and large object heap. Large objects are the ones above 85 000 bytes and they go straight into the Generation 2.&lt;/p&gt;

&lt;p&gt;In general, fewer objects on the managed heap is less work for garbage collector. That is applied especially to the large object heap that gets collected less often.&lt;/p&gt;

&lt;p&gt;If you feel like GC causes you troubles there are various tools that you can use to &lt;a href="https://msdn.microsoft.com/en-us/library/ee851764(v=vs.110).aspx#performance_analysis_tools"&gt;debug it&lt;/a&gt; – memory performance counter, WinDbg or tracing ETW events.&lt;/p&gt;

&lt;p&gt;Triggering collection manually with &lt;code&gt;GC.Collect&lt;/code&gt; is usually more counterproductive than beneficial unless you really know what you are doing. It might help in certain situations when you want to release a lot of memory at once (e.g. a large dialog is closed and won’t be used again) – but unless you have diagnosed a memory problem, don’t go there.&lt;/p&gt;

&lt;p&gt;If you are calling &lt;code&gt;GC.Collect&lt;/code&gt; manually too frequently you will certainly see a decrease of performance in your application.&lt;/p&gt;

&lt;p&gt;When you get into situation where the latency of your application is critical – like in the middle of the high frequency trading decision loop – you can set a &lt;em&gt;&lt;a href="https://msdn.microsoft.com/en-us/library/bb384202(v=vs.110).aspx"&gt;low latency mode&lt;/a&gt;&lt;/em&gt;. This will put the GC into a low intrusive mode when it will become very conservative.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;GCLatencyMode oldMode = GCSettings.LatencyMode;
System.Runtime.CompilerServices.RuntimeHelpers.PrepareConstrainedRegions();
try
{
    GCSettings.LatencyMode = GCLatencyMode.LowLatency;
    ...
}
finally
{
    GCSettings.LatencyMode = oldMode;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The collection of Generation 2 will be paused for the time in low latency mode. That leads to shorter and less frequent pause times and therefore decreased program latency. But that comes with the price that you might run out of memory if you are not careful. The best guideline is to keep those low latency sections as short as possible and don’t allocate too many new objects, especially on the large heap. In this case you might want to call &lt;code&gt;GC.Collect&lt;/code&gt; where appropriate to force the Generation 2 collection.&lt;/p&gt;

&lt;p&gt;Don’t forget that the latency mode is process wide, so if you are running multiple threads it will be applied to all of them.&lt;/p&gt;

&lt;h2 id="managed-and-unmanaged-resources"&gt;Managed and unmanaged resources&lt;/h2&gt;

&lt;p&gt;In &lt;a href="https://en.wikipedia.org/wiki/Common_Language_Runtime"&gt;&lt;acronym title="Common Language Runtime"&gt;CLR&lt;/acronym&gt;&lt;/a&gt; all the code that is written is managed and it will be garbage collected. C# gets compiled into &lt;acronym title="Common Intermediate Language"&gt;CIL&lt;/acronym&gt; and runs on top of CLR so all your C# code will be garbage collected.&lt;/p&gt;

&lt;p&gt;That sounds easy enough until you need to use unmanaged resources.&lt;/p&gt;

&lt;p&gt;And you will use them on almost daily basis as these are database connections, COM interops, network and file streams and many others. Unmanaged resources are not garbage collected and you need to free them from your memory by hand.&lt;/p&gt;

&lt;p&gt;If you write a type that uses an unamanged resource you should&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;implement the &lt;a href="https://msdn.microsoft.com/en-us/library/b1yfkh5e(v=vs.110).aspx"&gt;dispose pattern&lt;/a&gt; and&lt;/li&gt;
  &lt;li&gt;provide a mechanism to free the resource in case consumer forgets to call Dispose.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The basic implementation of a dispose pattern with the use of SafeHandle could look like&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;public class DisposableResourceHolder : IDisposable
{
    private SafeHandle resource;

    public DisposableResourceHolder()
    {
        this.resource = ...
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (disposing)
        {
            if (resource != null) resource.Dispose();
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To free the resource you can use &lt;code&gt;Object.Finalize&lt;/code&gt; or &lt;code&gt;SafeHandles&lt;/code&gt;. For more details check out &lt;a href="https://msdn.microsoft.com/en-us/library/498928w2(v=vs.110).aspx"&gt;Cleaning up Unmanaged Resources&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As a consumer of a type with unmanaged resource always use the &lt;code&gt;using&lt;/code&gt; pattern.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;using (var s = new StreamReader("file.txt"))
{
  ...
  s.Close();
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;How can you tell the object needs to be disposed? It implements the &lt;code&gt;IDisposable&lt;/code&gt; interface. Some static analysis tools can help you notice the cases where you might have forgotten to dispose your objects.&lt;/p&gt;

&lt;h2 id="what-about-other-languages"&gt;What about other languages?&lt;/h2&gt;

&lt;p&gt;The first versions of &lt;strong&gt;Ruby&lt;/strong&gt; used a simple mark and sweep technique which isn’t the best performer but it was simple for the authors of C-extensions to write native extensions. That simplicity was the key to Ruby’s growth in the beginning and took it where it is these days. Generational collection was introduced in Ruby 2.1 (current version is 2.4) to improve the throughput of programs – quite late in terms of language maturity. After that Ruby 2.2 introduced &lt;a href="https://blog.heroku.com/incremental-gc"&gt;incremental marking&lt;/a&gt; which addresses long pause times by running the GC in short increments.&lt;/p&gt;

&lt;p&gt;&lt;img src="https://heroku-blog-files.s3.amazonaws.com/posts/1488278432-file.copipa-temp-image%252520%2525282%252529.png%253Fdl%253D1" alt="Stop the world vs. incremental marking (source Heroku)" /&gt;&lt;/p&gt;

&lt;p&gt;Programmers in &lt;strong&gt;C++&lt;/strong&gt; don’t have any garbage collection and they need to do memory management by hand. There are techniques to make that easier – &lt;a href="http://www.boost.org/doc/libs/1_36_0/libs/smart_ptr/smart_ptr.htm"&gt;smart pointer&lt;/a&gt; are now part of the C++ 11 standard and are a tool that automatically deletes memory from the heap. Smart pointer can be implemented with &lt;a href="https://en.wikipedia.org/wiki/Reference_counting"&gt;reference counting&lt;/a&gt; that ensures that the object is deleted as soon as it is no longer needed – as opposed to tracing garbage collection when the unused object waits for the next cycle of collection.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Java&lt;/strong&gt; is very similar to C# and uses &lt;a href="http://www.oracle.com/webfolder/technetwork/tutorials/obe/java/gc01/index.html"&gt;tracing generational garbage collection&lt;/a&gt; – the heap is structured to a young generation (eden, S0 and S1), old generation and permanent generation. GC uses minor and major cycles to clean the generations and promote objects from one to the other. Both the collections of young and old generations are the “stop the world” event so all the threads are suspended until they finish. There are different types of collectors on JVM – serial, parallel, concurrent mark and sweep and its replacement G1 in Java 7.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Python&lt;/strong&gt; doesn’t use tracing garbage collection but a &lt;a href="https://www.quora.com/How-does-garbage-collection-in-Python-work"&gt;reference counting with periodical cycle detection&lt;/a&gt; to solve the case of two dead objects pointing to each other. But as opposed to classic reference counting it combines it with the generational approach and uses the reference count instead of the mark and sweep algorithm. It doesn’t deal with memory fragmentation but tries to avoid it with allocating objects on different pools of memory.&lt;/p&gt;

&lt;p&gt;In &lt;strong&gt;Javascript&lt;/strong&gt; there isn’t a unified approach to &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Memory_Management"&gt;garbage collection&lt;/a&gt;. It is in hands of browser vendors and they do it differently – Internet 6 and 7 used reference counting garbage collectors for DOM objects. From 2012 almost all modern browsers are shipped with tracing mark and sweep algorithms with some extra improvements – generations, incremental collection, concurrency and parallelism.&lt;/p&gt;

&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;C# and languages on top of CLR are garbage collected. They use generational garbage collection with 3 generations and an advanced tracing mark and sweep algorithm to figure out which objects are still alive.&lt;/p&gt;

&lt;p&gt;You can change the characteristics of the collector by changing to a server or workstation mode and setting up a concurrency mode.&lt;/p&gt;

&lt;p&gt;Most of the times triggering garbage collection manually is not a good idea unless you really know what you are doing. And in cases where latency is important you can use latency mode to increase your program throughput and eliminate pauses.&lt;/p&gt;

&lt;p&gt;Lastly, there are unmanaged resources like file streams, network, database connections that you need to take a special care of. Most of the times you’ll be implementing and using the IDisposable pattern so you don’t cause any memory leaks in your application.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;em&gt;If you liked this article you might enjoy &lt;a href="http://csharpdigest.net?utm_source=chodounsky.net&amp;amp;utm_medium=blog&amp;amp;utm_campaign=garbage+collection"&gt;C# Digest&lt;/a&gt; newsletter with 5 links from the .NET community that I put together every week.&lt;/em&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id="resources"&gt;Resources&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="https://msdn.microsoft.com/en-us/library/0xy59wtx(v=vs.110).aspx"&gt;Garbage collection on MSDN&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Garbage_collection_(computer_science)"&gt;Garbage collection on Wikipedia&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Tracing_garbage_collection"&gt;Tracing garbage collection&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="https://blog.plan99.net/modern-garbage-collection-911ef4f8bd8e#.y5kgl8qvc"&gt;Mike Hearn on Modern garbage collection&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.122.4295&amp;amp;rep=rep1&amp;amp;type=pdf"&gt;David Ungar on Generation Scavenging&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id="comments"&gt;Comments&lt;/h2&gt;

&lt;p&gt;Justin Self: Nice Post. Minor note: Large objects (over 85,000 bytes) get collected during a Gen 2 collection but are not really part of the Gen 2. They are part of the Large Object Heap.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <id>tag:chodounsky.net,2017-01-20:/2017/01/20/automate-your-macos-development-machine-setup/</id>
    <title type="html">Automate your macOS development machine setup</title>
    <published>2017-01-19T20:30:21Z</published>
    <updated>2017-01-19T20:30:21Z</updated>
    <link rel="alternate" href="https://chodounsky.net/2017/01/20/automate-your-macos-development-machine-setup/"/>
    <content type="html">
&lt;p&gt;My laptop was running a bit slow and there was an OS upgrade that I’ve been postponing for quite some time. So, on one rainy Friday afternoon, I decided to get my hands dirty and do a clean install of macOS Sierra. And why not automate it so I don’t have to think about it next time?&lt;/p&gt;

&lt;p&gt;One of the benefits is that my team mates can use chunks of the configuration that are relevant to our work and use it for themselves.&lt;/p&gt;

&lt;p&gt;Let’s have a look at the tools that we will use.&lt;/p&gt;

&lt;h2 id="dotfiles"&gt;Dotfiles&lt;/h2&gt;

&lt;p&gt;It’s a bunch of &lt;a href="https://dotfiles.github.io/"&gt;configuration files&lt;/a&gt; and directories that are in your home directory. For example vim uses &lt;code&gt;.vimrc&lt;/code&gt; or a git uses &lt;code&gt;.gitconfig&lt;/code&gt;. You want to bring them with you from your old machine.&lt;/p&gt;

&lt;p&gt;Some people store them as a git repository but I just chuck them on Dropbox. Make sure that you are &lt;strong&gt;not revealing any sensitive files&lt;/strong&gt; like your private SSH keys or infrastructure setup.&lt;/p&gt;

&lt;p&gt;When you setup your new machine you create symlinks to the ones that you like to use. It can get &lt;a href="http://codyreichert.github.io/blog/2015/07/07/managing-your-dotfiles-with-gnu-stow/"&gt;pretty fancy&lt;/a&gt; or you can keep it simple with &lt;code&gt;ln -s&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id="brew"&gt;Brew&lt;/h2&gt;

&lt;p&gt;&lt;a href="http://brew.sh/"&gt;Homebrew&lt;/a&gt; is a package manager for macOS. And you can create your own &lt;a href="https://github.com/Homebrew/homebrew-bundle"&gt;bundles&lt;/a&gt; to set up whole environment.&lt;/p&gt;

&lt;p&gt;Apart from that there is an extension for installing desktop applications — &lt;a href="https://caskroom.github.io/"&gt;cask&lt;/a&gt;. You can search for the recipes with the following commands.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;brew search vim
brew cask search google-chrome
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;When you find the mix of applications you bundle them together into a &lt;code&gt;Brewfile&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;cask_args appdir: '/Applications'

tap 'homebrew/bundle'
tap 'caskroom/cask'
tap 'homebrew/services'

brew 'vim'
brew 'tmux'
brew 'git'
brew 'ruby-build'
brew 'rbenv'

cask 'google-chrome'
cask 'vlc'
cask 'dropbox'
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I like to keep my &lt;code&gt;Brewfile&lt;/code&gt; in my Dropbox folder with the rest of the dotfiles. Now with the file you can run &lt;code&gt;brew bundle&lt;/code&gt; and it installs everything for you. Easy.&lt;/p&gt;

&lt;h2 id="everything-together"&gt;Everything together&lt;/h2&gt;

&lt;p&gt;We have our configuration with dotfiles and we can install all the necessary applications with brew and cask. How about putting everything into one script that we can run and leave the computer do its thing?&lt;/p&gt;

&lt;p&gt;I created an &lt;code&gt;install.sh&lt;/code&gt; file that I keep with the rest of the files.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;#!/bin/bash

xcode-select --install

# dotfiles
ln -s ~/Dropbox/dotfiles/.bash_profile ~/.bash_profile
ln -s ~/Dropbox/dotfiles/.gitconfig ~/.gitconfig
ln -s ~/Dropbox/dotfiles/.tmux.conf ~/.tmux.conf
ln -s ~/Dropbox/dotfiles/.vimrc ~/.vimrc

# brew stuff
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
cd ~/Dropbox/dotfiles
brew bundle
cd ~

git clone https://github.com/VundleVim/Vundle.vim.git ~/.vim/bundle/Vundle.vim
git clone https://github.com/tmux-plugins/tpm ~/.tmux/plugins/tpm

# ruby
rbenv install 2.2.5
rbenv global 2.2.5

gem install bundler

echo "******************** Done ********************"
echo "Don't forget to configure SSH properly with key and config"
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Firstly, it installs XCode command line tools — if you need to install the full version you might need to do that through AppStore. I haven’t found any way around that yet.&lt;/p&gt;

&lt;p&gt;After installing XCode the script takes care of the dotfiles and links them into your home directory. And when those are sorted it starts the brew magic.&lt;/p&gt;

&lt;p&gt;There is a few custom commands afterward — installing plugin managers for tmux and vim and installing ruby with rbenv. You can also use terminal to customize macOS behaviour or do other things that you would normally do by hand.&lt;/p&gt;

&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;And with that a fresh OS install is not a pain anymore. After finishing the installation and encrypting your disk you copy your backed up Dropbox folder into your home directory, run&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;. ~/Dropbox/dotfiles/install.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and you can go for a surf, come back and have your computer ready. Unless you need to compile Qt with Webkit. Then you might go for two surf sessions at least.&lt;/p&gt;

&lt;h2 id="comments"&gt;Comments&lt;/h2&gt;

&lt;p&gt;Victor Maslov aka Nakilon: My relevant &lt;a href="https://gist.github.com/Nakilon/7db114214d9019824543684ed4074891"&gt;gist&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Gabriel Filipe Gizotti: &lt;a href="https://github.com/freshshell/fresh"&gt;fresh&lt;/a&gt; helped me a lot&lt;/p&gt;

&lt;p&gt;ege: Brewfile also let you add apps from Mac App Store thanks to github.com/mas-cli/mas. But doesn’t work with 2FA-enabled account yet. I hope devs find a solution.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;brew 'mas' / brew install mas
mas '1Password'
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Phil Pirozhkov: I find it really hard maintaining the up to date list of formulae by hand and came up with the following:&lt;/p&gt;

&lt;p&gt;Show installed formulae that are not dependencies of another installed formula:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;brew leaves &amp;gt;! .formulae
brew cask list &amp;gt;! .casks
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Install:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;brew install $(&amp;lt; .formulae )
brew tap caskroom/cask
brew cask
brew cask install $(&amp;lt; .casks)
&lt;/code&gt;&lt;/pre&gt;
</content>
  </entry>
  <entry>
    <id>tag:chodounsky.net,2017-01-12:/2017/01/12/reading-diary-of-2016/</id>
    <title type="html">Reading Diary of 2016</title>
    <published>2017-01-12T06:18:39Z</published>
    <updated>2017-01-12T06:18:39Z</updated>
    <link rel="alternate" href="https://chodounsky.net/2017/01/12/reading-diary-of-2016/"/>
    <content type="html">
&lt;p&gt;I enjoy going through other’s reading lists and find inspiration what to read next. Here is mine from 2016.&lt;/p&gt;

&lt;h2 id="somehow-computer-related"&gt;Somehow computer related&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/14514115-team-geek"&gt;Team Geek&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A book about collaborating in a team by two former Googlers is a great read for everyone — not just team leaders. It sums up basic principles of being a valuable team member and gives you some guidance in challenging social situation. In the end it’s all about communication.&lt;/p&gt;

&lt;p&gt;It is not a revolutionary book and you might say it’s a common sense, but it’s a quick read and a well-written one.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/67825.Peopleware"&gt;Peopleware&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On the similar notion as Team Geek this book is about software development teams and projects. It discusses working environment (strongly discourages open offices), distractions (do you have your &lt;a href="/2015/11/12/focus/"&gt;slack notifications on&lt;/a&gt;?), hiring and turnover (turnover is expensive and always let the team have say in your hiring) and dives deeply into creating jelled teams.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/6399113-the-passionate-programmer"&gt;The Passionate Programmer&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A book about programmer’s career — with lot’s of different aspects discussed. How to be marketable. You should treat your career like a product. Learn the domain and understand the business and always know how you are making money for the employer.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/4268826-growing-object-oriented-software-guided-by-tests"&gt;Growing Object Oriented Software Guided by Tests&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Steve Freeman and Nat Pryce take a small trading platform and goes through a journey of adding requirements in a TDD manner. One takeaway I liked from the book is to setup a fully functioning skeleton before diving too deep into functionality. Otherwise the style was not for me and it took me ages to finish it.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/28259132-chaos-monkeys"&gt;Chaos Monkey&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A true story from Silicon Valley that gives you some insight into VC funding and all those accelerators. A startup company goes through &lt;a href="https://www.ycombinator.com/"&gt;Y Combinator&lt;/a&gt; and the team gets acquired by partially by Twitter and Facebook. The author stays in Facebook during it’s IPO phase and among other things shares what he earned. It’s a good view behind the curtains of startup industry and you can decide if it’s for you or not.&lt;/p&gt;

&lt;h2 id="kind-of-educational"&gt;Kind of educational&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/6732019-rework"&gt;Rework&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Jason Fried and David Heinemeier Hansson don’t waste words and in this short book provide a guide on how to run a business. As a few other books it seems mostly as a common sense. It advices against rigid MBA practices and suggests to always have your customer at the first place.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/2064279.Economic_Facts_and_Fallacies"&gt;Economic Facts and Fallacies&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A second look at facts that seems to be obvious and well-accepted such as the rate of crimes in poor neighbourhoods, income discrimination of women, academia or third-world countries. The views are backed by an extensive research.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/16235130-cockpit-confidential"&gt;Cockpit Confidential&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A brief look under the hood of airplanes, airlines and everything related to flying. Did you know that a rough landing is not a sign of a bad skill? Or what is the difference between captain and first officer? What are the career advances for pilots?&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/38210.The_Art_of_Happiness"&gt;The Art of Happiness&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A dialogue between Howard C. Cutler and Dalai Lama about western unhappiness. It is kind of meh. There is another volume called The Art of Happiness at work — I wonder what his holiness who never set a foot into the corporate environment has to advice.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/181727.How_to_Make_People_Like_You_in_90_Seconds_or_Less"&gt;How to Make People Like You in 90 Seconds or Less&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One of those books that focuses on a few tricks to improve your perception by others to set up a good rapport. It is an ok read (and a short one) with a few things that is nice to keep in mind when meeting people.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/87530.Confessions_of_a_Wall_Street_Analyst"&gt;Confession of a Wall Street Analyst&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A personal journey of Daniel Reingold — one of the top telecommunication Wall Street analysts — through the worst crysis in the industry. He openly discusses insider trading, CEOs fudging their numbers and other illegal activities on Wall Street.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/1842.Guns_Germs_and_Steel"&gt;Guns, Germs and Steel&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is one of the best books I read last year. It answers the question why Euroasian civilisation dominated the world. It starts from its location and climate, continues through crops and animals that are available for domestication and compares it to other continents. From that it moves to the development of germs in more dense population and how it played its role in wiping out a few entire civilisations.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/18693910-barbarian-days"&gt;Barbarian Days&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;William Finnegan talks about seeking perfect waves from 1960s when surfing wasn’t such mainstream sport as it is now. He starts in Hawaii, goes through Indonesia, Tonga, Samoa and Australia. For a surfer it is a beautiful book.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/12251838-the-ultimate-hiker-s-gear-guide"&gt;The Ultimate Hiker’s Gear Guide&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Andrew Skurka — a long-distance hiker — talks about hiking gear. A few useful advices that might save you some wasted money.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/11797365-escape-from-camp-14"&gt;Escape from Camp 14&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A chilling story of North Korean concentration camps that is told by a guy who was born there and escaped. In the end it turns out that there might be some troubles with his credibility but still — it is a reminder of dangers (or the fortunate lack of them) in different societies.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/6452796-drive"&gt;Drive&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A book on motivation and its three stages: first — food, shelter, reproduction, second — rewards and punishments and third — autonomy, mastery and purpose. Therefore from a certain point money is not a good motivator anymore. Also, coined the terms extrinsic (you get rewarded for doing something) and intrinsic (you want to do something) motivation.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/4865.How_to_Win_Friends_and_Influence_People"&gt;How to Win Friends and Influence People&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Apparently this is a classic, but it falls down into the bucket of common sense advices for me.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/1099422.The_Story_of_Tea"&gt;The Story of Tea&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This book has everything that you need to know about tea. It starts with the history of tea and goes nicely into the relationship of Western civilisation and tea culture. It also gives you the answer why English drink tea with milk.&lt;/p&gt;

&lt;p&gt;It continues with the different teas description and goes into deep details of their manufacturing. After that it goes into the tea drinking culture and health benefits.&lt;/p&gt;

&lt;p&gt;Even if you are not a tea enthusiast you will find a interesting pieces of knowledge in the cultural, geographical and historical chapters. And skip the tea specific ones.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/7650412-the-tea-enthusiast-s-handbook"&gt;The Tea Enthusiast’s Handbook&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As opposed to the Story of Tea, this one is a bit more practical and is focused on buying, drinking and steeping the different types of teas.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/17689431-the-art-of-empathy"&gt;The Art of Empathy&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Actually I haven’t finished this book. I couldn’t get over the author’s style and the message from first 50 pages was not worth it to push through it.&lt;/p&gt;

&lt;h2 id="fiction"&gt;Fiction&lt;/h2&gt;

&lt;p&gt;And I read some fiction too.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/234225.Dune"&gt;Dune&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/4407.American_Gods"&gt;American Gods&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/7624.Lord_of_the_Flies"&gt;Lord of Flies&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/5759.Fight_Club"&gt;Fight Club&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/826845.The_Chrysalids"&gt;The Chrysalids&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/22328.Neuromancer"&gt;Neuromancer&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I would recommend Dune, American Gods and Lords of Flies — I loved these books. Fight Club seems slightly overrated and Chrysalids and Neuromancer are not my cup of tea.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <id>tag:chodounsky.net,2016-12-23:/2016/12/23/progressive-web-applications/</id>
    <title type="html">Progressive Web Applications</title>
    <published>2016-12-22T19:52:09Z</published>
    <updated>2016-12-22T19:52:09Z</updated>
    <link rel="alternate" href="https://chodounsky.net/2016/12/23/progressive-web-applications/"/>
    <content type="html">
&lt;p&gt;Every time there is a chance to build a mobile application with javascript, web developers are like &lt;em&gt;“yeah, this is the way; the future of building mobile apps”&lt;/em&gt; and jump on the bandwagon of the saucy java intent avoidance.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;[WHATEVER JS FRAMEWORK] will change the way we build mobile apps
&lt;small&gt;&lt;cite&gt;Every web developer ever&lt;/cite&gt;&lt;/small&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We’ve seen it with &lt;a href="http://jquerymobile.com/"&gt;jQuery Mobile&lt;/a&gt;, &lt;a href="https://cordova.apache.org/"&gt;Apache Cordova&lt;/a&gt; (&lt;a href="http://phonegap.com/"&gt;Phonegap&lt;/a&gt;), &lt;a href="http://ionicframework.com/"&gt;Ionic&lt;/a&gt;, &lt;a href="https://www.nativescript.org/"&gt;NativeScript&lt;/a&gt; and of course &lt;a href="http://www.reactnative.com/"&gt;React Native&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;How do &lt;a href="https://developers.google.com/web/progressive-web-apps/"&gt;progressive web apps&lt;/a&gt; fit into the picture?&lt;/p&gt;

&lt;h2 id="what-is-it"&gt;What is it?&lt;/h2&gt;

&lt;p&gt;The fancy term was coined by Google where this technology originated. It sounds complex but progressive web apps are just web pages that use modern browser features – &lt;a href="https://developer.mozilla.org/en-US/docs/Web/Manifest"&gt;Web App Manifest&lt;/a&gt;, &lt;a href="https://developer.mozilla.org/en/docs/Web/API/Service_Worker_API"&gt;Service Workers&lt;/a&gt; and HTTPS. They are usually complemented with &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Cache"&gt;Cache Storage&lt;/a&gt; and &lt;a href="https://developer.mozilla.org/en/docs/Web/API/IndexedDB_API"&gt;IndexedDB&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;They are linked with the browser and those technologies are currently experimental. At the moment you are mostly limited on Android platform as Safari doesn’t have a full support of service workers. You can check out the readiness of it at &lt;a href="https://jakearchibald.github.io/isserviceworkerready/"&gt;Is ServiceWorker Ready?&lt;/a&gt; site.&lt;/p&gt;

&lt;p&gt;The web manifest is a simple file with a few information about your app – icon, name, description and others. When you add the site to your phone home screen this is the file where the icon comes from.&lt;/p&gt;

&lt;p&gt;Service worker sits in between the browser and the server and is able to manage the network communication, work with the cache API and manage request when offline. It only works over HTTPS protocol.&lt;/p&gt;

&lt;p&gt;Progressive web applications can mimic the material design of Android applications, but in the end you are in charge of your HTML and CSS. For that you could use &lt;a href="https://www.polymer-project.org/1.0/docs/devguide/feature-overview"&gt;Polymer&lt;/a&gt; or one of the native look emulating javascript libraries like &lt;a href="http://ionicframework.com/"&gt;Ionic&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id="why-would-you-want-to-use-it"&gt;Why would you want to use it?&lt;/h2&gt;

&lt;p&gt;Firstly, they won’t replace a mobile app. Or a website. They are a complement to them and are not faster to build or easier to maintain. They solve a different problem.&lt;/p&gt;

&lt;p&gt;They help to &lt;strong&gt;overcome the barrier to install and launch apps&lt;/strong&gt;. No need to go to the shop, search for the app, click install, agree on permissions and launch. You have them immediately in the browser and user can &lt;em&gt;bookmark&lt;/em&gt; them to the home screen.&lt;/p&gt;

&lt;p&gt;According to one of the Google presentations each step involved in installing an app has at least 20% drop out rate – meaning that with each click you lose 20% users. This is a huge! And for certain types of business like big e-shops, airlines or news it should be the reason to explore this area.&lt;/p&gt;

&lt;p&gt;When using your cellphone your connection will be flaky and slow even if you don’t live in &lt;a href="http://www.nzherald.co.nz/nz/news/article.cfm?c_id=1&amp;amp;objectid=10786737"&gt;New Zealand&lt;/a&gt;. Removing that from the equation leads to &lt;strong&gt;better conversions and more sales on flaky networks&lt;/strong&gt;. Users won’t leave your website because they’ve been staring at a blank screen for the past 3 minutes.&lt;/p&gt;

&lt;p&gt;Apart from improving the speed of the app you also have the ability to &lt;strong&gt;work purely offline&lt;/strong&gt;. That might be convenient for example for an airline app to show checked tickets.&lt;/p&gt;

&lt;p&gt;Prosper Otemuyiwa did a nice &lt;a href="https://auth0.com/blog/introduction-to-progressive-apps-part-one/"&gt;write up&lt;/a&gt; of existing use cases and how they improved the business.&lt;/p&gt;

&lt;h2 id="where-to-learn-more"&gt;Where to learn more?&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="https://www.udacity.com/course/offline-web-applications--ud899"&gt;Offline Web Applications&lt;/a&gt; on Udacity by Google  – a short but useful introduction into Service Workers, Cache Storage and IndexedDB by Michael Wales and Jake Archibald.&lt;/li&gt;
  &lt;li&gt;Rossta’s &lt;a href="https://rossta.net/blog/make-your-rails-app-a-progressive-web-app.html"&gt;Progressive Web Application on Rails&lt;/a&gt; guide with a few additional resources to follow.&lt;/li&gt;
  &lt;li&gt;&lt;a href="https://github.com/rossta/serviceworker-rails"&gt;serviceworker-rails&lt;/a&gt; is a gem from Rossta that provides the basic pieces for your offline app and integrates it into Rails asset pipeline.&lt;/li&gt;
  &lt;li&gt;&lt;a href="https://jakearchibald.com/2014/offline-cookbook/"&gt;The Offline Cookbook&lt;/a&gt; by Jake Archibald shows different architecture patterns and approaches with their translation to Javascript.&lt;/li&gt;
  &lt;li&gt;Mozilla’s &lt;a href="https://serviceworke.rs/"&gt;Service Worker Cookbook&lt;/a&gt; is a great collection of patterns and examples on how to solve common problems like deferring POST requests while offline.&lt;/li&gt;
  &lt;li&gt;&lt;a href="https://github.com/jakearchibald/idb"&gt;IndexedDB Promised&lt;/a&gt; wraps IndexedDB interface into a promise based architecture – nice to have if you want to interact with it. It keeps the interfaces same with the original so you can still use documentation for original &lt;a href="https://developer.mozilla.org/en/docs/Web/API/IndexedDB_API"&gt;IndexedDB API&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;a href="https://youtu.be/qDJAz3IIq18"&gt;Instant-loading Offline-first&lt;/a&gt; from Progressive Web App Summit 2016 where Jake Archibald’s demonstrates the capabilities of Progressive Web Apps, converts an existing online application into a fully functional offline web app and compares the results.&lt;/li&gt;
  &lt;li&gt;&lt;a href="https://youtu.be/U52dD0tegsA"&gt;Building Progressive Web Apps Today&lt;/a&gt; from Chrome Dev Summit 2016 where Thao Tran shares some success stories from customers like Flipkart and Alibaba and gives some guidance on how to make the money rain.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Building a progressive web application requires the same amount of effort as creating a mobile app. You can’t easily convert your website into an app without major changes to the architecture and most of the early adopters solves it by creating and serving a mobile version different to the desktop one.&lt;/p&gt;

&lt;p&gt;You shouldn’t think of it as a replacement for a mobile app, but as a complement to your website that will help with customer engagement, conversions on flaky networks and remove the barrier to install on the phone.&lt;/p&gt;

&lt;p&gt;It is not a faster and cheaper way to develop mobile apps but it provides another way to support your business and generate more money.&lt;/p&gt;

&lt;h2 id="comments"&gt;Comments&lt;/h2&gt;

&lt;p&gt;Sintaxi: As one of the inventors of Cordova/PhoneGap allow me to set the record straight. We never intended for anyone to think PG was anything more than a temporary measure. Hence the mantra: “the ultimate purpose of PhoneGap is to cease to exist” –Brian LeRoux.&lt;/p&gt;

&lt;p&gt;If anything this article should be acknowledging the role Cordova/PG served as a conceptual if not functional proof of concept for progressive web apps.&lt;/p&gt;

&lt;p&gt;Jakub: You guys did a hell of a good job with Phonegap though. I think it is a wonderful piece of technology and it still has a great number of use cases.&lt;/p&gt;

&lt;p&gt;People like to think about these as silver bullets to mobile development which I dont think exists.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <id>tag:chodounsky.net,2016-12-19:/2016/12/19/what-articles-c-number-developers-liked-in-2016/</id>
    <title type="html">What articles C# developers liked in 2016</title>
    <published>2016-12-18T21:20:34Z</published>
    <updated>2016-12-18T21:20:34Z</updated>
    <link rel="alternate" href="https://chodounsky.net/2016/12/19/what-articles-c-number-developers-liked-in-2016/"/>
    <content type="html">
&lt;p&gt;One of the benefits of running &lt;strong&gt;&lt;a href="http://csharpdigest.net/"&gt;C# Digest&lt;/a&gt;&lt;/strong&gt; – a weekly newsletter from .NET community – is to see which articles were the most popular in the C# space and what the programmers liked to read in the last year.&lt;/p&gt;

&lt;p&gt;This year I shared over 486 articles through the weekly emails and I bet you are wondering which ones were the top 5.&lt;/p&gt;

&lt;h4 id="common-multithreading-mistakes-in-chttpsxenoprimatewordpresscom20160703common-multithreading-mistakes-in-c-part-i"&gt;&lt;a href="https://xenoprimate.wordpress.com/2016/07/03/common-multithreading-mistakes-in-c-part-i/"&gt;Common Multithreading Mistakes in C#&lt;/a&gt;&lt;/h4&gt;

&lt;p&gt;Multithreading, concurrency and parallel programming are big topics in the .NET community and sometimes even seasoned developers don’t get them right. In this series of posts &lt;a href="https://twitter.com/Xenoprimate"&gt;Ben Bowen&lt;/a&gt; explains common mistakes and how to avoid them. We are eager to see part 3 about unsafe assumptions.&lt;/p&gt;

&lt;h4 id="net-on-linux--bye-windows-10httppiotrgankiewiczcom20161017net-on-linux-bye-windows-10"&gt;&lt;a href="http://piotrgankiewicz.com/2016/10/17/net-on-linux-bye-windows-10/"&gt;.NET on Linux – bye, Windows 10&lt;/a&gt;&lt;/h4&gt;

&lt;p&gt;One of the big things of 2016 was .NET Core and Microsoft officially supporting OS X and Linux platforms. &lt;a href="https://twitter.com/spetzu"&gt;Piotr Gankiewicz&lt;/a&gt; shared his experience of setting up and running a competitive development environment on Linux Mint and lots of people liked it. I’m glad to see .NET on other platforms as the power of some UNIX tools is enormous and programmers can only benefit from this mutual symbiosis.&lt;/p&gt;

&lt;h4 id="visual-studio-2015-extensions-you-might-find-usefulhttpwwwhamidmosallacom20160912-visual-studio-2015-extensions-you-might-find-usefulhtml"&gt;&lt;a href="http://www.hamidmosalla.com/2016/09/12-Visual-Studio-2015-Extensions-You-Might-Find-Useful.html"&gt;12 Visual Studio 2015 extensions you might find useful&lt;/a&gt;&lt;/h4&gt;

&lt;p&gt;Productivity tips and improving your development experience in Visual Studio is a popular topic. It seems that every .NET developer loves to be more efficient and deliver better quality code and use the best tools possible. In this article &lt;a href="https://twitter.com/Xellarix"&gt;Hamid Mosalla&lt;/a&gt; shared his 12 favorite extensions for Visual Studio. Check them out!&lt;/p&gt;

&lt;h4 id="whats-some-c-bad-practices-that-you-know-and-whats-the-workaroundhttpswwwredditcomrcsharpcomments5dpjk0whatssomecbadpracticesthatyouknowand"&gt;&lt;a href="https://www.reddit.com/r/csharp/comments/5dpjk0/whats_some_c_bad_practices_that_you_know_and/"&gt;What’s some C# bad practices that you know and what’s the workaround?&lt;/a&gt;&lt;/h4&gt;

&lt;p&gt;Number two is actually not an article but a reddit discussion about C# bad practices. Some might argue that it doesn’t belong to a newsletter, but reading these battlefield proven stories might actually improve the way how you think about your design as opposed to read another article about &lt;em&gt;Javascript fatigue&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;And it only proves that C# developers care about their code and want to avoid common pitfalls. Good on us!&lt;/p&gt;

&lt;h4 id="performance-considerations-for-ef-4-5-and-6httpsmsdnmicrosoftcomen-usdatahh949853aspx"&gt;&lt;a href="https://msdn.microsoft.com/en-us/data/hh949853.aspx"&gt;Performance Considerations for EF 4, 5, and 6&lt;/a&gt;&lt;/h4&gt;

&lt;p&gt;Performance is a hot topic in .NET world. You can write very efficient and fast applications in .NET with the speed of development a C++ developers could only dream of.&lt;/p&gt;

&lt;p&gt;The most popular article of this year is this deep dive into Entity Framework performance and database techniques by &lt;a href="https://twitter.com/DavidObando"&gt;David Obando&lt;/a&gt; and &lt;a href="https://www.linkedin.com/in/eric-dettinger-321a1a8b"&gt;Eric Dettinger&lt;/a&gt;. Great read guys, thank you — I bet you saved a few CPU cycles and disk spins out of our database and application servers.&lt;/p&gt;

&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;These were the most read articles that I shared with you over 2016. I recommend reading through them (even twice if you already did) as you can learn a heaps.&lt;/p&gt;

&lt;p&gt;Make sure that you don’t miss the golden ones in 2017 and &lt;strong&gt;&lt;a href="https://csharpdigest.net/"&gt;subscribe&lt;/a&gt;&lt;/strong&gt; to the weekly newsletter to keep your knowledge up to date.&lt;/p&gt;
</content>
  </entry>
</feed>

