<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[Khebbies blog]]></title><description><![CDATA[I write about coding]]></description><link>https://khebbie.dk/</link><image><url>https://khebbie.dk/favicon.png</url><title>Khebbies blog</title><link>https://khebbie.dk/</link></image><generator>Ghost 5.26</generator><lastBuildDate>Fri, 26 Sep 2025 16:38:55 GMT</lastBuildDate><atom:link href="https://khebbie.dk/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[If humans do stuff that computers can do, computers gather at night and laugh at the human]]></title><description><![CDATA[<p>Sometimes we have to do really boring work as software developers.</p><p>For instance today we are working on moving a domain from our internal DNS servers to AWS route53.</p><p>This domain has been in our hands for 25 years - we have a lot of DNS records.</p><p>We naturally have</p>]]></description><link>https://khebbie.dk/if-humans-do-stuff-that-computers-can-do-computers-gather-at-night-and-laugh-at-the-human/</link><guid isPermaLink="false">6023de2a9efeef0001dc54fe</guid><dc:creator><![CDATA[Klaus Hebsgaard]]></dc:creator><pubDate>Wed, 10 Feb 2021 13:42:41 GMT</pubDate><content:encoded><![CDATA[<p>Sometimes we have to do really boring work as software developers.</p><p>For instance today we are working on moving a domain from our internal DNS servers to AWS route53.</p><p>This domain has been in our hands for 25 years - we have a lot of DNS records.</p><p>We naturally have to make sure every record exists in the new DNS - otherwise people can&apos;t receive mails or other important stuff.</p><p>The natural thing to do is compare the two DNS servers. Unfortunately I don&apos;t know of a way to compare two dns servers.</p><p>And I promise you I am not going to do the boring work of comparing every DNS record I know of (I actually lied in the beginning - we are moving 3 domains).</p><p>But I am a human who knows programming.</p><p>So instead of sitting down and do dull comparison work - I will sit down and do interesting programming work.</p><p>Using the AWS cli for route53 I can get all the DNS records like so (if you don&apos;t know about jq and you do json stuff - you will love it!)</p><pre><code class="language-bash">prod aws route53 list-resource-record-sets --hosted-zone-id $ZONE_ID | jq &apos;.ResourceRecordSets[] | {Name: .Name, Type: .Type, Value: .ResourceRecords[].Value}&apos;</code></pre><p>I put this into a file and I do some manual mangling (I should automate that, but hey this is a one off - right [it never is]) I put it into a file called input.json</p><p>I then parse the file like to</p><pre><code class="language-bash">jq -c &apos;.[]&apos; input.json | while read i; do
    echo &quot;=========================================&quot;
    # Name, Type, Value
    name=`echo $i | jq &apos;.Name&apos; | tr -d &quot;\&quot;&quot; `
    ttype=`echo $i | jq &apos;.Type&apos; | tr -d &quot;\&quot;&quot;`
    value=`echo $i | jq &apos;.Value&apos; | tr -d &quot;\&quot;&quot;`
    
    echo $name $ttype $value
    dig_options=( $ttype +noall +answer )

    existing=`dig &quot;${dig_options[@]}&quot; $name @8.8.8.8 | sed &apos;s/[0-9]*//g&apos; | sort -u`
    new=`dig &quot;${dig_options[@]}&quot; $name @$AWS_DNS_SERVER | sed &apos;s/[0-9]*//g&apos; | sort -u`
    if [[ &quot;$existing&quot; == &quot;$new&quot; ]]; then

      echo -e &quot;\e[01;32mstrings are equal\e[0m&quot;
    else
      echo -e &quot;\e[01;31mstrings are not equal\e[0m&quot;

      echo &quot;from existing dns&quot;
      echo $existing

      echo &quot;from new dns&quot;
      echo $new
    fi

done
</code></pre><p>This script will loop over all the records from route53 and look it up in dig from googles DNS server and the new AWS route53 server and it will give me a nice output, where red mean I made a mistake and green means OK.</p><p>Now all I have to do is run the script and look out for the red lines (and ignore NS and SOA records since the should be different)</p><p>What do I want to say with this? - well of course I am proud of what I did and want to brag about it.</p><p>But I also want you to think: When you have your next dull task with maybe a dash of repetitive work on top - &quot;how can I automate this&quot;.</p><p>We know how to program - lets put it to good use!</p><p>As Mary Poppins would have said &quot;Just a spoon full of sugar makes the medicine go down!&quot;</p>]]></content:encoded></item><item><title><![CDATA[How should I do error handling?]]></title><description><![CDATA[<p>In <a href="https://khebbie.dk/dont-do-generic-error-handling/">my last post</a> I told you not to do generic error handling.</p><p>The natural next question is then &quot;How should I do error handling?&quot;.</p><p>That question can be hard to answer, and as always in software development the answer is: &quot;It depends&quot;.</p><p>First of all</p>]]></description><link>https://khebbie.dk/how-should-i-do-error-handling/</link><guid isPermaLink="false">60201365dd88e30001c322aa</guid><dc:creator><![CDATA[Klaus Hebsgaard]]></dc:creator><pubDate>Sun, 07 Feb 2021 16:34:02 GMT</pubDate><content:encoded><![CDATA[<p>In <a href="https://khebbie.dk/dont-do-generic-error-handling/">my last post</a> I told you not to do generic error handling.</p><p>The natural next question is then &quot;How should I do error handling?&quot;.</p><p>That question can be hard to answer, and as always in software development the answer is: &quot;It depends&quot;.</p><p>First of all error handling in every language is different, and you should certainly do what is idiomatic in your specific programming language.</p><p>Next it depends very much on you business case.</p><p>By making exception handling generic, you make error handling a technical thing - solved with technical methods and a technical mindset.</p><p>However when you do error handling you are, most likely, implementing something useful for the business you work for (if not you should probably stop and see why not). So we have to consider what the business needs us to do. If for instance you have a locked resource and your auth. system is down - do you give access to every one of do you shut out everyone? That is certainly not a technical question - somebody from the business side of things should be asked about that.</p><p>In the error handling, I mentioned in the last post, I btw. didn&apos;t find the error handling obvious: it took me a while to find out where the error handling was taking place.</p><p>The reason for this is, apart from my slowness, that the error handling did not stand out.</p><p>Error handling is the special case, and for a long time I tried to hide away the error handling, thinking that I did not want the special case (error handling) to stand in the way of the normal case.</p><p>However I have changed my mind on this.</p><p>For instance in go, error handling, done idiomatically, is every method that should be handled, returning a tuple of an error (if present) and the normal case return value. For every method call you have to check if the method succeed. When I first came to go - I hated it - but now I can see that at least error handling is in your face - you can see what is going on.</p><pre><code class="language-go">f, err := os.Open(&quot;/test.txt&quot;)
if err != nil {
    fmt.Println(err)
    return
}
fmt.Println(f.Name(), &quot;opened successfully&quot;)</code></pre><p><strong>Bottom line:</strong></p><p>Error handling is not a technical thing, but a business decision.</p><p>Error handling should be easily identifiable in the code, so you can see what is the normal case and what is the special case.</p><p>You might want to read the blog post I made about <a href="https://khebbie.dk/exception-handling-for-junior-devs/">exception handling for junior developers.</a></p>]]></content:encoded></item><item><title><![CDATA[Don't do generic error handling]]></title><description><![CDATA[<p>So I just had a look at a fairly new restful api, written in kotlin.</p><p>The developers who made the api decided to be smart about error handling - instead of doing error handling in every api endpoint - why not just do some generic error handling.</p><p>The error handling</p>]]></description><link>https://khebbie.dk/dont-do-generic-error-handling/</link><guid isPermaLink="false">601ec0a791cc8e0001ff8e59</guid><category><![CDATA[architecture]]></category><category><![CDATA[generic_programming]]></category><dc:creator><![CDATA[Klaus Hebsgaard]]></dc:creator><pubDate>Sat, 06 Feb 2021 16:27:33 GMT</pubDate><content:encoded><![CDATA[<p>So I just had a look at a fairly new restful api, written in kotlin.</p><p>The developers who made the api decided to be smart about error handling - instead of doing error handling in every api endpoint - why not just do some generic error handling.</p><p>The error handling exists in ControllerExceptionHandler.kt</p><p>The code would look something like:</p><pre><code class="language-kotlin">    @ExceptionHandler(WebClientResponseException::class)
    fun handleWebClientResponseException(e: WebClientResponseException): ResponseEntity&lt;Any&gt; {
        logger().error(&quot;Error from WebClient - Status {}: {}&quot;, e.rawStatusCode, e.statusText, e)
        return ResponseEntity(mapOf(&quot;error&quot; to &quot;Error in external service&quot;), HttpStatus.BAD_GATEWAY)
    }
</code></pre><p>That really seems like a smart thing to do - right!</p><p>Well I suppose you save a lot of time not doing exception handling on each and every endpoint.</p><p><strong>However</strong> error handling is not something that should be generalized.</p><p><em>The thing is:</em> when an error happens in one situation it should probably be handled completely differently from another situation.</p><p>For instance imagine a customer not being able to order a product on your website - you probably want customer support handing this ASAP.</p><p>On the other hand if you cannot load related products on the product page, you probably want to log an error and have developers look into it at next convenient time.</p><p>These are two examples that could easily both stem from the same WebClientResponseException - but they should be handled very differently.</p><p><strong>Bottom line:</strong></p><p>Exception handling is pretty important to do specifically and differently in every instance, since the response is probably different for different use cases.</p><p>And actually you most likely want to ask the business owners what should happen in each case.</p>]]></content:encoded></item><item><title><![CDATA[Are you smart enough to debug your code?]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>Everyone knows that debugging is twice as hard as writing a program in the first place. So if you&apos;re as clever as you can be when you write it, how will you ever debug it?<br>
Brian Kernighan from The Elements of Programming Style, 2nd edition, chapter 2</p>
<p>&#x201C;</p>]]></description><link>https://khebbie.dk/if-you-write-your-code-so/</link><guid isPermaLink="false">5c2643bf4728a30001b8a11b</guid><dc:creator><![CDATA[Klaus Hebsgaard]]></dc:creator><pubDate>Tue, 26 Dec 2017 17:01:17 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>Everyone knows that debugging is twice as hard as writing a program in the first place. So if you&apos;re as clever as you can be when you write it, how will you ever debug it?<br>
Brian Kernighan from The Elements of Programming Style, 2nd edition, chapter 2</p>
<p>&#x201C;Simple doesn&#x2019;t mean stupid. Thinking that it does, does.&#x201D; - Paul Krugman</p>
<p>Have you ever worked with a piece of that that made you think: &quot;The person who created software was really smart - like a lot smarter than me&quot;?</p>
<p>I have and when I was younger I was impressed, but as I have seen a lot of <em>&apos;smart code&apos;</em> I am not impressed with it any longer.</p>
<p>Have a look at this Perl one-liner for instance:<br>
<code>find . -name &apos;*~&apos; -print0 | perl -0ne unlink</code></p>
<p>Honestly, I don&apos;t know what it does and figuring it out is almost hopeless. BTW <a href="https://explainshell.com/explain?cmd=find+.+-name+%27*%7E%27+-print0+%7C+perl+-0ne+unlin">Explain shell at your rescue</a></p>
<p>In the Perl community, there was a culture of making one-liner that would do magic. And that is exactly the problem with that culture - magic.</p>
<p>Code that is not simple and clear to understand is a pain to maintain and will slow you down. When the code is overly complicated and not simple, it could just as well be magic.<br>
Remember: when we amend the code, we have to understand it first, and then we can change it. Of course, a good test suite will help you with the understanding and the confidence while changing it.<br>
Some times I have seen people who did not try to understand the code before implementing a bug fix or a change.<br>
This can of course be due to two things:</p>
<ol>
<li>The code is too complex to understand</li>
<li>The developer is too lazy to spend time understanding before moving on.</li>
</ol>
<p>The solution to 1 is actually to understand the code and then make time to make it understandable.</p>
<p>As a software developer, it is a pleasure to create a piece of code that is pretty complex - it makes you feel smart in - the moment.</p>
<p>But it is better to work a bit longer on this problem and make it readable and understandable for the next person, who takes over the code after you.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[One of the best programming skills you can have is knowing when to walk away for awhile.]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p><em>&quot;One of the best programming skills you can have is knowing when to walk away for awhile.&quot;</em> - Oscar Godson<br>
<em>&quot;Sometimes it&apos;s better to leave something alone, to pause, and that&apos;s very true of programming.&quot; - Joyce Wheeler<br>
&quot;Best ergonomics advice</em></p>]]></description><link>https://khebbie.dk/one-of-the-best-programming-skills-you-can-have-is-knowing-when-to-walk-away-for-awhile/</link><guid isPermaLink="false">5c2643bf4728a30001b8a11a</guid><dc:creator><![CDATA[Klaus Hebsgaard]]></dc:creator><pubDate>Wed, 20 Dec 2017 20:50:06 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p><em>&quot;One of the best programming skills you can have is knowing when to walk away for awhile.&quot;</em> - Oscar Godson<br>
<em>&quot;Sometimes it&apos;s better to leave something alone, to pause, and that&apos;s very true of programming.&quot; - Joyce Wheeler<br>
&quot;Best ergonomics advice is &apos;stay hydrated&apos;&quot;</em> Michael Feathers</p>
<p>When working in a factory it is pretty easy to see if you are doing work if you are standing by the assembly line and do manual work of some sort - you are probably working.<br>
Many people, even software developers, believe that writing code is what we do.<br>
But I would state that <em>thinking</em> is what we do.</p>
<p>Most software developers have experienced working on a hard problem that they couldn&apos;t solve and then suddenly while they were doing some other mundane task, the solution to the problem just showed up.<br>
So if you have a hard problem sitting staring at the computer screen for more than half an hour (give or take...) will not solve the problem.<br>
Getting away from the computer will most likely help you.<br>
I have often left work with an unsolvable problem only to show up the next day and fix it in 5 minutes.<br>
Just to give an anecdote from the real life:<br>
I once worked at a place where we had a strange error that we couldn&apos;t quite catch. We worked a long time to figure out what it was and couldn&apos;t figure it out.<br>
But one day as I was sitting on the toilet with my phone browsing on the toilet it appeared to me.<br>
I was not trying to solve the problem, I was just browsing the website...</p>
<p>And BTW drinking a lot of water will make sure you don&apos;t sit too long staring at the computer screen - especially as you get older.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[We value code that is easy to maintain over code that is easy to write]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p><em>&quot;We value code that is easy to maintain over code that is easy to write&quot;</em> from Growing object-oriented software guided by tests.</p>
<p><em>&quot;Quick becomes quicksand&quot;</em> Uncle Bob.<br>
This is the first post in the <a href="https://khebbie.dk/series-on-wise-software-catchphrases/">Series on wise software catchphrases</a></p>
<p>This is probably one of the most</p>]]></description><link>https://khebbie.dk/we-value-code-that-is-easy-to-maintain-over-code-that-is-easy-to-write/</link><guid isPermaLink="false">5c2643bf4728a30001b8a118</guid><dc:creator><![CDATA[Klaus Hebsgaard]]></dc:creator><pubDate>Mon, 18 Dec 2017 18:13:30 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p><em>&quot;We value code that is easy to maintain over code that is easy to write&quot;</em> from Growing object-oriented software guided by tests.</p>
<p><em>&quot;Quick becomes quicksand&quot;</em> Uncle Bob.<br>
This is the first post in the <a href="https://khebbie.dk/series-on-wise-software-catchphrases/">Series on wise software catchphrases</a></p>
<p>This is probably one of the most overarching catchphrases in this series, I have often mentioned it to a junior developer while working on a task.</p>
<p>Just think about it for a second: You sit with the task of writing new code for maybe a day or two. After that, you and other people come back to the code again and again.</p>
<p>So often when we develop software we have a deadline or at least a product owner who waits for the task to finish. Completing the task quickly and cut some corners seems like a good way to satisfy everybody, and we can always fix the code later.<br>
Thinking like this is what makes a mess of a code base. History and experience show that getting back to technical debt and fixing it later never (or only rarely) happens.<br>
So if we follow the mantra of cutting corners to deliver quickly we end up with a codebase that has a lot of technical debt. If you do this over a period of time you will move slowly and the product owner will wonder why you are so slow, you used to be so quick.<br>
Believe me, I have worked on code bases that had been developed in the spirit of delivering fast and in the end, it was not fast at all.</p>
<p>As you can see taking it slow will make it quick in the long run.<br>
This particular catchphrase is, as I already mentioned, one that is overarching in this series, and hence the following posts will assume that we strive for code that is easy to maintain over code that is easy to write.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Series on wise software catchphrases]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>So I follow Code Wisdom on twitter:<br>
<a href="https://twitter.com/CodeWisdom">https://twitter.com/CodeWisdom</a><br>
What the account basically does is tweet quotations by famous and not so famous software developers. The quotes are wisdom gathered through many years of working with software development.</p>
<p>In my day to day job, I work with quite</p>]]></description><link>https://khebbie.dk/series-on-wise-software-catchphrases/</link><guid isPermaLink="false">5c2643bf4728a30001b8a119</guid><dc:creator><![CDATA[Klaus Hebsgaard]]></dc:creator><pubDate>Mon, 18 Dec 2017 17:25:22 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>So I follow Code Wisdom on twitter:<br>
<a href="https://twitter.com/CodeWisdom">https://twitter.com/CodeWisdom</a><br>
What the account basically does is tweet quotations by famous and not so famous software developers. The quotes are wisdom gathered through many years of working with software development.</p>
<p>In my day to day job, I work with quite a few junior developers.<br>
As a senior developer, it is my job to teach them the ways of software development; one of the things that I find most important for is to pass on some of the stuff I have learned.</p>
<p>But also I find it important to pass on some of the stuff other people have learned throughout the years.<br>
Teaching them about my experience comes pretty naturally in the day to day tasks, but I thought it would be good to do a blog post series on some of the wisdom gathered by others along the way and add my reason why I find it valuable.<br>
This way I can pass on the bigger picture of the software development landscape.</p>
<p>So in the coming weeks, I will publish a series of my take on software development wisdom. I will strive to make the post short and on the point.</p>
<p><a href="https://khebbie.dk/we-value-code-that-is-easy-to-maintain-over-code-that-is-easy-to-write/">1st post - We value code that is easy to maintain over code that is easy to write</a><br>
<a href="https://khebbie.dk/one-of-the-best-programming-skills-you-can-have-is-knowing-when-to-walk-away-for-awhile/">2nd post - One of the best programming skills you can have is knowing when to walk away for awhile.</a><br>
<a href="http://www.khebbie.dk/if-you-write-your-code-so/">3rd post - Are you smart enough to debug your code?</a></p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Serverless Monitoring heat remotely]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>So I attend a small church and I am responsible for the heating system.<br>
That should be a simple task, but sometimes people fiddle with the heating system and sometimes the furnace simply stops.</p>
<p>And even though I live pretty close to the church I don&apos;t want to</p>]]></description><link>https://khebbie.dk/monitoring-heat-remotely/</link><guid isPermaLink="false">5c2643bf4728a30001b8a11f</guid><dc:creator><![CDATA[Klaus Hebsgaard]]></dc:creator><pubDate>Sun, 17 Dec 2017 18:40:54 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>So I attend a small church and I am responsible for the heating system.<br>
That should be a simple task, but sometimes people fiddle with the heating system and sometimes the furnace simply stops.</p>
<p>And even though I live pretty close to the church I don&apos;t want to go there all the time to check the heat.</p>
<p>So I decided to setup remote heat monitoring in our church.</p>
<p>The way I have done it is I have setup a raspberry pi with a spark fun tmp102 temperature sensor and every 5 minutes, through a cron job, I send the data to AWS.</p>
<p>I decided to do it serverless since it is a way to small task to have a ec2 server running all the time.<br>
I setup a lambda, where I can send a curl message to with the room and temperature.<br>
I used the default template for a lambda and an API gateway to setup a Python lambda.</p>
<p>The following code is the lambda:</p>
<pre><code>import boto3
import json


def respond(err, res=None):
    return {
        &apos;statusCode&apos;: &apos;400&apos; if err else &apos;200&apos;,
        &apos;body&apos;: err.message if err else json.dumps(res),
        &apos;headers&apos;: {
            &apos;Content-Type&apos;: &apos;application/json&apos;,
        },
    }


def lambda_handler(event, context):
    operation = event[&apos;httpMethod&apos;]

    if operation != &quot;POST&quot;:
        respond(ValueError(&apos;Unsupported method &quot;{}&quot;&apos;.format(operation)))
    
    js = json.loads(event[&apos;body&apos;])
    print(js[&quot;room&quot;])
    print(js[&quot;temperature&quot;])
    cw = boto3.client(&apos;cloudwatch&apos;)
    cw.put_metric_data(
    Namespace=&apos;temperature&apos;,
    MetricData=[
        {
            &apos;MetricName&apos;: js[&quot;room&quot;],
            &apos;Value&apos;: js[&quot;temperature&quot;]
        
        }&quot;{}&quot;&apos;.
    ]
)

return respond(None, js)
</code></pre>
<p>This code is extermely naive and simply fails if not called correctly, for this use case that is just fine.<br>
So if it is not called with room and temperature in a json it will return an internal server error. But I figure the only client is the bash script below and if it fails I will know through the fact that the metrics are missing.</p>
<p>As you can see this is really just the default template with me sending the room and temperature to CloudWatch.<br>
I decided that if I wanted to go serverless Cloudwatch metrics would be the way to go.</p>
<p>So what is now left is to send the temperature from the tmp102 and send it to the lambda via a curl.</p>
<p>The following code is what I use to get the temperature from the tmp102 and send the curl</p>
<pre><code>#!/bin/bash
hex_temp=$(i2cget -y 1 0x48)
dec_temp=$(printf &quot;%d&quot; $hex_temp)
echo $dec_temp
curl -X POST --data &apos;{&quot;temperature&quot;: &apos;$dec_temp&apos;, &quot;room&quot;: &quot;kids&quot;}&apos; https://lambda-stuff.execute-api.us-east-1.amazonaws.com/prod/temperature
</code></pre>
<p>So the tmp102 sends the temperature in Celsius through hex. I convert it to decimal and send it in json to the lambda.</p>
<p>I set it up in a cron to send every 5th minute, and .... it didn&apos;t work.</p>
<p>After some googling I found this:<br>
<a href="https://www.raspberrypi.org/forums/viewtopic.php?t=60702">https://www.raspberrypi.org/forums/viewtopic.php?t=60702</a></p>
<p>What made it work was adding to the path of the crontab:<br>
<code>PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/games:/usr/games</code></p>
<p>After that I simply called the above bash script every 5th minute.</p>
<p>And I now have a cloudwatch dashboard in AWS where I can see the temperature in the church.<br>
And I can even set alarms if the temperature goes below or above a preset.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Docker vs binary packages]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>The other day I had a conversation with a Operations Engineer who made a bold statement: &quot;Sending us a docker container is not different from sending us a .deb package&quot;<br>
I do not agree with that statement at all but didn&apos;t have the time to counter</p>]]></description><link>https://khebbie.dk/docker-vs-binary-packages/</link><guid isPermaLink="false">5c2643bf4728a30001b8a116</guid><dc:creator><![CDATA[Klaus Hebsgaard]]></dc:creator><pubDate>Sat, 21 Oct 2017 08:59:10 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>The other day I had a conversation with a Operations Engineer who made a bold statement: &quot;Sending us a docker container is not different from sending us a .deb package&quot;<br>
I do not agree with that statement at all but didn&apos;t have the time to counter it, so instead I will write this blog post.</p>
<p>So what really is the difference between a deb package and a docker container?<br>
Just a sidenote that .deb is just one example of a binary package, rpms and packages for other linux systems, could be another example. And I suppose the Windows term would be a msi package.</p>
<p>Well let me first quote our ops guy a bit more, he further said that if we need to monitor CPU usage for one application, we can just setup a vm for that application.</p>
<p>So the first thing to notice is that <a href="https://blog.docker.com/2016/03/containers-are-not-vms/">a docker container is not the same as a vm.</a>.<br>
There are many differences between vms and docker containers, and I won&apos;t get into them all in this blogpost.<br>
But one major difference is that a docker container is simply running on your computer (which is probably a vm by the way). And since it is running on your computer it does not have the overhead of a hypervisor and an operating system. These are pretty big overheads.<br>
Furthermore a docker container does not really care which computer/vm it is running on, as long as it has a kernel that supports all the stuff it needs (such as cgroups, namespaces etc.)<br>
This means that you are free to move your docker container around as you please and as you have resources available. This means you can use a container orchestration tool like AWS ECS or kubernetes, and hence use the resources on your servers more efficiently.<br>
Hosting in a container orchestration also means that hosting a java or python app is basically the same, since your are &apos;just&apos; shipping a container. Having big consistency on all your hosted applications means that hosting a new type of thing (be it language or external application) is not a big thing, since all it needs is a container, some configuration and some ports to expose.<br>
It also means that the docker container is self containing (see a container is self containing) so all the configuration drift you get from long running vms should be gone.<br>
Furthermore a docker container does not care if it is running on a developers computer, a test server or production - it just needs the correct configuration.<br>
And since it is self containing it does not contaminate the computer on which it is running.<br>
So a docker container will not have problems with applications wanting different dependencies (like java 7 and 8 or python 2 or 3), because everything is inside the container (&lt;-- it is self containing).<br>
If you start a docker container it will be fetched from the image repository and started. When you stop and delete the container and the image, it will be completely gone from the computer not leaving stuff behind that will mess up dependencies in the future.</p>
<p>There are many more differences, but these are just a few I choose to emphasize.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Exception handling for junior devs]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>Exception handling is a very important thing for creating production ready code.<br>
When you are a brand new developer you might not know how to do exception handling properly.<br>
Here I will try to describe a few basic rules that should be followed when coding.<br>
Please note that as always</p>]]></description><link>https://khebbie.dk/exception-handling-for-junior-devs/</link><guid isPermaLink="false">5c2643bf4728a30001b8a115</guid><dc:creator><![CDATA[Klaus Hebsgaard]]></dc:creator><pubDate>Tue, 05 Sep 2017 13:31:15 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>Exception handling is a very important thing for creating production ready code.<br>
When you are a brand new developer you might not know how to do exception handling properly.<br>
Here I will try to describe a few basic rules that should be followed when coding.<br>
Please note that as always there might be reasons for breaking these rules, but they are a sane default.</p>
<p>The rules here can be used for java and c#.</p>
<h2 id="exceptionsshouldbeexceptional">Exceptions should be exceptional</h2>
<p>Don&apos;t use exceptions for normal program flow.<br>
In normal program flow use simple return statements.<br>
<strong>why</strong>: Because exceptions were not made for normal program flow and hence they can be a very slow.<br>
Furthermore the program flow is a lot harder to follow when exceptions are flowing around as a few methods might be skipped.<br>
<strong>cure</strong>: Use normal program flow mechanisms for this.</p>
<h2 id="dontusepokmonexceptionhandling">Don&apos;t use Pok&#xE9;mon exception handling</h2>
<p>You know the themesong from Pok&#xE9;mon: &quot;Gotta catch them all&quot; - well it may hold true when in the Pok&#xE9;mon universe, but when doing exception handling it rarely does.</p>
<h4 id="dontcatchexception">Don&apos;t catch <code>Exception</code>.</h4>
<p><strong>why</strong>: If you catch <code>Exception</code> it is a strong communication that you do not know what you are doing which exceptions you are expecting.<br>
And furthermore future exceptions that you do not know about will be handled<br>
<strong>cure</strong>: Handle the specific exceptions that you know about and expect.</p>
<h3 id="dontswallowexceptions">Don&apos;t swallow exceptions</h3>
<p>Swallowing exceptions means catching an exception and doing nothing.<br>
<strong>why</strong>: Only if you really know that this is by intention and always leave a comment as to why you swallow the exception. Not just a <code>//do nothing by intention</code>, but a real explanation.<br>
Swallowing exceptions denies your future self the opportunity to debug the problem in production.<br>
<strong>cure</strong>: Only handle exceptions you can actually handle</p>
<h2 id="ifyoucannotdoanythingtoanexceptiondonthandleit">If you cannot do anything to an exception don&apos;t handle it</h2>
<p>Let someone else handle it.<br>
<strong>why</strong>: you are just adding extra code and taking away the chance to handle the exception where it actually has meaning<br>
<strong>cure</strong>: Don&apos;t do anything where you cannot handle the exception, but do find another place where it makes sense. If you cannot find a place to handle the exception, maybe you have a problem in your code?</p>
<p>But maybe you should do some logging... But ...</p>
<h3 id="dontloganexceptionifyoucannothandleit">Don&apos;t log an exception if you cannot handle it</h3>
<p><strong>why</strong>: If you log where you cannot handle it you will clutter the log and add no context.<br>
<strong>cure</strong>: Log when you handle exceptions and add some context.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[TILs (Today I Learneds)]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>I have started a <a href="https://khebbie.github.io/">TIL</a>.<br>
To be quite honest, I don&apos;t post a lot on this blog, but on my TIL, I do post a lot more often.</p>
<!--kg-card-end: markdown-->]]></description><link>https://khebbie.dk/tils-today-i-learneds/</link><guid isPermaLink="false">5c2643bf4728a30001b8a114</guid><dc:creator><![CDATA[Klaus Hebsgaard]]></dc:creator><pubDate>Tue, 06 Sep 2016 17:10:31 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>I have started a <a href="https://khebbie.github.io/">TIL</a>.<br>
To be quite honest, I don&apos;t post a lot on this blog, but on my TIL, I do post a lot more often.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Values in software development]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>During my job as a software developer I have stumbled upon some values that makes a lot of sense to me:</p>
<p><strong>We value code that is easy to maintain over code that is easy to write</strong><br>
I am not sure if this is the origin of this value, but I</p>]]></description><link>https://khebbie.dk/values-in-software-development/</link><guid isPermaLink="false">5c2643bf4728a30001b8a113</guid><dc:creator><![CDATA[Klaus Hebsgaard]]></dc:creator><pubDate>Tue, 06 Sep 2016 17:07:08 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>During my job as a software developer I have stumbled upon some values that makes a lot of sense to me:</p>
<p><strong>We value code that is easy to maintain over code that is easy to write</strong><br>
I am not sure if this is the origin of this value, but I first heard of this value in the book <a href="http://www.amazon.co.uk/Growing-Object-Oriented-Software-Guided-Signature/dp/0321503627/ref=sr_1_1?ie=UTF8&amp;qid=1442818353&amp;sr=8-1&amp;keywords=growing+object-oriented+software+guided+by+tests">Growing Object Oriented Software, Guided by tests</a>.<br>
This should be the overarching value of 99% of all software developers.<br>
You will have to go over your code again and again, and so will your co-workers or someone coming after you.<br>
So the few minutes or hours you save now is just like wetting your pants, you will feel the warm now, but it gets a lot colder in time ;-)</p>
<p><strong>We value code that is clear over code that is consise</strong><br>
This value is amongst other places found on <a href="http://elixir-lang.org/getting-started/meta/macros.html">the elixir-lang website</a><br>
The simple reasoning behind this value is the principle that you read code a lot more than you write it, just as stated above.<br>
One of the places where concise code has been valued too high is in perl one-liners.<br>
Perl one-liners kind of made sense when using them on the cli. But they sometimes spilled into real code that had to be maintained.<br>
For a period there was almost some kind of heroic thing in the software community, where the ones with the most concise unreadable code, that did the expected was supposedly the most heroic software developer.<br>
I am glad to say that this is a dying culture.</p>
<p><strong>Everyone knows that debugging is twice as hard as writing a program in the first place. So if you&apos;re as clever as you can be when you write it, how will you ever debug it?</strong><br>
This quote is from Brian Kernighan, and it probably one of the most clever things said in software development. I don&apos;t have much to add to it.</p>
<p>So as you can see these values are about almost the same thing: Namely writing code that is as easy to maintain as possible.<br>
By writing easily maintainable code, you save the business many money in the long run.<br>
The hard part about this is making the business understand that by <strong>not</strong> cowboy coding through this in a hurry now, you save them money in the long run.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Vlog: what is an API (for non-tech people)]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>So I decided to try something new:<br>
I made a video explaining what an API is!</p>
<p>Of course if you are a software developer you probably already know, so move on then, or wait just a second - you could show this video to a business person you know :-)</p>]]></description><link>https://khebbie.dk/vlog-what-is-an-api-for-non-tech-people/</link><guid isPermaLink="false">5c2643bf4728a30001b8a112</guid><dc:creator><![CDATA[Klaus Hebsgaard]]></dc:creator><pubDate>Wed, 16 Sep 2015 11:56:59 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>So I decided to try something new:<br>
I made a video explaining what an API is!</p>
<p>Of course if you are a software developer you probably already know, so move on then, or wait just a second - you could show this video to a business person you know :-)</p>
<p>So if you are, say maybe a business person, you have maybe heard developers talk about the API, and maybe you thought: &quot;What the heck is an API?&quot;.<br>
Well that is what I am going to explain to you in this video:</p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/QdrGPZHqQz0" frameborder="0" allowfullscreen></iframe>
<p>Now, what I explained in the video is that, basically an API is like a website for phone apps.<br>
So you could say that you iPhone app browses a website, when it calls the API.<br>
The app can both get and post data to the API, just like when you for instance search on google, then you post a search term like maybe: &quot;new iPhone model&quot; and google sends the results back to you.<br>
Basically that is what the phone app does when it calls the api.</p>
<p>Just to make it clear, API means Application Programmable Interface. And it can be more than just what I am talking about here (which is an API for a phone app), but getting in to that would be too long haired for this post.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Mix tasks in Phoenix using Ecto]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>Working with <a href="https://github.com/phoenixframework/phoenix">Phoenix</a> version 0.16 I needed to import some records from a csv file.<br>
My first problem was where to place the tasks, after some research I found that you place them under lib/tasks and name them some_name.ex (not exs)</p>
<p>The code for the task</p>]]></description><link>https://khebbie.dk/mix-tasks-in-phoenix/</link><guid isPermaLink="false">5c2643bf4728a30001b8a111</guid><category><![CDATA[ecto]]></category><category><![CDATA[elxir]]></category><category><![CDATA[phoenix]]></category><category><![CDATA[mix]]></category><dc:creator><![CDATA[Klaus Hebsgaard]]></dc:creator><pubDate>Sun, 16 Aug 2015 08:54:13 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>Working with <a href="https://github.com/phoenixframework/phoenix">Phoenix</a> version 0.16 I needed to import some records from a csv file.<br>
My first problem was where to place the tasks, after some research I found that you place them under lib/tasks and name them some_name.ex (not exs)</p>
<p>The code for the task should look something like:</p>
<script src="https://gist.github.com/khebbie/0f7156f04b8f86c31ebd.js"></script>
<p>You can now run the task with the command<br>
<code>mix task_name</code><br>
That was the first problem.</p>
<p>Next I needed to use Ecto, in the task, since I wanted to import some records.</p>
<p>When I wanted to insert records I got the error (my app is called ExCMS):<br>
<code>repo ExCMS.Repo is not started, please ensure it is part of your supervision tree</code></p>
<p>It was pretty obvious from this error message that I should start the Ecto repo, and I found that I needed to run the following code in order to start the Ecto repo:<br>
<code>ExCMS.Repo.start_link</code></p>
<p>And all was good.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Optimistic locking in mongomapper and eventbus]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>In Be My Eyes we use <a href="https://github.com/mongomapper/mongomapper/">mongomapper</a> and <a href="https://github.com/kevinrutherford/event_bus">eventbus</a>, both are very good tools that make my everyday life as a developer easier - except when it doesn&apos;t.<br>
We had a problem where more than one helper is added to a call. This should not happen. We have</p>]]></description><link>https://khebbie.dk/optimistic-locking-in-mongomapper-and-eventbus/</link><guid isPermaLink="false">5c2643bf4728a30001b8a110</guid><dc:creator><![CDATA[Klaus Hebsgaard]]></dc:creator><pubDate>Mon, 27 Apr 2015 17:29:36 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>In Be My Eyes we use <a href="https://github.com/mongomapper/mongomapper/">mongomapper</a> and <a href="https://github.com/kevinrutherford/event_bus">eventbus</a>, both are very good tools that make my everyday life as a developer easier - except when it doesn&apos;t.<br>
We had a problem where more than one helper is added to a call. This should not happen. We have a <a href="https://github.com/bemyeyes/bemyeyes-server/blob/master/routes/requests.rb#L56">pretty simple if statement</a> in our code. The thing is that many helpers were allowed through the if statement down to the &quot;default&quot; case, where only one should be allowed.<br>
I really lost a lot of hair trying to figure out why more than one helper could fall through. It really made no sense, since we assigned a helper and assigned <em>answered</em> to be true. This should mean that the next time a helper tries to answer, she would be told that the call was already answered. But in many cases this did not happen.<br>
I searched the codebase through and through for many hours with two things in mind that could be wrong:</p>
<ol>
<li>The if statement did not work</li>
<li>The db returned something wrong.</li>
</ol>
<p>No 1 is absurd so I did not follow that very far.<br>
No 2 I could not make sense of until I did some research on stale objects and mongomapper.<br>
I stumbled over and <a href="https://www.bignerdranch.com/blog/optimistic-locking-with-mongodb/">article on optimistic locking in mongodb</a> and it hit me that somewhere in the codebase I must have and object with an old state that I somehow saved and by doing that, I overwrote the <em>answered</em>  and helper attributes.<br>
A quick Ag search found <a href="https://github.com/bemyeyes/bemyeyes-server/commit/4a7d958fde54cbdacce72217b57d58d7510b9ae7">two places</a> where I sent actual objects and not just Ids in the eventbus, after reading the aforementioned article I saw pretty clearly how bad this is.<br>
For a quick fix I did a request.reload to get the new state before saving the new.<br>
Long term it shall be a rule in the codebase that we do not send objects in the eventbus, but rather send ids. I already knew that and had it on my todo, but did not consider it important - well now I do ...</p>
<!--kg-card-end: markdown-->]]></content:encoded></item></channel></rss>