<?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"><channel><title><![CDATA[KITS - Blogg]]></title><description><![CDATA[Senaste inläggen i KITS blogg]]></description><link>https://kits.se</link><generator>GatsbyJS</generator><lastBuildDate>Wed, 07 Jan 2026 12:20:52 GMT</lastBuildDate><item><title><![CDATA[AWS Key Management System ]]></title><description><![CDATA[<p>Management of cryptographic keys</p>
<p>In this post we will discuss what Key Management System is and what are the main features of it. Furthermore, we will show how you can integrate KMS with AWS lambda and migrate your signing and verification workload to the KMS service. At last, we will discuss a limitation on creating CSRs in the KMS service and a solution for it using Bouncycastle and Java. :rocket:</p>
<!-- more -->
<h4>What is KMS service</h4>
<p><a href="https://aws.amazon.com/kms" target="_self" rel="noopener noreferrer">The key management service (KMS)</a> is a service for the creation and management of the cryptographic keys. You can create both symmetric keys as well as asymmetric key pairs to perform encryption, decryption, signing, and verification process in your applications. Signing and verify in AWS kms feature is <a href="https://aws.amazon.com/blogs/security/digital-signing-asymmetric-keys-aws-kms/" target="_self" rel="noopener noreferrer">relatively new</a> compared to encryption and decryption.</p>
<h4>Key features</h4>
<p>KMS is a <a href="https://aws.amazon.com/kms/features/" target="_self" rel="noopener noreferrer">fully managed</a> service and can integrate with plenty of AWS services easily. KMS uses a <a href="https://aws.amazon.com/kms/features/#Secure" target="_self" rel="noopener noreferrer">hardware security module</a> to keep the cryptographic keys secure. AWS KMS is designed so that no one, including AWS employees, can retrieve your plaintext keys from the service.</p>
<h4>Characteristic of the key</h4>
<p>For the propose of this post, I am using an EC key pair to sign my content with the private key of that key pair. More specifically, the “key-spec” I am using is an asymmetric <a href="https://tools.ietf.org/html/rfc5753" target="_self" rel="noopener noreferrer">NIST-recommended</a> elliptic curve key pairs, EC_NIST_P256 for signing and verification. <a href="https://docs.aws.amazon.com/kms/latest/developerguide/symm-asymm-choose.html" target="_self" rel="noopener noreferrer">On this page</a>, you can see which configuration is most suitable for your case.</p>
<h4>What is CSR and why we need to create one CSR</h4>
<p>Certificate Signing Request (CSR) is a message from an applicant to a certificate authority(CA). You normally apply for a digital certificate to a CA by sending them a CSR. The most common format for CSRs is the <a href="https://en.wikipedia.org/wiki/PKCS" target="_self" rel="noopener noreferrer">PKCS</a>10 specification, usually represented as a Base64 encoded. A CSR usually consists of three parts:</p>
<ol>
<li>A subject including identity information like country, state, city, organization name, and so on.</li>
<li>The public key for which the certificate should be issued</li>
<li>A digital signature on point one and two. This integrity protection ensures the CA that nothing has changed in the communication channel.</li>
</ol>
<h2>Kms signer application</h2>
<p>Let’s create an application to demonstrate how you can migrate your signing workload on KMS. I am using <a href="https://www.serverless.com/" target="_self" rel="noopener noreferrer">Serverless framework</a> for creating my AWS resources. If you are not familar with this framework, take a look on <a href="https://www.serverless.com/framework/docs/getting-started/" target="_self" rel="noopener noreferrer">this page</a></p>
<ul>
<li>Create a Aws Lambda
​ <code class="language-text">sls create -t "aws-java-maven" -n kms-signer</code></li>
</ul>
<h4>First step: Create lambda and API gateway</h4>
<ul>
<li>
<p>Add post method as a trigger to the lambda function in <code class="language-text">serverless.yml</code></p>
<div class="gatsby-highlight" data-language="yml"><pre class="language-yml"><code class="language-yml"><span class="token key atrule">events</span><span class="token punctuation">:</span>
  <span class="token punctuation">-</span> <span class="token key atrule">http</span><span class="token punctuation">:</span>
      <span class="token key atrule">path</span><span class="token punctuation">:</span> sign
      <span class="token key atrule">method</span><span class="token punctuation">:</span> post</code></pre></div>
</li>
<li>
<p>Deploy
Congratulation! You created a lambda function and an API gateway for it. It is time to deploy it on AWS. Don’t forget to build your project before deploy!
​ <code class="language-text">sls deploy</code></p>
</li>
<li>
<p>If the deploy goes well, you will get a link to your API in the logs. You can test the API using a REST client e.g. curl like following:</p>
</li>
</ul>
<div class="gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">curl</span> <span class="token parameter variable">--location</span> <span class="token parameter variable">--request</span> POST <span class="token string">'https://&lt;MYURL>/dev/sign'</span> <span class="token punctuation">\</span>
<span class="token parameter variable">--header</span> <span class="token string">'Content-Type: application/json'</span> <span class="token punctuation">\</span>
--data-raw <span class="token string">'{
	"message": "sign-this!"
}'</span></code></pre></div>
<p>Ofcourse you get a default result which has created by Serverless framwork. In the next step we will put the application into context and send back an actual result from the API. You can read the logs on CloadWatch console, or easier using this command:</p>
<p>​ <code class="language-text">sls logs -f &lt;FUNCTION-NAME></code></p>
<h4>BONUS:</h4>
<p>Useful log messages that you can put in your lambda to observe system environment variables, context data, and event data are as following.</p>
<div class="gatsby-highlight" data-language="java"><pre class="language-java"><code class="language-java"><span class="token comment">// log execution details</span>
<span class="token constant">LOG</span><span class="token punctuation">.</span><span class="token function">debug</span><span class="token punctuation">(</span><span class="token string">"ENVIRONMENT VARIABLES: {}"</span><span class="token punctuation">,</span> gson<span class="token punctuation">.</span><span class="token function">toJson</span><span class="token punctuation">(</span><span class="token class-name">System</span><span class="token punctuation">.</span><span class="token function">getenv</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token constant">LOG</span><span class="token punctuation">.</span><span class="token function">debug</span><span class="token punctuation">(</span><span class="token string">"CONTEXT: {}"</span><span class="token punctuation">,</span> gson<span class="token punctuation">.</span><span class="token function">toJson</span><span class="token punctuation">(</span>context<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// process event</span>
<span class="token constant">LOG</span><span class="token punctuation">.</span><span class="token function">debug</span><span class="token punctuation">(</span><span class="token string">"EVENT: {}"</span><span class="token punctuation">,</span> gson<span class="token punctuation">.</span><span class="token function">toJson</span><span class="token punctuation">(</span>event<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token constant">LOG</span><span class="token punctuation">.</span><span class="token function">debug</span><span class="token punctuation">(</span><span class="token string">"EVENT TYPE: {}"</span><span class="token punctuation">,</span> event<span class="token punctuation">.</span><span class="token function">getClass</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div>
<h4>Second step: Create a EC key pair</h4>
<p>In the time of writing this post, CloudFormation does not currently support creating asymmetric CMKs. So we need to do it in the Console or Aws Command line tool. You can find a comprehensive description on how to create a CMK <a href="https://docs.aws.amazon.com/kms/latest/developerguide/create-keys.html#create-asymmetric-cmk" target="_self" rel="noopener noreferrer">here</a></p>
<h4>Third step: Add IAM Role</h4>
<p>The Lambda needs to have correct IAM ROLE to be able to access the CMK you have created in the previous step. To give access, you need something like following the IAM role statement in your serverless.yml.</p>
<div class="gatsby-highlight" data-language="yml"><pre class="language-yml"><code class="language-yml"><span class="token key atrule">iamRoleStatements</span><span class="token punctuation">:</span>
  <span class="token punctuation">-</span> <span class="token key atrule">Effect</span><span class="token punctuation">:</span> <span class="token string">"Allow"</span>
    <span class="token key atrule">Action</span><span class="token punctuation">:</span>
      <span class="token punctuation">-</span> kms<span class="token punctuation">:</span>GetPublicKey
      <span class="token punctuation">-</span> kms<span class="token punctuation">:</span>ListKeys
      <span class="token punctuation">-</span> kms<span class="token punctuation">:</span>ListResourceTags
      <span class="token punctuation">-</span> kms<span class="token punctuation">:</span>Sign
    <span class="token key atrule">Resource</span><span class="token punctuation">:</span> <span class="token string">"arn:aws:kms:&lt;REGION>:&lt;ACCOUNT>:key/&lt;KEY-ID>"</span></code></pre></div>
<h4>Fourth step: Sign a string using kms</h4>
<p>First of all you need to include <code class="language-text">aws-java-sdk-kms</code> dependency to your project dependencies. Then, You need to define another function handler and corresponding API gateway for it. Finally, you create a method that gets a serilized object as an argument and send a sign request to the KMS. For example you can look into following example:</p>
<div class="gatsby-highlight" data-language="java"><pre class="language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">byte</span><span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token function">sign</span><span class="token punctuation">(</span><span class="token keyword">final</span> <span class="token keyword">byte</span><span class="token punctuation">[</span><span class="token punctuation">]</span> message<span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">final</span> <span class="token class-name">SignResult</span> signResult <span class="token operator">=</span> <span class="token class-name">AWSKMSClientBuilder</span>
      <span class="token punctuation">.</span><span class="token function">standard</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
      <span class="token punctuation">.</span><span class="token function">build</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
      <span class="token punctuation">.</span><span class="token function">sign</span><span class="token punctuation">(</span><span class="token function">getSignRequest</span><span class="token punctuation">(</span>message<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">return</span> signResult<span class="token punctuation">.</span><span class="token function">getSignature</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">array</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token class-name">SignRequest</span> <span class="token function">getSignRequest</span><span class="token punctuation">(</span><span class="token keyword">final</span> <span class="token keyword">byte</span><span class="token punctuation">[</span><span class="token punctuation">]</span> signingInput<span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">final</span> <span class="token keyword">byte</span><span class="token punctuation">[</span><span class="token punctuation">]</span> hashedInput <span class="token operator">=</span> <span class="token class-name">DigestUtils</span><span class="token punctuation">.</span><span class="token function">sha256</span><span class="token punctuation">(</span>signingInput<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">final</span> <span class="token class-name">ByteBuffer</span> message <span class="token operator">=</span> <span class="token class-name">ByteBuffer</span><span class="token punctuation">.</span><span class="token function">wrap</span><span class="token punctuation">(</span>hashedInput<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">SignRequest</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
      <span class="token punctuation">.</span><span class="token function">withMessage</span><span class="token punctuation">(</span>message<span class="token punctuation">)</span>
      <span class="token punctuation">.</span><span class="token function">withMessageType</span><span class="token punctuation">(</span><span class="token string">"DIGEST"</span><span class="token punctuation">)</span>
      <span class="token punctuation">.</span><span class="token function">withKeyId</span><span class="token punctuation">(</span><span class="token string">"&lt;KEY-ID>"</span><span class="token punctuation">)</span>
      <span class="token punctuation">.</span><span class="token function">withSigningAlgorithm</span><span class="token punctuation">(</span><span class="token class-name">SigningAlgorithmSpec</span><span class="token punctuation">.</span><span class="token constant">ECDSA_SHA_256</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre></div>
<h4>Fifth step: Create a CSR programmatically</h4>
<p>So far, so good! You have an application that can sign content for you. You can send your signature and your public key to a third party entity, and that entity is able to verify your signature. One problem is remaining, though! What if an attacker forges your signature and public key. You need to ensure the other entities that your public key is authentic.</p>
<p>First, you apply for a certificate by sending a CA a CSR. The digital certificate you eventually get from the CA is confirming the authenticity of your public key. Traditionally, you create a CSR with OpenSSL tool with these steps:</p>
<ol>
<li>First generate a pair of keys:
<code class="language-text">openssl ecparam -out private.key -name prime256v1 -genkey</code></li>
<li>Then using these pair of key to generating a CSR. Note that you need private key for having a “Applicant signature” on your CSR
<code class="language-text">openssl req -new -key private.key -out my-csr.csr -sha256</code></li>
</ol>
<p>The issue in KMS is the CSR creation feature is not an available feature. Additionally, no one can have access to the private key generated on KMS. So this is a deadend way?</p>
<p>No, using the Bouncycastle, we are able to create a CSR. By using <code class="language-text">PKCS10CertificationRequestBuilder</code> class from PKCS package, we create a “pre-build” CSR object which would need a <code class="language-text">ContentSigner</code>. All we need to do is implement <code class="language-text">ContentSigner</code> interface and glue the “sign” method we created before to this class.</p>
<div class="gatsby-highlight" data-language="java"><pre class="language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">AwsKMSContentSigner</span> <span class="token keyword">implements</span> <span class="token class-name">ContentSigner</span> <span class="token punctuation">{</span>

  <span class="token keyword">private</span> <span class="token keyword">final</span> <span class="token class-name">ByteArrayOutputStream</span> outputStream<span class="token punctuation">;</span>
  <span class="token keyword">private</span> <span class="token keyword">final</span> <span class="token class-name">AlgorithmIdentifier</span> sigAlgId<span class="token punctuation">;</span>
  <span class="token keyword">private</span> <span class="token keyword">final</span> <span class="token class-name">AwsKmsSigner</span> signer<span class="token punctuation">;</span>

  <span class="token keyword">public</span> <span class="token class-name">AwsKMSContentSigner</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>sigAlgId <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">DefaultSignatureAlgorithmIdentifierFinder</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token string">"SHA256WITHECDSA"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>outputStream <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ByteArrayOutputStream</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>signer <span class="token operator">=</span> <span class="token class-name">AwsKmsSigner</span><span class="token punctuation">.</span><span class="token function">getInstance</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token annotation punctuation">@Override</span>
  <span class="token keyword">public</span> <span class="token class-name">AlgorithmIdentifier</span> <span class="token function">getAlgorithmIdentifier</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span>sigAlgId<span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token annotation punctuation">@Override</span>
  <span class="token keyword">public</span> <span class="token class-name">OutputStream</span> <span class="token function">getOutputStream</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span>outputStream<span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token annotation punctuation">@Override</span>
  <span class="token keyword">public</span> <span class="token keyword">byte</span><span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token function">getSignature</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">byte</span><span class="token punctuation">[</span><span class="token punctuation">]</span> signedAttributeSet <span class="token operator">=</span> outputStream<span class="token punctuation">.</span><span class="token function">toByteArray</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> signer<span class="token punctuation">.</span><span class="token function">sign</span><span class="token punctuation">(</span>signedAttributeSet<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

<span class="token punctuation">}</span></code></pre></div>
<p>Additionally, pass it to the PKCS builder. The builder uses the signer to generate the “application signature” on the CSR.</p>
<div class="gatsby-highlight" data-language="java"><pre class="language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token class-name">String</span> <span class="token function">createCsr</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token class-name">PKCS10CertificationRequestBuilder</span> p10Builder <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">JcaPKCS10CertificationRequestBuilder</span><span class="token punctuation">(</span>
    <span class="token keyword">new</span> <span class="token class-name">X500Principal</span><span class="token punctuation">(</span><span class="token string">"CN=Signer, O=MyOrg, OU=MyOrgUnit, C=Gothenburg, L=Sweden"</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    <span class="token function">getPublicKey</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token class-name">ContentSigner</span> contentSigner <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">AwsKMSContentSigner</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token class-name">PKCS10CertificationRequest</span> csr <span class="token operator">=</span> p10Builder<span class="token punctuation">.</span><span class="token function">build</span><span class="token punctuation">(</span>contentSigner<span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token class-name">PemObject</span> pemObject <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">PemObject</span><span class="token punctuation">(</span><span class="token string">"CERTIFICATE REQUEST"</span><span class="token punctuation">,</span> csr<span class="token punctuation">.</span><span class="token function">getEncoded</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token class-name">StringWriter</span> csrString <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">StringWriter</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token class-name">JcaPEMWriter</span> pemWriter <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">JcaPEMWriter</span><span class="token punctuation">(</span>csrString<span class="token punctuation">)</span><span class="token punctuation">;</span>
  pemWriter<span class="token punctuation">.</span><span class="token function">writeObject</span><span class="token punctuation">(</span>pemObject<span class="token punctuation">)</span><span class="token punctuation">;</span>
  pemWriter<span class="token punctuation">.</span><span class="token function">close</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  csrString<span class="token punctuation">.</span><span class="token function">close</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">return</span> csrString<span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre></div>
<p>Done! The output is something similar to this:</p>
<div class="gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">-----BEGIN CERTIFICATE REQUEST-----
MIIBKDCBzwIBADBtMQ8wDQYDVQQHEwZTd2VkZW4xEzARBgNVBAYTCkdvdGhlbmJ1
cmcxGzAZBgNVBAsTEk15T3JnYW5pemF0aW9uVW5pdDEXMBUGA1UEChMOTXlPcmdh
bml6YXRpb24xDzANBgNVBAMTBlNpZ25lcjBZMBMGByqGSM49AgEGCCqGSM49AwEH
A0IABEGM2IMVUC3edUwly1y+G+ufLXbCVj6Ee9Dqz/XFEV7goD2twHBok+kGQxqN
nYkgBDIw54F9JtWWEhSch8QIluCgADAKBggqhkjOPQQDAgNIADBFAiEA3WFMR7mg
nF4VqCh1sFoLoxoAdvZvRpAa/F4wyvJQjU0CIEVxatmlGXzmoBY/MKHPiXG2UKVu
0yOb6ZsZeFQoHHN1
-----END CERTIFICATE REQUEST-----</code></pre></div>
<h4>Verify the signature in CSR</h4>
<p>If you want to verify the digital signature inside a Certificate Signing Request, you can use the OpenSSL “req -verify” command as shown below:</p>
<p><code class="language-text">openssl req -in myCsr.csr -noout -verify</code></p>
<p>The output “verify OK” indicates that the decrypted digital signature matches the digest of the CSR data.</p>
<h4>Useful links</h4>
<ul>
<li>SSL shopper <a href="https://www.sslshopper.com/" target="_self" rel="noopener noreferrer">https://www.sslshopper.com/</a></li>
<li>Cert logik <a href="https://certlogik.com/decoder/" target="_self" rel="noopener noreferrer">https://certlogik.com/decoder/</a></li>
<li><a href="https://aws.amazon.com/blogs/security/digital-signing-asymmetric-keys-aws-kms/" target="_self" rel="noopener noreferrer">https://aws.amazon.com/blogs/security/digital-signing-asymmetric-keys-aws-kms/</a></li>
</ul>]]></description><link>https://kits.se/blogg-2020-09-10/aws-key-management-system</link><guid isPermaLink="false">https://kits.se/blogg-2020-09-10/aws-key-management-system</guid><dc:creator><![CDATA[Soroush Nejad]]></dc:creator><pubDate>Thu, 10 Sep 2020 00:00:00 GMT</pubDate></item><item><title><![CDATA[Union types - when one type isn't enough]]></title><description><![CDATA[<p>I often encounter situations where I want to use data which have more than one type. The most common case for me is when I want to present an as informative response as possible to why an HTTP request wasn’t successful, but it could also be an internal backend API with a set of types which might be extended in the future, or a frontend application where multiple types would help model the domain. Unions types to the rescue!</p>
<!-- more -->
<h2>Background</h2>
<p>A couple of years ago I was working on a large codebase with a lot of dependencies between features where we often missed to implement new functionality for all use cases in the product, as it was quite impossible to know all functionality that we supported. When I first learned about the <a href="https://en.wikipedia.org/wiki/Visitor_pattern" target="_self" rel="noopener noreferrer">visitor pattern</a> I felt like it solved all my problems, I could now extend my data types and all code that used the types would need to implement handling of the newly added cases. The visitor pattern require you to explicitly handle all potential data it can contain, which is nice, but the downside is that it produces a lot of boilerplate code and isn’t really intuitive to understand, it felt like I had to read up on the pattern over and over again. Enter union types.</p>
<h2>Union types</h2>
<p>Union types, or discriminating unions, are basically a type which can contain one value of one of its specified types, similar to how in a <a href="https://www.json.org/json-en.html" target="_self" rel="noopener noreferrer">data format specification</a> you might want to say “a value is either a boolean, a string, or a number”.</p>
<p>In TypeScript using a union type might look like this</p>
<div class="gatsby-highlight" data-language="typescript"><pre class="language-typescript"><code class="language-typescript"><span class="token keyword">const</span> value<span class="token operator">:</span> <span class="token builtin">boolean</span> <span class="token operator">|</span> <span class="token builtin">string</span> <span class="token operator">|</span> <span class="token builtin">number</span> <span class="token operator">=</span> <span class="token string">"hello"</span><span class="token punctuation">;</span></code></pre></div>
<p>or in F# like this</p>
<div class="gatsby-highlight" data-language="fsharp"><pre class="language-fsharp"><code class="language-fsharp"><span class="token keyword">type</span> <span class="token class-name">ValueType</span> <span class="token operator">=</span>
    <span class="token operator">|</span> Boolean <span class="token keyword">of</span> <span class="token class-name">bool</span>
    <span class="token operator">|</span> Text <span class="token keyword">of</span> <span class="token class-name">string</span>
    <span class="token operator">|</span> Number <span class="token keyword">of</span> <span class="token class-name">int</span>
    
<span class="token keyword">let</span> value <span class="token operator">=</span> Text <span class="token string">"hello"</span><span class="token punctuation">;</span></code></pre></div>
<p>or in C# I have created <a href="https://github.com/PhilipAlexanderWallin/GenericDataStructures" target="_self" rel="noopener noreferrer">my own open source project</a> for union types</p>
<div class="gatsby-highlight" data-language="csharp"><pre class="language-csharp"><code class="language-csharp"><span class="token class-name">Union<span class="token punctuation">&lt;</span><span class="token keyword">bool</span><span class="token punctuation">,</span> <span class="token keyword">string</span><span class="token punctuation">,</span> <span class="token keyword">int</span><span class="token punctuation">></span></span> <span class="token keyword">value</span> <span class="token operator">=</span> <span class="token string">"hello"</span><span class="token punctuation">;</span></code></pre></div>
<p>What is great about the union type is that you cannot access specific functionality of the value type unless you first can guarantee the functionality is available. Lets say we now want to get the number of characters of our value, I’ll treat true/false as text in this example:</p>
<p>In TypeScript this might look like this</p>
<div class="gatsby-highlight" data-language="typescript"><pre class="language-typescript"><code class="language-typescript"><span class="token keyword">function</span> <span class="token function">getNumberOfCharacters</span><span class="token punctuation">(</span>value<span class="token operator">:</span> <span class="token builtin">boolean</span> <span class="token operator">|</span> <span class="token builtin">string</span> <span class="token operator">|</span> <span class="token builtin">number</span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token builtin">number</span> <span class="token punctuation">{</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">typeof</span> value <span class="token operator">===</span> <span class="token string">"boolean"</span><span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        <span class="token keyword">return</span> value <span class="token operator">?</span> <span class="token number">4</span> <span class="token operator">:</span> <span class="token number">5</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
	<span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">typeof</span> value <span class="token operator">===</span> <span class="token string">"number"</span><span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        <span class="token keyword">return</span> value<span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>length<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
	<span class="token keyword">else</span> 
    <span class="token punctuation">{</span>
        <span class="token comment">// Here we know it's a string, which has a length property</span>
        <span class="token keyword">return</span> value<span class="token punctuation">.</span>length<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

<span class="token keyword">const</span> characters <span class="token operator">=</span> <span class="token function">getNumberOfCharacters</span><span class="token punctuation">(</span>value<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div>
<p>or in F# like this</p>
<div class="gatsby-highlight" data-language="fsharp"><pre class="language-fsharp"><code class="language-fsharp"><span class="token keyword">let</span> getNumberOfCharacters value <span class="token operator">=</span>
    <span class="token keyword">match</span> value <span class="token keyword">with</span>
    <span class="token operator">|</span> Boolean boolean <span class="token operator">-></span> <span class="token keyword">match</span> boolean <span class="token keyword">with</span>
        <span class="token operator">|</span> <span class="token keyword">true</span> <span class="token operator">-></span> <span class="token number">4</span>
        <span class="token operator">|</span> <span class="token keyword">false</span> <span class="token operator">-></span> <span class="token number">5</span>
    <span class="token operator">|</span> Text text <span class="token operator">-></span> text<span class="token punctuation">.</span>Length
    <span class="token operator">|</span> Number number <span class="token operator">-></span> number<span class="token punctuation">.</span><span class="token function">ToString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>Length
    
<span class="token keyword">let</span> characters <span class="token operator">=</span> getNumberOfCharacters value<span class="token punctuation">;</span></code></pre></div>
<p>or in C# for <a href="https://github.com/PhilipAlexanderWallin/GenericDataStructures#union" target="_self" rel="noopener noreferrer">my union type</a></p>
<div class="gatsby-highlight" data-language="csharp"><pre class="language-csharp"><code class="language-csharp"><span class="token class-name"><span class="token keyword">var</span></span> characters <span class="token operator">=</span> <span class="token keyword">value</span><span class="token punctuation">.</span><span class="token function">Map</span><span class="token punctuation">(</span>
        boolean <span class="token operator">=></span> boolean <span class="token punctuation">?</span> <span class="token number">4</span> <span class="token punctuation">:</span> <span class="token number">5</span><span class="token punctuation">,</span>
        text <span class="token operator">=></span> text<span class="token punctuation">.</span>Length<span class="token punctuation">,</span>
        number <span class="token operator">=></span> number<span class="token punctuation">.</span><span class="token function">ToString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>Length
    <span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div>
<p>Another nice thing here is that if we should include an additional type in the value union type in the future the code wouldn’t compile. In the case of TypeScript I would no longer know it’s a string type in my last “else”-case, in F# I would no longer be matching on all possible values, and in my C# library I would be missing a Func as parameter.</p>
<h2>How I use union types</h2>
<p>Lately I’ve been working mostly with REST API:s, where my use case has been that I should execute some kind Create/Read/Update/Delete operation and report back either a successful result or a failure result with data detailing why the operation failed. Commonly the failure cases are validation errors, missing data/resources, conflicting modifications, or insufficient permissions. In backend services I’ve seen many different kinds of result classes, often with implicit relation between data properties which you as a user of the service need to understand to access the result properties safely. In my library I have implemented <a href="https://github.com/PhilipAlexanderWallin/GenericDataStructures#result" target="_self" rel="noopener noreferrer">a result type</a> which is basically just a union type with extra methods to deal with the success case. This can be useful if you for example use the backend services both for a public REST API, where error handling is very important, and for an internal API or tool for developers where you only care if operation executed as expected. It also makes it more semantically clear what is the expected result than just using a union type directly.</p>
<h2>Summary</h2>
<p>I believe union types is a good way of handling multiple data types while maintaining strongly typed code, and as a way to minimize need of dependent properties of data objects. Even if your language of choice doesn’t support it natively you can hopefully implement it yourself.</p>
<p>If you’re a C# developer feel free to try out my <a href="https://github.com/PhilipAlexanderWallin/GenericDataStructures" target="_self" rel="noopener noreferrer">generic data structures project</a> for union types, any and all feedback is appreciated!</p>]]></description><link>https://kits.se/blogg-2020-05-07/unions-types</link><guid isPermaLink="false">https://kits.se/blogg-2020-05-07/unions-types</guid><dc:creator><![CDATA[Philip Wallin]]></dc:creator><pubDate>Thu, 07 May 2020 00:00:00 GMT</pubDate></item><item><title><![CDATA[Svelte - the framework for those who don't want a framework]]></title><description><![CDATA[<p>The hype around web frontend frameworks seems like a never ending story. This article is not trying to address that problem. But sometimes there comes around something that challenge the norm of how things are done. <a href="https://reactjs.org" target="_self" rel="noopener noreferrer">React</a> was one of those frameworks that completely revolutionized the industry thanks to some controversial ways of structure code.</p>
<p>Svelte uses new controversial ways of going about things that have caught my interest. In this article I will present an overview of Svelte.</p>
<!-- more -->
<h2>Problems to solve</h2>
<h3>Bundle size</h3>
<p>A common problem with web applications today is that the bundle size is way too large to provide a fast user experience. Not only does the code need to be delivered over a network, it also needs to be parsed before anything can be painted to the screen. A common problem with almost all frameworks today. Solutions like code splitting and server side rendering exists but I rarely see that they are used. Code splitting can also not be done on the framework bundle, typically the largest portion of the bundle anyway.</p>
<h3>Performance</h3>
<p>Declarative code style is very popular. In the case of React, given a set of input props it declares what markup should be produced. Not <em>how</em>, but <em>what</em> markup. Under the hood React uses a “virtual dom” mechanism that compares every single piece of the old markup against a proposed new markup. If any difference is found, React will access the “browser dom” and perform the actual update.</p>
<h3>Things to learn</h3>
<p>Developers like things that are easy to learn but have a flexible nature. A trend amongst frameworks since the jQuery days is that there are typically less framework specific details to learn. jQuery had a ton of API to learn, Angular 1.x had its share of boilerplate, React has reduced that even more. But this article is about to describe Svelte, which in my humble opinion has been the easiest framework to learn to date since there actually aren’t that much to it.</p>
<h2>Solution attempts</h2>
<p>The creator of Svelte, Rich Harris, recognized that frameworks aren’t made for organizing code, they only organize our minds. Meaning that the translation from declarative code (the <em>what</em>) to imperative code (the <em>how</em>) might as well be done at build time rather than at run time. This moves the necessity of a framework being present from the client browser to the build step. If we don’t need to ship a framework to the client, the bundle size can be significally smaller.</p>
<p>Svelte also doesn’t use a “virtual dom” to keep track of updates, it uses shallow equality comparison along with a “reactive operator” to know what to update. It does so by producing the actual dom api calls needed to make the update. That also gets rid of a complete category of performance problems. Therefore Svelte is also very fast.</p>
<p>Svelte is currently at version 3, which fundamentally works the same way as version 2, but it focuses a lot on the developer experience. That’s what caught my interest and has kept me going, since there actually aren’t that much API details to remember.</p>
<h2>Developing in Svelte</h2>
<p>Start to play around with Svelte using the following commands, which effectively clones an example project setup:</p>
<div class="gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">  npx degit sveltejs/template new_app</code></pre></div>
<p>The project setup is put in the <code class="language-text">new_app</code> directory. Enter that folder and start developing like so:</p>
<div class="gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">  <span class="token builtin class-name">cd</span> new_app
  <span class="token function">npm</span> <span class="token function">install</span>
  <span class="token function">npm</span> run dev</code></pre></div>
<p>Visit <a href="http://localhost:5000" target="_self" rel="noopener noreferrer">http://localhost:5000</a> and open your editor of choice to take a look around of the files that produced the web application. Find <code class="language-text">src/App.svelte</code> and make a change. It should immediately be reflected in the browser.</p>
<p>The svelte compiler is configured in <code class="language-text">rollup.config.js</code> and <code class="language-text">src/main.js</code> is the starting point for the application.</p>
<h3>Components</h3>
<p>Components in Svelte follows the “component tree” abstraction made popular by React. Creating custom elements that’s inserted into your regular HTML markup. Create a new file <code class="language-text">src/TimerButton.svelte</code>.</p>
<div class="gatsby-highlight" data-language="html"><pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span><span class="token punctuation">></span></span><span class="token script"><span class="token language-javascript">
  <span class="token comment">// javascript goes here</span>
</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">></span></span>

<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>style</span><span class="token punctuation">></span></span><span class="token style"><span class="token language-css">
  // styling goes here
</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>style</span><span class="token punctuation">></span></span>

<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name"><span class="token namespace">on:</span>click</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>{handleClick}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>+ 30 seconds<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">></span></span></code></pre></div>
<p>Remove most of <code class="language-text">src/App.svelte</code> and import the TimerButton component:</p>
<div class="gatsby-highlight" data-language="html"><pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span><span class="token punctuation">></span></span><span class="token script"><span class="token language-javascript">
  <span class="token keyword">import</span> TimerButton <span class="token keyword">from</span> <span class="token string">"./TimerButton.svelte"</span>
</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">></span></span>

<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>TimerButton</span> <span class="token punctuation">/></span></span></code></pre></div>
<p>By now, if your editor hasn’t shown you nice colors yet, it’s time to set it to highlight <code class="language-text">html</code> and you should be good to go.</p>
<p>The timer button should be disabled for 30 seconds after clicked, so let’s add some logic to do that. It’s a simple interval counting down and we use curly braces to use variables and functions in the markup.</p>
<div class="gatsby-highlight" data-language="html"><pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span><span class="token punctuation">></span></span><span class="token script"><span class="token language-javascript">
  <span class="token keyword">let</span> time <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>

  <span class="token function">setInterval</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
    <span class="token comment">// if time is 0 (or below?) stay 0, otherwise decrease by 1</span>
    time <span class="token operator">=</span> time <span class="token operator">&lt;=</span> <span class="token number">0</span> <span class="token operator">?</span> <span class="token number">0</span> <span class="token operator">:</span> time <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">1000</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token comment">// handler to refer to from the markup</span>
  <span class="token keyword">const</span> <span class="token function-variable function">handleClick</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
    time <span class="token operator">+=</span> <span class="token number">30</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">;</span>
</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">></span></span>

<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>style</span><span class="token punctuation">></span></span><span class="token style"><span class="token language-css">
  <span class="token selector">button[disabled]</span> <span class="token punctuation">{</span>
    <span class="token property">background</span><span class="token punctuation">:</span> white<span class="token punctuation">;</span>
    <span class="token property">color</span><span class="token punctuation">:</span> lightgrey<span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>style</span><span class="token punctuation">></span></span>

&lt;button disabled={time !== 0} on:click={handleClick}>+ 30 seconds<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">></span></span></code></pre></div>
<p>If copy pasted correctly, you should have a button which when clicked disables itself for 30 seconds. But it would be nice to show the count down as well. That’s easy to print in some more markup (try and do that now…). But I would like to show how that state can be handled by a <code class="language-text">store</code> instead.</p>
<h3>Stores</h3>
<p>Our store will for this example be very simple. There are of course more complex variants (<a href="https://svelte.dev/tutorial/writable-stores" target="_self" rel="noopener noreferrer">read about them here</a>). Create <code class="language-text">src/TimeStore.js</code> and fill it with these two lines:</p>
<div class="gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">import</span> <span class="token punctuation">{</span> writable <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"svelte/store"</span>

<span class="token keyword">export</span> <span class="token keyword">const</span> timeStore <span class="token operator">=</span> <span class="token function">writable</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span></code></pre></div>
<p>Our <code class="language-text">TimerButton.svelte</code> should now be refactored to use the store instead of the local <code class="language-text">time</code> variable. The <code class="language-text">subscribe</code> part of the code seems somewhat boilerplatey, feel free to <a href="https://svelte.dev/tutorial/auto-subscriptions" target="_self" rel="noopener noreferrer">rewrite using an auto subscription</a>.</p>
<div class="gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">import</span> <span class="token punctuation">{</span> timeStore <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"./TimeStore.js"</span>
<span class="token keyword">let</span> time

<span class="token function">setInterval</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
  timeStore<span class="token punctuation">.</span><span class="token function">update</span><span class="token punctuation">(</span><span class="token parameter">t</span> <span class="token operator">=></span> <span class="token punctuation">(</span>t <span class="token operator">&lt;=</span> <span class="token number">0</span> <span class="token operator">?</span> <span class="token number">0</span> <span class="token operator">:</span> t <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">1000</span><span class="token punctuation">)</span>

<span class="token keyword">const</span> <span class="token function-variable function">handleClick</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
  timeStore<span class="token punctuation">.</span><span class="token function">update</span><span class="token punctuation">(</span><span class="token parameter">t</span> <span class="token operator">=></span> t <span class="token operator">+</span> <span class="token number">30</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>

timeStore<span class="token punctuation">.</span><span class="token function">subscribe</span><span class="token punctuation">(</span><span class="token parameter">t</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
  time <span class="token operator">=</span> t
<span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre></div>
<p>We have now created a store and interacted with it using the <code class="language-text">update</code> and <code class="language-text">subscribe</code> functions. In fact, the API you need to learn isn’t much more than that. However, we just used a <code class="language-text">writable</code> store. There are <a href="https://svelte.dev/tutorial/readable-stores" target="_self" rel="noopener noreferrer"><code class="language-text">readable</code></a> and <a href="https://svelte.dev/tutorial/derived-stores" target="_self" rel="noopener noreferrer"><code class="language-text">derived</code></a> stores as well, which we will not get in to more detail about here.</p>
<p>We will create a second component to show the decreasing time value which it will read from the store. This time we will use the much sleaker “auto subscribe” method to read the value. Create <code class="language-text">src/TickerView.svelte</code> containing the following code:</p>
<div class="gatsby-highlight" data-language="html"><pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span><span class="token punctuation">></span></span><span class="token script"><span class="token language-javascript">
  <span class="token keyword">import</span> <span class="token punctuation">{</span> timeStore <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"./TimeStore.js"</span>
</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">></span></span>

<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>style</span><span class="token punctuation">></span></span><span class="token style"><span class="token language-css">
  <span class="token selector">p</span> <span class="token punctuation">{</span>
    <span class="token property">font-size</span><span class="token punctuation">:</span> 50px<span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>style</span><span class="token punctuation">></span></span>

<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">></span></span>{$timeStore}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">></span></span></code></pre></div>
<p>This component doesn’t do much more than showing the decreasing number from the store. It includes some CSS though. Styling with CSS in Svelte is isolated to the component that declares the style. Svelte does this by rewriting all style declarations with a unique CSS class. So CSS for a <code class="language-text">p</code> in one component does affect any other components.</p>
<h2>Summary</h2>
<p>So far we’ve made one of the simplest applications possible. But believe me, the complexity doesn’t really grow when scaling up. From my experience complexity grows due to poor naming and stress. A framework can only go so far in staying away from the developer’s attention, and in the case of Svelte, I think it has a good level of abstraction.</p>
<p>There are many features in Svelte which we didn’t cover, for instance <a href="https://svelte.dev/tutorial/reactive-assignments" target="_self" rel="noopener noreferrer">reactivity</a>, <a href="https://svelte.dev/tutorial/dom-events" target="_self" rel="noopener noreferrer">events</a>, <a href="https://svelte.dev/tutorial/text-inputs" target="_self" rel="noopener noreferrer">bindings</a>, <a href="https://svelte.dev/tutorial/tweened" target="_self" rel="noopener noreferrer">animations 😲</a>, <a href="https://svelte.dev/tutorial/onmount" target="_self" rel="noopener noreferrer">component lifecycle hooks</a> and much more. Since Svelte only brings along those features needed when compiling the code, there’s no need to prioritize away features with regards to bundle size (which other frameworks must compromise).</p>
<h2>Resources</h2>
<ul>
<li><a href="https://svelte.dev/tutorial/basics" target="_self" rel="noopener noreferrer">Svelte Tutorial</a> - the go-to interactive tutorial</li>
<li><a href="https://sapper.svelte.dev/" target="_self" rel="noopener noreferrer">Sapper</a> - an application framework made for Svelte</li>
</ul>]]></description><link>https://kits.se/blogg-2019-10-29/svelte</link><guid isPermaLink="false">https://kits.se/blogg-2019-10-29/svelte</guid><dc:creator><![CDATA[Gustav Jorlöv]]></dc:creator><pubDate>Tue, 29 Oct 2019 00:00:00 GMT</pubDate></item><item><title><![CDATA[Craft Conf 2019, Budapest]]></title><description><![CDATA[<p>Som en del av vår kompetensutveckling har vi på Kits bland annat möjligheten att besöka intressanta konferenser. Vi var två kollegor som valde att bege oss till Budapest och <a href="https://craft-conf.com" target="_self" rel="noopener noreferrer">Craft Conf</a>, anordnad av Prezi och den del av IBM som tidigare var Ustream. Konferensen gick av stapeln 8-10 maj.</p>
<p>Craft Conf har det uttalade temat ”software delivery craft” och fokuserar på de metoder och verktyg som kan vara till gagn den enskilde individen, större organisationer och allt däremellan. Efter att tidigare ha besökt mer tekniskt inriktade konferenser så var det välkommet att få lyfta blicken en smula. Det här året lockades det med namn som Martin Fowler, Dan North, Dave Snowden, Mary Poppendieck och Bjarne Stroustrup. Bland talarna fanns även Göteborgsbekanta Emily Bache.</p>
<!-- more -->
<p>Återkommande teman i dragningarna var chaos engineering, skalbar arkitektur och Cynefin. Bland de bättre var Martin Fowlers och Birgitta Böckelers <a href="https://www.youtube.com/watch?v=MZnrxjw602E" target="_self" rel="noopener noreferrer"><em>Cultivating Architecture</em></a> och Randy Shoups <a href="https://www.youtube.com/watch?v=t-sIaw4kHqI" target="_self" rel="noopener noreferrer"><em>Moving Fast at Scale</em></a>, bägge en blandning av tänkvärdheter och sunt förnuft. Mary Poppendieck höll <a href="https://www.youtube.com/watch?v=zlfhJiNmin8" target="_self" rel="noopener noreferrer">en underhållande presentation</a> om hur det är att jobba inom <em>Reliability Engineering</em>, där hon delade med sig av sin långa, gedigna erfarenhet. Några av talarna kan återupplevas, med varierande ljud- och bildkvalitet, på <a href="https://www.youtube.com/channel/UC9E-wqsOP_1nRKXWIWPBhXw" target="_self" rel="noopener noreferrer">Prezis Youtubekanal</a>.</p>
<p>Överlag var Craft Conf en trevlig tillställning som höll till i en lite annorlunda miljö, i och kring ett av ungerska tågmuseets lokstallar, drygt en halvtimme med kollektivtrafik från centrala Budapest. Gissningsvis var det fler besökare i år än tidigare, det märktes att logistiken var lite underdimensionerad vid bland annat matserveringen. Man kunde promenera fritt bland gamla ånglok och vändskivor vilket var skönt ibland då det stundtals blev lite trångt inne i lokalen.</p>
<p>Sammanfattningsvis var Craft Conf en prisvärd konferens med intressant tema, med en gemytlig järnvägshistorisk inramning.</p>]]></description><link>https://kits.se/blogg-2019-05-30/craft-conf-2019-budapest</link><guid isPermaLink="false">https://kits.se/blogg-2019-05-30/craft-conf-2019-budapest</guid><dc:creator><![CDATA[Pär Svedberg]]></dc:creator><pubDate>Thu, 30 May 2019 00:00:00 GMT</pubDate></item><item><title><![CDATA[Security recommendations for implementing BankID]]></title><description><![CDATA[<p>BankID is the leading identification solution in Sweden that allows companies and government agencies to authenticate individuals over the Internet. BankID offers an API which makes integration easy for companies.</p>
<p>In this article I will describe BankID API features which developers should use to limit the effectiveness of today’s phishing attacks against BankID. I will also cover how QR codes can be used as a method for authentication/signing with mobile BankID and how it can improve security.</p>
<p>After reading this article, you will have learned different phishing techniques that exists and what you can do to limit their effectiveness.</p>
<!-- more -->
<h2>Ordering shoes</h2>
<p>Depending on which platform you initiate BankID on, the flow will be different.</p>
<p>Let’s assume we want to order a pair of shoes from supershoes.se on our computer. We pick our shoes, proceed to checkout, enter our address information and select mobile BankID as our signing method. We enter our personal identity number (PIN) and open the BankID app on our phone and sign.</p>
<p>What happened was that supershoes.se sent a <em>signing order</em> with our PIN to BankID using their REST API, informing that the accompanying PIN should sign this request. In this scenario, we expect the user to <em>consume</em> their signing order on a mobile device. I will later explain why this distinction is important. After we send this request to BankID, a special token called <em>autoStartToken</em> is created which is tied to our session. This token is returned to the user, depending on which BankID method is used.</p>
<p>The BankID API offers a <em>requirement</em> parameter which allows you to configure how orders should be created and verified. To configure an order to be limited to mobile BankID, set <em>certificatePolicies</em> in the <em>requirement</em> field:</p>
<div class="gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">"requirement": {    "certificatePolicies": ["1.2.752.78.1.5"]}</code></pre></div>
<p>This restricts an order to only be consumed on mobile devices. The same can be done for other platforms. If it is not evident why it is beneficial to control how an order should be consumed, the following example will show why.</p>
<h3>The autoStartToken</h3>
<p>Let’s say supershoes.se implemented a member’s area page protected by BankID login, with the option to use <em>BankID on file</em> to authenticate. No personal identity number is technically required for this option, if you have multiple identities on your computer/phone, you will be prompted to select the appropriate identity.</p>
<p>Alright, we are sitting at our computer, we browse to the member’s area at supershoes.se and login by authenticating with BankID on file. What happens at this stage is that a special URL is returned to our browser which opens the BankID application automatically. The URL looks like this:</p>
<div class="gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">bankid://?autostarttoken=463e5661-33a9-4738-ad1e-6c5ef1d732ce&amp;redirect=null</code></pre></div>
<p>The local BankID application opens automatically because it has associated itself with the protocol <em>bankid://</em>. The interesting part is the <em>autoStartToken</em> parameter which contains the token value. This token is associated with your current session.</p>
<p>After your local BankID opens, you enter your credentials and successfully complete the identification (or signing). Now, let’s assume the developers at supershoes.se did not specify which platform the token should be limited to. This is means that even though you requested to identify/sign with BankID on file, the token you received can be consumed by <em>mobile BankID on a different device</em>. An attacker could generate a token meant for BankID on file and trick someone to authenticate themselves with the token on <em>their mobile device</em>.</p>
<p>The only thing an attacker needs to do is to send the following:</p>
<div class="gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">bankid://?autostarttoken=463e5661-33a9-4738-ad1e-6c5ef1d732ce&amp;redirect=null</code></pre></div>
<p>Which can of course be semi-disguised as an HTML link, like so:</p>
<div class="gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">&lt;a href="bankid://?autostarttoken=463e5661-33a9-4738-ad1e-6c5ef1d732ce&amp;redirect=null">Click me!&lt;/a></code></pre></div>
<p>Once the unknowing user clicks the link and identify using mobile BankID on their smartphone, the attacker will be successfully logged in as the user. Why this seemingly tiny detail matters is because most users today use mobile BankID which makes this scenario <em>easy</em> for an attacker to perform. Had the token been limited to only be consumed using BankID on file, then this scenario had not been possible. The only thing an attacker could do is to trick someone to identify with the token using specifically BankID on file, which is <em>harder</em> for an attacker to convince someone to do, since most people use mobile BankID.</p>
<h3>AutostarttokenRequired</h3>
<p>In the first example we ordered shoes from supershoes.se from our computer, entered our personal identity number and chose to sign with mobile BankID. If you have multiple mobile devices with your BankID identity installed, you could open any of those devices to sign the request, which is the purpose of mobile BankID.</p>
<p>Let’s explore another common scenario – supershoes.se has created their own app which you have downloaded from the Appstore to your smartphone. In order to use the app, you must enter your PIN and login in using mobile BankID. Since you are <em>on your smartphone</em> and trying to login <em>with your smartphone,</em> you would expect <em>only your smartphone</em> to be able to authenticate. However, as previously mentioned if you have multiple devices with your BankID identity installed, any of them could open the BankID app the sign the request.</p>
<p>This becomes problematic because an attacker could enter your PIN and trick you into signing. This is how most BankID scams are performed today.</p>
<p>But as you may suspect, there is a way to control if all your devices should be able to sign a BankID request or if it should be limited to the device that initiated the request. This is done by specifying the <em>autoStartTokenRequired</em> field in the API request when creating an authentication/signing order request.</p>
<div class="gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">"requirement": {"autoStartTokenRequired": true}</code></pre></div>
<p>The option <em>autoStartTokenRequired</em> specifies that no other device will be able to sign the request. Only the device that initiated the request <em>(your smartphone in this case)</em> will get the <em>autoStartToken</em> and thereby be able to sign with BankID. This means we can make it harder for those who enter other people’s personal identity number and tricks people into signing with their mobile BankID. By specifying <em>autoStartTokenRequired,</em> only the attacker will get the autoStartToken. The attacker must then somehow transfer the token to the victim.</p>
<p>The problem is that we can’t use <em>autoStartTokenRequired</em> when ordering on our computer and signing with mobile BankID, because our mobile phone somehow needs to consume the autoStartToken. This is where QR codes comes into play.</p>
<h2>Scan the QR Code</h2>
<p>QR code scanning does not involve implementing a new technology or support a new protocol, it’s already supported! The QR code is just a visual representation of the URL containing the autoStartToken.</p>
<p><img src="data:image/*;base64,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vH0QERHB7Sc+Pt7qdSBSv2JLrX311VdMH1evXpUKq2SaWrClhrd2MsGWWktMTLR6jQEAAAAAAADAtlwq2Pr555/ttk2eESNGaA62pk6dqjnYOnHihPD25s+fz+0nLi7OmiUwkg22YmJimD7y8vKoefPmLhFs8dgi2Dpw4IDmcQAAAAAAAACAbagGW/aEYAvBFoItAAAAAAAAANCKG2zZW0UKtj788EOHBltqtyImJCRYswRG2dnZUuPesGED08eff/5JtWvXtkuwtXr1ak3zIyJ67bXXNI/j2LFjmscBAAAAAAAAALbBBFuOIBNs3b59m7Zu3Upff/01xcTESLeNGzfSTz/9xH2YuEywlZ2dTRs3blT0/Z///Ieef/55hwZbO3bsoIEDB9KQIUOMbfDgwbRs2TLatGmTVWsUExNDX375Jb388suKftXaoEGDuFcu5efn06hRo+ill14y1g4dOpT8/f2ZeVepUoX69etHQ4cONda+8sorFBQUxF2n119/nf7zn/9YPb/NmzdT9+7dmX7r1atHgwYNon/+859Cc1+5cqXQOm/cuBEhGAAAAAAAAICd6SyX2J5MsPXHH39QtWrVNIVHXbt2pTt37jB9ywRbP/74o12uRJINttT07NlT0zgeeughzWNQw9vfHh4edPLkSab2u+++s8s6qzUfHx/usaEmICBAuO+xY8fachkBAAAAAAAAoAyXD7aysrLIw8NDU3ih1+s1B1u7du1y6WCrd+/emsbh6elJxcXFmsfBs2zZMm6wlZyczNRu377docGWt7c3FRQUCM+lW7duwn1PmDDBlssIAAAAAAAAAGWUi2BL63ObgoKCNAdbcXFxLh1sBQcHaxpHq1atqKioSPM4eJYuXcoNtpKSkpjabdu2OTzYys/PF55LYGCgcN8TJ0605TICAAAAAAAAQBkItpwcbOl0OkpNTdW8pra4Yuvu3buax8HDC7aqV6/OvWLr22+/delgS6/XI9gCAAAAAAAAcBEIthwUbLm5uVGVKlXI3d2d+beUlBTNa6r1iq2HH35Y6llTMmSu2OIFW+7u7lSlShVyc3NzerCFK7YAAAAAAAAAXAeCLQcFWzqdjgYNGkT79++nvXv30t69eyk+Pp727t1LgwcPpqCgIOrRo4d0e/LJJykoKIhWr16t6FumJSQk0Lfffku9e/emJ5980qpxqLUnnniCpk6dSvv27VPMOy4ujoYMGaKYt16vp9GjRzPzOHToEL344ovcNV2/fr3FecfHx9O+ffuob9++wsHWl19+SV27dlXMpWfPntSgQQMEWwAAAAAAAAAuAsGWA4Otd999l7serVu31tx3fHy8pn2SlZWleQxqbdy4cdxttmvXjql95plnuLXjx4/n9p2ZmSk8x9DQUOFga+rUqZrnjWALAAAAAAAAwL4QbDkw2Bo/fjzTr8FgIB8fH819x8XFadonGRkZVL16dbsEW7xvBywoKCBfX1+mdsCAAdzxjRkzhtv3qVOnhOc4bNgw4WArPDwcwRYAAAAAAACAi0OwhWCLiBBslYVgCwAAAAAAAMD1IdhyYLD15ptvMv0aDAZ6+OGHNfd98OBBTfvk8uXLDg22bt26RY888ghT27dvX+74Ro4cye1b5lbEkJAQ5vWtWrXi1kZERGie96hRo4THBgAAAAAAAADyEGxpDLYefvhhCgoKEmpLlixh+jUYDDR8+HCm1s/PT2qOUf9v725ColrjOI4r2kRQi5CaIgoMTCPBmo7OGZ2BKJNw06KSILCZCMSmVhGRSlG+gNMLJrRpEdpGaGFEqxYFIVRiSlIGgUUUvUCL7MVQaM7/Lu4lsOex+8ydGT3n+v3Ag5v/+T8v56x+nDl2dcnAwMCMMTo6qj3/Fy9eKLU3btyQRYsWKX39fr/x/mzb1oZjumBrampKotGo0uPUqVPaNV+4cEE7Z39/v/G+W1tblev37Nkjd+/eVXrMFqSVlZUZn8fly5e16wAAAAAAAJlBsJVmsHXp0qVsHJGMjY2l/cZQeXm5JJNJpff+/fuNe+jeMpvN1NSUrF692ijYypTCwkJlPsuyjK8fHx+XvLw84/MYGRnJ2l4AAAAAAEBqCLbSDLYSiUQ2jkhGRkbSDrbC4bA22NJ9a2q2cejQIeM1T0xMyKpVq+Y02CouLlbmq6qqMr7++fPnKT1f6f7kEwAAAAAAZA7BVprBVmdnZzaOSIaHh9MOtiKRiDbYqq+vN+4Ri8WM1/z58+c5D7ZKSkq099vU2NiYLF261Pg8Hjx4kLW9AAAAAACA1BBsEWwRbBFsAQAAAADgSa4Ptt69e5d2wFNaWirT09NK70wEW1euXElp747jGNW9fPky7X1v375d2zuVb2xlItg6efKkcQ+dP53Zpk2bCLYAAAAAAFigXB9sffv2TRKJhLS1tUl7e3vKo62tTXp6erLyxlZubq5UV1dLS0uLNDc3/3E0NTXJrVu3lJDGcRzp7u6WpqamGfWHDx+W3NxcbWjz+x47OjqkqKhIqV27dq3St7m5Wc6ePauc5/Hjx7UfUc9EsGVZlnIWp0+flrdv3xr1dRxHbt68qd1LQUEBwRYAAAAAAAuU64OtTNG99ZOJYCuVN6h0IZHjOLJmzRptva7/mTNntPvbtWuX8Tr6+vqU6ycmJsTn82Ul2JptDA0NGfdO5YP3BFsAAAAAACwMCybY0snETxFTGceOHVP6Oo4jpaWlxj1OnDih3cuOHTuMe/T29irXv3r1ak6DrSVLlsiTJ0+Mezc2NhJsAQAAAACAGQi2CLZEhGCLYAsAAAAAAO9xVbB1//79OV1HNBr93wRb1dXVxj2uX7+uXP/69WvJz89XaqPRqPF5fvnyRVauXGm0hsWLF8vo6Khx7yNHjrgi2Hr48KFxbwAAAAAAkF2uCrYGBgbmdB2xWIxg6x9v3rzRftMrlWDr+/fv2o+560Z+fr48e/bMuHc8HndFsDU4OGjcGwAAAAAAZJergq2ioiIJBAJzNnQhjFuCrZKSEhkeHlZGR0eHdi/Lli1TemzZskWGhoaUHvF4XLm+pqZGBgcHldru7m7j8wyHw3Lv3j3tun8fjx49kt27dxv3XrFixZwGW42Njdp179u3T1lbbW2t9r9uAgAAAACA7HJVsOWG4ZZgq7y8XHt258+fN55v27Zt2h4HDhxQav1+v7a2t7fXeD6fzydfv341fg6Ki4uzcg8zEWx1dnZq6wOBgFJbUFAg09PTxnMCAAAAAIDMINhyabAVCAS0Z5dIJIzni0QikkwmlR719fVKbWFhoTacuXbtmvF8y5cvlw8fPhg9Az9+/JCysjLXBlvnzp3T1odCIaV23bp1BFsAAAAAAMwDgi2CLYItgi0AAAAAADxpXoKtrq6ueQ+wZht5eXny8eNHZc137txJu3dDQ4PS13EcWb9+vVK7ceNG7dm1t7cbz2dZljbYqqurU2r9fr82nLl69arxfD6fT96/f2/0DExOTsqGDRuycg+3bt1qtAYRkadPn2p7tLS0aOs3b96s1PJTRAAAAAAA5se8BFv9/f0SDAYlHA5LJBJxzaisrJSamhr59OmTsubHjx+Lbdv/ec0VFRVy8eJFpa/jOHLw4EGxbftXrW3bEovFtGfX19cnlmX963y2bcvRo0eVYMtxHGltbZVgMPirNhQKSV1dnfYD6Ldv3zaar7KyUmpra7VnpzM5OSnRaFRCoVBG72EwGJR4PG60BhGR8fFx2blzp1RVVf3qYVmW9PT0aOsbGhqkoqJixtnt3buXj8cDAAAAADAP5iXYcrufP39mpW8ymRTHcYxqHcfRvm3l9jWY9s7G3lLtn+r+Ujk7AAAAAACQfQRbAAAAAAAA8CSCLQAAAAAAAHgSwRYAAAAAAAA8iWALAAAAAAAAnkSwBQAAAAAAAE8i2AIAAAAAAIAnEWwBAAAAAADAkwi2AAAAAAAA4EkEWwAAAAAAAPAkgi0AAAAAAAB4EsEWAAAAAAAAPIlgCwAAAAAAAJ5EsAUAAAAAAABPItgCAAAAAACAJxFsAQAAAAAAwJMItgAAAAAAAOBJOZKTIzl//wEAAAAAAAA84y/9NdSkbEi88QAAAABJRU5ErkJggg==" alt=""></p>
<p>The only thing developers need to do is to convert the returned URL after sending an authentication/signing order request to BankID, to a QR code and instruct the user to scan it with their mobile BankID, that’s it!</p>
<p>We previously mentioned the autoStartTokenRequired option and its purpose to only allow the device with the autoStartToken to authenticate/sign an order request. This works great if you are using BankID on file on your computer/smartphone or mobile BankID on the same device. However, it will not work if you are using mobile BankID on different devices, since you often initiate the request on your computer and open the mobile BankID app on your phone. The token cannot be created with <em>autoStartTokenRequired = True</em> in this scenario. This is where QR codes shines.</p>
<p>The QR code is just a visual representation of</p>
<div class="gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">bankid://?autostarttoken=463e5661-33a9-4738-ad1e-6c5ef1d732ce&amp;redirect=null</code></pre></div>
<p>Which now means that the user can easily consume the autoStartToken and sign the request.</p>
<p>Which is the ingredient you need to authenticate/sign with BankID. Therefore, when offering to sign with mobile BankID on a different device, <em>autoStartTokenRequired</em> can be set to <em>True</em> if QR codes are used.</p>
<h2>Conclusion</h2>
<p>We have identified three possible flows using BankID</p>
<ul>
<li>BankID on file</li>
<li>Mobile BankID – different device</li>
<li>Mobile BankID – same device</li>
</ul>
<p>To make current phishing attacks against BankID <em>harder</em> to perform, we can do the following:</p>
<ul>
<li>Set <em>certificatePolicies</em> to define which platform an authentication/signing order request should be limited to.</li>
<li>To prevent our mobile BankID app to automatically activate when there is an existing authentication/signing request order present, we can set <em>autoStartTokenRequired = True.</em> Good for BankID on file and mobile BankID on same device.</li>
<li>When using mobile BankID on different devices – set <em>autoStartTokenRequired = True</em> and enable QR codes. The user must scan the QR code presented on the device that initiated the order request.</li>
<li>The user’s personal identity number should always be present for each order request. This limits the effectiveness of simply generating a token and sending it to random people, hoping that someone will sign using the token.</li>
</ul>
<p>None of these features prevents phishing attacks against BankID. They only make today’s attacks harder to perform and requires additional technical skill from the attacker than just being able to call victims. If the attacker can trick a victim into clicking a link containing the autoStartToken, it will be possible to phish BankID users.</p>
<p>However, the point is to make the process more difficult for the attacker, which can be achieved by following the steps above.</p>
<p>BankID API documentation can be found here: <a href="https://www.bankid.com/bankid-i-dina-tjanster/rp-info" target="_self" rel="noopener noreferrer">https://www.bankid.com/bankid-i-dina-tjanster/rp-info</a>.</p>
<p><strong>Bonus question:</strong> <em>Can you find the open redirection in the token URL? :)</em></p>]]></description><link>https://kits.se/blogg-2019-05-13/bankid-anyone</link><guid isPermaLink="false">https://kits.se/blogg-2019-05-13/bankid-anyone</guid><dc:creator><![CDATA[Michael Dubell]]></dc:creator><pubDate>Mon, 13 May 2019 00:00:00 GMT</pubDate></item><item><title><![CDATA[Gakuseiprojektet]]></title><description><![CDATA[<p>KITS anställer en del personer som har talang, men kanske inte så mycket erfarenhet. När vi gör det, tar vi också på oss ett ansvar, att se till de utvecklas. Som konsultbolag med höga krav på oss själva, är det lätt att intala sig att vi bara kan anställa erfarna personer, för det är det enda som går att sälja. Vi har valt att tänka tvärtom. KITS kan ta ett ansvar, och utan att det är en uppoffring. Juniorer är en frisk fläkt, och det behövs om vi ska fortsätta utvecklas, och de insatser vi gör för att utveckla juniorer, utvecklar också oss lite mer erfarna.</p>
<p>Hösten 2016 föreslog jag, i den andan, att våra juniorkonsulter skulle ta sig an en app för japanskainlärning. Utvecklingen har skett som ett “riktigt” projekt, där slutmålet, en webbapp, är viktigare än att deltagarna utvecklas. D v s det har inte varit ett projekt för att lära upp juniorkonsulter, utan ett projekt för att ta fram en app för japanska, och projektmedlemmarna kan inte undvika att lära sig mycket, trots, eller snarare, tack vare, att lärande inte är i fokus.</p>
<p>Projektet har körts i fyra omgångar men tar nu ett uppehåll och det är dags att summera. Hur har det gått?</p>
<!-- more -->
<h2>Bakgrund till projektet</h2>
<p>Våren 2016 började jag läsa japanska på Göteborgs Universitet, och började leta efter appar som stöd för min inlärning. Det finns ganska många olika appar och webbsidor för språkinlärning, men de är oftast inte anpassade för japanska, med sitt komplicerade skriftsystem. Dessutom fanns inga alternativ om man vill lära sig från svenska till japanska, åtminstone inga som jag kunde hitta.</p>
<p>Som svenskar har vi en stor tillgång i att de flesta av oss kan prata två språk ganska bra, engelska och svenska, och de flesta av oss har lärt oss grunderna i fler språk. I japansk undervisning utnyttjas det mest genom att engelsk litteratur används istället för att ta fram svenska alternativ. Jag tror att det ändå är bättre om man lär sig japanska direkt från svenska. Det blir en onödig extra kognitiv belastning att gå via engelska. Engelskakunskapen skulle däremot kunna utnyttjas som förstärkning och precisering. Ett konkret exempel: Sumu är ett verb som kan översättas till live på engelska eller att bo på svenska, och genom att lära sig båda översättningarna får man en bättre förståelse för vad sumu egentligen betyder.</p>
<p><img src="/assets/blogg_gakusei-1.svg" alt=""></p>
<p>Det här var inspirationen till appen Gakusei. Målet mer specifikt är att appen ska vara ett stöd för svenska studenter som läser japanska på ett universitet. Ingående komponenter skulle kunna vara t ex glosförhör, grammatikövningar, skrivövningar, men också mer generella saker, som statistikinsamling och lärarstöd. Webbappen ska vara <a href="https://github.com/kits-ab/gakusei" target="_self" rel="noopener noreferrer">open source</a>.</p>
<h2>Utveckling</h2>
<p>Teknikstacken ser ut som något vi skulle kunna stöta på hos våra kunder, en traditionell backend med en lite nyare fronted. Spring Boot och React landade vi i, men det hade lika gärna kunnat vara t ex JEE och Angular. Mestadels har vi använt Scrum. Inget konstigt för en it-konsult med andra ord.</p>
<p>Första kullen färdigställde de första versionerna med bl a glosförhör, inloggning, statistikinsamling, talsyntes, flashcards, teckeninlärning. I februari 2017 visade vi upp Gakusei för lärare och studenter på Göteborgs Universitet, vilket skapade intresse för appen vid Göteborgs Universitet, Högskolan i Dalarna, och Hvitfeldtska Gymnasiet.</p>
<p>Gakusei har ända sedan 2017 varit öppet för vem som helst att använda, och lärare och studenter har testat och kommit med värdefull feedback. Dock har jag hittills varit den enda fasta användaren, och andra kullen arbetade mycket med driftsfrågor, samt att ta bort hinder för att använda Gakusei. T ex gjordes förstasidan om från början, HTTPS infördes, och servrarna konfigurerades med automatisk backup. Dessutom togs ett administrationsverktyg för dataredigering fram.</p>
<p><img src="/assets/blogg_gakusei-2.png" alt=""></p>
<p>Arbetet fortsatte våren 2018 med nytt utseende på lektionssidorna, och smart inlärning (spaced repetition). Teckeninlärningen gjordes om så att den gick att använda i praktiken, tidigare hade den varit för otillförlitlig. Så till sommaren hade vi en applikation som var konkurrenskraftig men fortfarande lite för buggig.</p>
<p><img src="/assets/blogg_gakusei-3.png" alt=""></p>
<p>Den fjärde kullen har fokuserat på att förbättra stabilitet och utseende. Några kända buggar återstår, men i stora drag känns grundfunktionaliteten väldigt stabil. Vi har också gjort analysverktyg m h a ELK-stacken, som vi ska använda för att finjustera inlärningsfunktioner, hitta problemområden och så vidare. Parallellt med detta har jag skapat data, ord- och kanjilistor m m, och idag täcker vi de tre första terminerna ganska väl.</p>
<h2>Resultat</h2>
<p>Jag tycker att Gakusei nu är konkurrenskraftigt jämfört med de vanligaste engelskspråkiga alternativen och en app vi kan vara stolta över.</p>
<p>Hur har det då fungerat som inkörsport till arbetslivet? Förvånansvärt bra, projektmedlemmarna har fått erfarenhet och självförtroende.</p>
<blockquote>
<p>Gakusei var ett perfekt projekt för mig som var ny på arbetsmarknaden. Det var skönt att på ett prestigelöst sätt få lära mig hur det är att jobba i ett riktigt projekt tillsammans med andra som befann sig i samma situation. Dessutom så fick jag direkt nytta av de ramverk som Gakusei använder då samma teknikstack användes på mitt första uppdrag</p>
<p><em>Joakim Danielsson</em></p>
</blockquote>
<p>Nu avslutar vi Gakusei-projektet och Kits lämnar över produkten Gakusei till mig för vidareutveckling och förvaltning. Kommer Gakusei att bli en produkt att räkna med framöver? Det återstår att se, men det finns en stabil grund att stå på, och jag har stora förhoppningar om framtiden!</p>
<blockquote>
<p>Gakusei var ett bra projekt att jobba i där man fick använda tekniker man hade tittat på under utbildningen i ett större sammanhang</p>
<p><em>Joella Johannesson</em></p>
</blockquote>
<p>Vi har kört fyra vändor hittills, och det hade vi förstås inte gjort om det inte hade fungerat, och vi fortsätter med konceptet nu i vår, men med en ny produkt. Håll utkik efter LogLady, ett nytt verktyg för programmerare!</p>
<p>Gakusei finns på <a href="https://gakusei.daigaku.se" target="_self" rel="noopener noreferrer">https://gakusei.daigaku.se</a><br>
Följ utvecklingen av LogLady på <a href="https://github.com/kits-ab/LogLady" target="_self" rel="noopener noreferrer">https://github.com/kits-ab/LogLady</a></p>]]></description><link>https://kits.se/blogg-2019-02-28/gakusei</link><guid isPermaLink="false">https://kits.se/blogg-2019-02-28/gakusei</guid><dc:creator><![CDATA[Pierre Sandboge]]></dc:creator><pubDate>Thu, 28 Feb 2019 00:00:00 GMT</pubDate></item><item><title><![CDATA[Over-engineering a booth competition]]></title><description><![CDATA[<p>During <a href="https://securityfest.com/" target="_self" rel="noopener noreferrer">Security Fest 2018</a> we decided to build a competition the only way we know how: by over-engineering it! We started by buying a ball maze. We also recently saw that 8Bitdo had released their new SN30 controller and we wanted an excuse to buy one … maybe we can control the ball maze with it? So of course, we had to auto-<strong>maze</strong> the game and play it using a controller!</p>
<!-- more -->
<h6><img src="/assets/blogg_ballmaze-1.jpg" alt=""><img src="/assets/blogg_ballmaze-2.jpg" alt=""><img src="/assets/blogg_ballmaze-3.jpg" alt=""></h6>
<h2>Ball mazeing for dummies</h2>
<h3>Controlling</h3>
<p>We broke out the 3D-printer, modified some stepper stands (creative commons, made by adamyelland <a href="https://www.thingiverse.com/thing:1938710" target="_self" rel="noopener noreferrer">download drawing</a>), bought some servos (Luxorparts S3003) and got to soldering!
We attached the whole thing to a Raspberry Pi 3 which in turn steered the servos and listened to the NS30 over Bluetooth (using python, following this <a href="https://core-electronics.com.au/tutorials/using-usb-and-bluetooth-controllers-with-python.html" target="_self" rel="noopener noreferrer">guide</a>).</p>
<p>At first, we wanted to use the gyro function to steer how much the servos should move but for some reason we never got it to work…</p>
<p>So, we moved on to using the sticks. Left stick for up/down, right one for left/right. It was not the most natural way to steer so the first couple of times playing most struggled slightly, just as intended!
The last piece of our over-engineering was how to time each race from start to either finish or failure.</p>
<h3>Detecting the ball and measure time and length of the game</h3>
<p>We opted for a webcam that kept track of the ball as it moved through the maze, giving points for each zone cleared and ending the game when it lost sight of the ball.
Recognizing objects using computer vision is a somewhat mystified process. Similar to how a person who is not a programmer perceives how applications are made, even a programmer may find that they don’t have a clue on what actually happens to “recognize” things using a camera and some code.</p>
<p>One way of doing video/picture analysis is using machine learning, for example Googles TensorFlow. You take a picture (or video stream), feed it to a “magical tool”, and out comes data saying what it is, and perhaps also <em>where</em> it is on the picture.</p>
<p>We went for a more special purpose solution using OpenCV.</p>
<p>OpenCV is an open source computer vision library, written mostly in C++, it effectively allows you, as a developer, to modify an image as much as it lets you measure things. The steps we took was:</p>
<ul>
<li>Modify: Capturing the source picture and shrinking it to a smaller resolution.</li>
<li>Modify: Removing all the Blue and Green in a picture, keeping only the Redness.</li>
<li>Modify: Replacing a range of redness with a single, solid, red color.</li>
<li>Measure: Get all matching pixels where neighboring pixels are also red.</li>
<li>Measure: Finding the biggest source of red by applying regular programming arithmetic.</li>
</ul>
<p>While the example above is intentionally convoluted, the reality is that <em>this</em> is how we detected the ball in the maze. :-)</p>]]></description><link>https://kits.se/blogg-2018-08-29/ballmaze</link><guid isPermaLink="false">https://kits.se/blogg-2018-08-29/ballmaze</guid><dc:creator><![CDATA[Tobias Lans, William Bernting]]></dc:creator><pubDate>Wed, 29 Aug 2018 00:00:00 GMT</pubDate></item><item><title><![CDATA[Summary of Apple Worldwide Developers Conference 2018]]></title><description><![CDATA[<p>Every year Apple invites the community to their Worldwide Developers Conference and even though 6 000 developer gets to go every year it’s really hard to get a ticket. For me it took six attempts but I finally got one and it was worth the wait.</p>
<p>In a five day conference there are a lot of topics covered. There where over 100 sessions and even more labs where you could actually get access to over 1 000 Apple engineers. I managed to go to about a quarter of the sessions and visit a handful of labs and in this post I’ll try to summarize my impressions, talk about how it may effect us developers and link to the best talks.</p>
<!-- more -->
<h6><img src="/assets/blogg_wwdc-2018-1.jpg" alt=""><img src="/assets/blogg_wwdc-2018-2.jpg" alt=""><img src="/assets/blogg_wwdc-2018-3.jpg" alt=""></h6>
<h2>Machine Learning and Augmented Reality</h2>
<p>Last year Apple introduced Core ML and ARKit and to be honest I was not really that interested. ARKit lacked a lot of stuff and you still had to train your machine learning models using other tools before you could take advantage of Core ML. After this year’s talks though, I’m really impressed.</p>
<p>The first piece of the puzzle is Create ML, a simple way to to augment prebuilt models from Apple with your own custom data. You can use images, text or tabular data and it’s ridiculously easy to get started. For images you can start by putting a lot of images of apples in a folder called apple, oranges in a folder called orange and bananas in a a third folder. Then you can use Swift Playgrounds to pass the images to Create ML or just write a simple script like this:</p>
<div class="gatsby-highlight" data-language="swift"><pre class="language-swift"><code class="language-swift">#<span class="token operator">!/</span>usr<span class="token operator">/</span>bin<span class="token operator">/</span>swift
<span class="token keyword">import</span> <span class="token class-name">Foundation</span>
<span class="token keyword">import</span> <span class="token class-name">CreateML</span>

<span class="token comment">// Specify Data</span>
<span class="token keyword">let</span> trainDirectory <span class="token operator">=</span> <span class="token function">URL</span><span class="token punctuation">(</span>fileURLWithPath<span class="token punctuation">:</span> “<span class="token operator">/</span><span class="token class-name">Users</span><span class="token operator">/</span><span class="token class-name">Joakim</span><span class="token operator">/</span><span class="token class-name">Desktop</span><span class="token operator">/</span><span class="token class-name">Fruits</span>“<span class="token punctuation">)</span>
<span class="token keyword">let</span> testDirectory <span class="token operator">=</span> <span class="token function">URL</span><span class="token punctuation">(</span>fileURLWithPath<span class="token punctuation">:</span> “<span class="token operator">/</span><span class="token class-name">Users</span><span class="token operator">/</span><span class="token class-name">Joakim</span><span class="token operator">/</span><span class="token class-name">Desktop</span><span class="token operator">/</span><span class="token class-name">TestFruits</span>“<span class="token punctuation">)</span>

<span class="token comment">// Create Model</span>
<span class="token keyword">let</span> model <span class="token operator">=</span> <span class="token keyword">try</span> <span class="token class-name">MLImageClassifier</span><span class="token punctuation">(</span>trainingData<span class="token punctuation">:</span> <span class="token punctuation">.</span><span class="token function">labeledDirectories</span><span class="token punctuation">(</span>at<span class="token punctuation">:</span> trainDirectory<span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token comment">// Evaluate Model</span>
<span class="token keyword">let</span> evaluation <span class="token operator">=</span> model<span class="token punctuation">.</span><span class="token function">evaluation</span><span class="token punctuation">(</span>on<span class="token punctuation">:</span> <span class="token punctuation">.</span><span class="token function">labeledDirectories</span><span class="token punctuation">(</span>at<span class="token punctuation">:</span> testDirectory<span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token comment">// Save Model</span>
<span class="token keyword">try</span> model<span class="token punctuation">.</span><span class="token function">write</span><span class="token punctuation">(</span>to<span class="token punctuation">:</span> <span class="token function">URL</span><span class="token punctuation">(</span>fileURLWithPath<span class="token punctuation">:</span> “<span class="token operator">/</span><span class="token class-name">Users</span><span class="token operator">/</span><span class="token class-name">Joakim</span><span class="token operator">/</span><span class="token class-name">Desktop</span><span class="token operator">/</span><span class="token class-name">FruitClassifier</span><span class="token punctuation">.</span>mlmodel“<span class="token punctuation">)</span><span class="token punctuation">)</span></code></pre></div>
<p>Now you got a trained model that you can drag into your project and you are ready to recognize fruits in your images. Text and tabular data can be trained in the same way. I can think of a lot of cases where this could have improved previous projects I’ve been involved in and I hope I’ll get to use it in the future.</p>
<p>With machine learning in place we can turn to an application of machine learning and that is augmented reality. Apple introduced ARKit last year and this year they added image, face and object tracking which means you can both recognize these in the real world and track them around as they move. You should really check out <a href="https://developer.apple.com/videos/play/wwdc2018/602" target="_self" rel="noopener noreferrer">this video</a> to understand how it works but I was able to try this for myself and it’s actually really nice.</p>
<p>They also added support for persisting the AR world as you build it and support for multiple users in the same world which makes it possible to create really fun experiences. At WWDC they ran an AR tournament around the game SwiftShot. The entire game is open source so you can <a href="https://developer.apple.com/documentation/arkit/swiftshot_creating_a_game_for_augmented_reality" target="_self" rel="noopener noreferrer">download</a> it to play or learn more.</p>
<h3>Universal Scene Descriptions</h3>
<p>If games and object recognition is not your thing, how about shopping for bags online and actually being able to put it on your back to see how it looks? That will not be so hard to do in the future.</p>
<p>If, in addition to an image of the bag, you create your bag as an AR scene you can now store this in a <code class="language-text">.usdz</code> file. This is an open file format that Apple created in collaboration with Pixar. When you’ve created this file you can link to it, just as as you normally do on the web, and users can click on it to show the bag in the augmented real world and do whatever they want with it.</p>
<p>Creating these scenes will obviously be quite hard but Adobe showed a preview of <a href="https://www.adobe.com/products/projectaero.html" target="_self" rel="noopener noreferrer">project Aero</a> that will make this much easier.</p>
<p>This may have been one of the least appreciated announcements this year and whenever you create your next e-commerce solution I will call it a fail if it doesn’t include AR.</p>
<h2>Siri Shortcuts</h2>
<p>Building on the Machine Learning theme shortcuts provide a way for developers to surface actions that a user do frequently to Siri to let Siri learn the behaviour of the user. With this knowledge Siri can surface these actions as shortcuts on the lock screen, in spotlight or in the Siri watch face on the Apple Watch as they become relevant (based on time, location and user behaviour). Contrary to other companies, Apple doesn’t collect this data on their servers and instead it all happen on-device and to me this makes it much less creepy but to be honest, probably not as good.</p>
<p>These shortcuts can also be triggered by voice if the user assigns a trigger phrase to them. This trigger phrase can even be used on CarPlay or the HomePod. This finally opens Siri to all developers which is really good. Unfortunately the trigger phrases are static so we can’t pass parameters the same way we can to Alexa for instance and this makes this feature way less attractive but it’s a first step and I would not be surprised to see this added in a future release.</p>
<p>If your app already uses <code class="language-text">NSUserActivity</code> you can expose it to Siri shortcuts by simply setting <code class="language-text">userActivity.isEligibleForPrediction = true</code> and if you want more control and the ability to run the commands using your voice in the background you can use the more advanced intent api.</p>
<p>Finally there is a Shortcuts app that can tie all of these shortcuts together. The shortcuts can be scripted, combined with calls to web services and we can even assign a trigger phrase to them. This means that for the first time since the iPhone was introduced, we finally have built-in automation on iOS!</p>
<h2>Notifications</h2>
<p>In the keynote Apple showed grouped notifications and got huge applause. The changes to the notification system was much bigger though, it really got a complete overhaul. Notifications can now be more dynamic, have custom actions and if the notification provides a custom UI, using content extensions, it can now be fully interactive. This means that if a user receives an offer as a push notification the user can now interact with that notification and choose what to do with the offer right there without opening the app.</p>
<p>Apple is also making it way easier to manage notifications as the user receives them. This means that the user will now be able to turn notifications off right from the notification so if you abuse the system, by sending too many or irrelevant notifications, I’m pretty sure that user engagement will go down over time.</p>
<h2>Performance, performance, performance</h2>
<p>Performance really was the theme of the conference and if you run the beta you will not be disappointed. You can really see that the platforms have grown up and you don’t have to focus on how to put stuff on the screen anymore and instead you can focus on how to do it really really fast. This includes everything from the network stack up to scrolling in table views, from persistence in Core Data to how image assets are compressed.</p>
<p>I learned so many great tricks and this really is where native development shines. I’ve never been a fan of cross platform tools such as Electron or React Native and this is one reason. I realize that in many situations this doesn’t really matter but if you want to make your product the best it can be, there really aren’t any choice.</p>
<h2>The conference</h2>
<p>Besides the big stuff there obviously was a lot of “small” stuff as well. NFC for Wallet Passes, a new Mac App Store, Dark Mode for macOS, a sneak peek of UIKit running on macOS, WebKit running on the Apple Watch and a whole lot more.</p>
<p>To summarize, I was really impressed with both the content of the conference and the conference itself. The organization around the keynote was a mess but besides that, everything worked great.</p>
<p>There where a lot of great sessions but these are my favorites:</p>
<ul>
<li><a href="https://developer.apple.com/videos/play/wwdc2018/602" target="_self" rel="noopener noreferrer">What’s New in ARKit 2</a></li>
<li><a href="https://developer.apple.com/videos/play/wwdc2018/803" target="_self" rel="noopener noreferrer">Designing Fluid Interfaces</a></li>
<li><a href="https://developer.apple.com/videos/play/wwdc2018/102" target="_self" rel="noopener noreferrer">Platforms State of the Union</a></li>
<li><a href="https://developer.apple.com/videos/play/wwdc2018/207" target="_self" rel="noopener noreferrer">Strategies for Securing Web Content</a></li>
<li><a href="https://developer.apple.com/videos/play/wwdc2018/230" target="_self" rel="noopener noreferrer">Deliver an Exceptional Accessibility Experience</a></li>
</ul>
<p>After visiting a few labs I realize, what everyone have been telling me, that this is the real benefit of the conference and I kind of regret not going to more but I guess I can do that the next time I’ll get to go in six years. I really hope it won’t take that long though, because as an Apple fan, this was without a doubt the best conference experience I’ve ever had and I wish can can go next year.</p>]]></description><link>https://kits.se/blogg-2018-06-26/wwdc</link><guid isPermaLink="false">https://kits.se/blogg-2018-06-26/wwdc</guid><dc:creator><![CDATA[Joakim Kemeny]]></dc:creator><pubDate>Tue, 26 Jun 2018 00:00:00 GMT</pubDate></item><item><title><![CDATA[Going serverless, an introduction]]></title><description><![CDATA[<p>What if I told you that you can get an API up and running in a couple of minutes. What if I told you that the deployed application will be running in both a development and a production environment where scaling is a non issue and where you only pay when your application is actually being used. Doesn’t that sound pretty great? This is the promise of serverless architectures.</p>
<p>For the last year I’ve been working on a project where we use this kind of architecture to create an IoT platform and not only have this made backend development fun for me again but it have fundamentally changed how I think about creating software. In a series of posts I’m going to take you through the experience of building a full application. Let’s start with an introduction.</p>
<!-- more -->
<h2>What is serverless?</h2>
<p>First of all, serverless is a really bad name. Not only because it both describes an architectural pattern, a specific framework and the company that makes that framework but also because it’s not even true. There is of course always a server somewhere so maybe serveradministrationless would be a better name but that’s not as catchy so let’s stick with serverless for now.</p>
<p>I don’t think there’s a strict definition of what serverless is and there have definitely been several services in the past that you might call serverless but what really caused serverless to take of was when people started using the term to talk about “Functions as a Service”. The idea is that as a developer you should have full control of the code behind your application but that is all you need to worry about. How the functions are actually executed is not important. Just focus on creating beautiful code and it will be run and scaled for you automatically.</p>
<p>A typical serverless function can look like this:</p>
<div class="gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript">module<span class="token punctuation">.</span>exports<span class="token punctuation">.</span><span class="token function-variable function">hello</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">event<span class="token punctuation">,</span> context<span class="token punctuation">,</span> callback</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> response <span class="token operator">=</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">statusCode</span><span class="token operator">:</span> <span class="token number">200</span><span class="token punctuation">,</span>
    <span class="token literal-property property">body</span><span class="token operator">:</span> <span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">stringify</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
      <span class="token literal-property property">message</span><span class="token operator">:</span> <span class="token string">"Hello World! You're awesome!"</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span>
  <span class="token punctuation">}</span>

  <span class="token function">callback</span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">,</span> response<span class="token punctuation">)</span>
<span class="token punctuation">}</span></code></pre></div>
<p>If you can see through the weirdness of JavaScript this looks like a normal function that returns a Hello world message, why is this such a big deal?</p>
<p>As I hope this series will show you this turns out to be a great way to structure your application but what’s even better is that when you deploy this function it will cost you absolutely nothing until it’s actually used. If your service suddenly gains traction and gets widely popular it will scale automatically so all requests will be served super fast and you will only pay for the actual execution time.</p>
<p>Still not convinced? Let’s try it for real to give you an idea of what to expect.</p>
<h2>Getting started</h2>
<p>Just as pretty much every cloud provider has its own solution for running containers, many of them are starting to gain support for serverless architectures. I’ll get back to this in a later post but for now I’ll be focusing on AWS’ implementation called Lambda just because it’s the most mature solution and it also happens to be the one that I’ve been working with for the last year.</p>
<h3>Preparations</h3>
<p>Before we start you need to prepare a few things. You need to install <a href="https://nodejs.org/en/download" target="_self" rel="noopener noreferrer">Node.js</a> version 4 or or later. You can write your code using other languages as well but the tool that we are going to use requires Node.js. You also need an <a href="https://aws.amazon.com" target="_self" rel="noopener noreferrer">AWS</a> account. There is a free tier available for AWS and since Lambda is included in this you can do a lot before you need to pay any money.</p>
<p>The final step is to acquire the access key to AWS to deploy your functions. You should probably create a separate account and limit its permissions but to keep things simple we are going to use your root credentials (see <a href="https://serverless.com/framework/docs/providers/aws/guide/credentials" target="_self" rel="noopener noreferrer">this guide</a> if you don’t want to do that). The access key can be found if you login, choose <strong>My Security Credentials</strong> from the top right menu. Choose <strong>Access Keys</strong> and <strong>Create New Access Key</strong>. Save this information, you will need it later.</p>
<h3>Serverless, the framework</h3>
<p>Now that we’re prepared, we can start creating our application. If you’re impatient, you can login to the AWS console, go to <strong>Lambda</strong>, choose <strong>Create a Lambda function</strong>, click through the wizard and paste the code above. Press <strong>Save and Test</strong> and it will run. That’s cool but not a very practical way of writing real applications so for this series I’m going to use a framework called <a href="https://serverless.com" target="_self" rel="noopener noreferrer">Serverless</a>.</p>
<p>Run the following command to install it:</p>
<div class="gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell"><span class="token function">npm</span> <span class="token function">install</span> <span class="token parameter variable">-g</span> serverless</code></pre></div>
<p>Now you need to allow Serverless to access your AWS account. Run the following command but substitute <code class="language-text">&lt;YOURKEY></code> and <code class="language-text">&lt;YOURSECRET></code> with the credentials you saved earlier.</p>
<div class="gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">serverless config credentials <span class="token parameter variable">--provider</span> aws
	<span class="token parameter variable">--key</span> <span class="token operator">&lt;</span>YOURKEY<span class="token operator">></span> <span class="token parameter variable">--secret</span> <span class="token operator">&lt;</span>YOURSECRET<span class="token operator">></span></code></pre></div>
<p>Now you’re ready to create your first project. I’ll be using the template <code class="language-text">nodejs</code> in these posts but you can use <code class="language-text">python</code>, <code class="language-text">java-gradle</code>, <code class="language-text">java-maven</code>, <code class="language-text">scala-sbt</code> or <code class="language-text">csharp</code> if you want to. To create a project in the current folder run the following command:</p>
<div class="gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">serverless create <span class="token parameter variable">--template</span> aws-nodejs</code></pre></div>
<p>This will create a normal Node.js project and install its dependencies. The interesting parts can be found in <code class="language-text">handler.js</code> that contains the actual function that we want to run and the file <code class="language-text">serverless.yml</code> that contains the configuration that tells AWS how to deploy the function and how to trigger it. How should the function be triggered?</p>
<h3>Events</h3>
<p>Even if functions are the heroes of serverless architectures they still need to be triggered somehow. The trigger can be a lot of things; a message on a queue, an event from an IoT device or maybe another function. I’ll get back to these in a later post but for now we are going to use a normal HTTP request to trigger the function.</p>
<p>Open the file <code class="language-text">serverless.yml</code> and locate the events section. Uncomment the following lines to instruct AWS to setup API Gateway to provide the GET endpoint <code class="language-text">/hello</code> that calls the function.</p>
<div class="gatsby-highlight" data-language="yaml"><pre class="language-yaml"><code class="language-yaml"><span class="token key atrule">events</span><span class="token punctuation">:</span>
  <span class="token punctuation">-</span> <span class="token key atrule">http</span><span class="token punctuation">:</span>
      <span class="token key atrule">path</span><span class="token punctuation">:</span> hello
      <span class="token key atrule">method</span><span class="token punctuation">:</span> get</code></pre></div>
<p>Next let’s deploy and run this.</p>
<div class="gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">serverless deploy</code></pre></div>
<p>This will take a couple of minutes since it creates a new stack on AWS and deploys the function. The next deployment will be much faster.</p>
<p>Now open a browser and paste the url from output into a browser. Congratulations, you’ve just created and deployed your first serverless service and exposed it to the world on an HTTP endpoint.</p>
<h3>What just happened?</h3>
<p>Let’s dive into what happened. Serverless created a new stack for you in your AWS account. A stack is like an environment and since you can have multiple stacks you can create one for development, one for testing and one for production or why not one stack for each pull request. Next it deployed the function as a Lambda and configured API Gateway so that when you call the GET endpoint it calls the Lambda. It also created the neccessary roles for the services to communicate with each other.</p>
<p>Serverless doesn’t have a magic wand to do this, instead it uses CloudFormation which is the solution that AWS provides to automate deployments. CloudFormation is quite complicated though so Serverless makes this much easier.</p>
<p>You can deploy your code to a new stack by adding the <code class="language-text">--stage</code> parameter (the default stack is dev).</p>
<div class="gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">serverless deploy <span class="token parameter variable">--stage</span> prod</code></pre></div>
<p>After you run this command your AWS environment will look like this.</p>
<p><img src="/assets/blogg_serverless-1-aws.png" alt="AWS Image"></p>
<p>That’s it. Now you are ready to develop your application. If you want you can call the Lambda from the command line using <code class="language-text">serverless invoke --function hello</code> and if you want to see the logs that it produces you can add a console.log statement to the handler, deploy it run it and then call <code class="language-text">serverless logs --function hello</code>. When your application grows you can deploy a single function using <code class="language-text">serverless deploy function --function hello</code>.</p>
<h2>Where to go from here?</h2>
<p>This was an introduction to serverless architectures and the Serverless framework and even though we’ve just created a service that scales automatically, that only costs when it’s invoked it is still a really boring application. In the following posts I’ll be showing you where to go from here. How to structure your application, how to add a web frontend to it and maybe connect it to some real devices as well. Stay put for more.</p>]]></description><link>https://kits.se/blogg-2017-02-06/serverless-1</link><guid isPermaLink="false">https://kits.se/blogg-2017-02-06/serverless-1</guid><dc:creator><![CDATA[Joakim Kemeny]]></dc:creator><pubDate>Mon, 06 Feb 2017 00:00:00 GMT</pubDate></item><item><title><![CDATA[What makes responsive design work]]></title><description><![CDATA[<p>In this brief introduction I would like to give you an understanding of the mechanisms that make responsive web design possible. I aim not to go into unnecessary details, but to explain concepts at a level web developers can benefit from. I also would like to mention that browsers do things differently, especially in the free land of Android, but this short text has no room for handling inconsistencies between browsers since that is a entire story itself.</p>
<!-- more -->
<h2>First off, what is a web browser?</h2>
<p>A web browser is a computer program which lets the user view and interact with web pages. Technically, a browser (i.e. Google Chrome or Firefox) is of a computer program that runs natively on the current operating system. That program handles things like window management, tabs, bookmarks and more. It also uses a “rendering engine” to calculate what should be shown in the greater part of the interface. The browser is provided a url (usually the user writing in the address bar or clicking a link) which it passes to the rendering engine along with a surface that is used to paint the interface on.</p>
<p>Historically browsers tend to do the rendering task somewhat different. Which is a subject of its own, but let’s stick to the subject and move on.</p>
<h2>Responsive web design</h2>
<p>Responsive web design is, <a href="https://en.wikipedia.org/wiki/Responsive_web_design" target="_self" rel="noopener noreferrer">according to Wikipedia</a> “an approach to web design aimed at crafting sites to provide an optimal viewing and interaction experience — easy reading and navigation with a minimum of resizing, panning, and scrolling—across a wide range of devices (from desktop computer monitors to mobile phones)“. The practical translation for a web developer is that we want complete control of the screen area and the interface we put on it has to have the right size for interaction and viewing.</p>
<p>But mobile and desktop screens have different size and ratio and they have different types of input devices. This implies that interfaces need to be customized for the target screen and input device.</p>
<h2>Show me the code</h2>
<p>Let’s dive right in and look at some code. Assume the following markup and styling for a web page:</p>
<div class="gatsby-highlight" data-language="html"><pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>html</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>head</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>style</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>text/css<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token style"><span class="token language-css">
      <span class="token selector">#something</span> <span class="token punctuation">{</span>
        <span class="token property">width</span><span class="token punctuation">:</span> 35%<span class="token punctuation">;</span>
        <span class="token property">background-color</span><span class="token punctuation">:</span> red<span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
    </span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>style</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>head</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>body</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>something<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">></span></span>Hello<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>body</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>html</span><span class="token punctuation">></span></span></code></pre></div>
<p>This will result with the div #something to have the width of 35% of the parent element, <code class="language-text">&lt;body></code>. The <code class="language-text">&lt;body></code> element will take up 100% of the width of the <code class="language-text">&lt;html></code> element. Then what, how wide is the <code class="language-text">&lt;html></code> element?</p>
<h2>The viewport</h2>
<p>The uppermost building block of a web layout is called the viewport. It’s what contains the <code class="language-text">&lt;html></code> element. It’s the outer limits for the rendering engine to work with.</p>
<p>When dealing with responsive web design, control of the viewport is what really enables us to produce interfaces for all screen sizes.</p>
<p><strong>Let’s invent the mobile internet</strong></p>
<p>Image you have the task to make internet work nice on mobile screens. There are neither previous mobile browsers nor web pages optimized for mobility. To make the “mobile internet” gain any popularity, it surely needs to work with every existing web page out there, or at least close to. So before even trying to make responsive web design, we need to address existing content first.</p>
<p><strong>How existing web pages work</strong></p>
<p>Web pages are styled using fixed pixel sizes, percentage expressions and other measurements. Consider a menu on the side of the page which is styled using a percentage width. On a mobile screen that might end up in such a narrow band that none of the text fits. (You may notice that I omit ‘height’, that is because the height of a web page is most often variable and is not as important when dealing with responsive design as the width.)</p>
<p>On mobile the rendering engine needs to believe that the target area is more pixels wide than it physically is. So the interface gets painted to more pixels than the phone has. The canvas is then zoomed out to show the complete interface on the screen.</p>
<p><img src="/assets/blogg_responsive-iphone.jpg" alt="iPhone"></p>
<p>As you might have guessed, we need to tamper with the viewport. The viewport would logically get the width of the mobile browser, thus the physical width of the mobile device. But it is not, it gets another width decided by the creator of the browser. This width differs between browsers and device vendors, but span 768-1024px. If a mobile browser tells the rendering engine that it is 980px wide it will render the example #something div 35% of 980px = 343px wide. The interface drawn for 980px will then be zoomed out to fit the mobile device. This way existing web pages will render correctly to mobile browsers, but we haven’t yet touched any responsive behavior.</p>
<p><strong>A note on higher resolutions</strong></p>
<p>Recent models of computer screens and mobile devices often have higher resolution than prior models. More dense pixels would logically end up in interfaces being drawn at smaller sizes than before. But we know that they are not, web pages didn’t shrink to half the size when the Mac got its retina display. The abstraction we look for is called devicePixelRatio.</p>
<p>Try and type in <code class="language-text">devicePixelRatio</code> to your browser developer console, what comes out? On recent Macbooks it says 2, on older it says 1. It can be any fractional number though. This is a number that affects the width communicated to the rendering engine. For a screen that has a devicePixelRatio = 2 the number of physical pixels gets divided by 2 before going in to the rendering engine. That way a browser that takes up 1400 physical pixels only communicate 1400 / 2 = 700px to the rendering engine. That’s why CSS that targets 700px gets interpreted the same way without you having to manually deal with screen resolutions.</p>
<p>Imagine some years from now, where no device have devicePixelRatio = 1 any more. It will be weird to write CSS targeting pixel sizes that no device have.</p>
<h3>What sets mobile apart from desktop?</h3>
<p>Let’s introduce some proper names for the things we’ve just talked about. On a desktop browser there is the <code class="language-text">viewport</code>, which has the same width as the browser window, (although altered at higher resolutions). On mobile though it’s slightly more complicated.</p>
<p><img src="/assets/blogg_responsive-desktop.png" alt="Desktop viewport"></p>
<p><strong>Layout, visual and ideal viewport</strong>
The rendering engine operates on what’s called the <code class="language-text">layout viewport</code> and the physical pixels of the device makes the <code class="language-text">visual viewport</code>, (The media queries we declare in CSS targets the layout viewport).</p>
<p><img src="/assets/blogg_responsive-layout.png" alt="Layout viewport"></p>
<p>The third and last viewport, the <code class="language-text">ideal viewport</code>, is an abstract notion of the best layout viewport for a particular device. The ideal viewport might as well be <code class="language-text">physical pixels / devicePixelRatio</code>, but in many cases it differs slightly from that. Luckily the developer has an easy way of using the ideal viewport:</p>
<div class="gatsby-highlight" data-language="html"><pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>meta</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>viewport<span class="token punctuation">"</span></span> <span class="token attr-name">content</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>width=device-width,initial-scale=1<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span></code></pre></div>
<p>This declaration is the meta viewport tag and it goes inside of the <code class="language-text">&lt;head></code> section of the HTML. The <code class="language-text">width=device-width</code> command tells the rendering engine to use the ideal viewport as layout viewport when it renders the web page. There are more options to this meta tag, summarized by <a href="http://www.quirksmode.org/mobile/metaviewport/" target="_self" rel="noopener noreferrer">Peter-Paul Koch at Quirksmode</a></p>
<p><img src="/assets/blogg_responsive-ideal.png" alt="Ideal viewport"></p>
<h2>Where to go from here</h2>
<p>By now you hopefully have the understanding of why <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Media_Queries/Using_media_queries" target="_self" rel="noopener noreferrer">media queries</a> work the way they do and a little bit of history about the challenges with web development for mobile devices. This short article does not cover the actual use of media queries, although I provided some good links to further reading and more comprehensive guides to that.</p>
<ul>
<li><a href="http://www.quirksmode.org/mobile/" target="_self" rel="noopener noreferrer">Quirksmode - Mobile</a></li>
<li><a href="https://developer.apple.com/library/iad/documentation/AppleApplications/Reference/SafariHTMLRef/Articles/MetaTags.html#//apple_ref/doc/uid/TP40008193-SW6" target="_self" rel="noopener noreferrer">Apple - Supported meta tags: viewport</a></li>
<li><a href="https://css-tricks.com/css-media-queries/" target="_self" rel="noopener noreferrer">CSS-TRICKS - CSS Media Queries &#x26; Using Available Space</a></li>
</ul>]]></description><link>https://kits.se/blogg-2016-01-12/what-makes-responsive-design-work</link><guid isPermaLink="false">https://kits.se/blogg-2016-01-12/what-makes-responsive-design-work</guid><dc:creator><![CDATA[Gustav Jorlöv]]></dc:creator><pubDate>Tue, 12 Jan 2016 00:00:00 GMT</pubDate></item><item><title><![CDATA[Välkommen till kits.se]]></title><description><![CDATA[<p>Under det första året i KITS historia har vi lyckats med mycket. Vi har lyckats hitta duktiga och roliga kollegor, vi har lyckats leverera i spännande och utmanande projekt, varit på givande konferenser och en massa annat. På ett område har vi dock misslyckats fatalt, att få upp en enkel hemsida! Men plötsligt händer det:</p>
<p><strong>Välkommen till kits.se</strong></p>
<p>Som vanligt återstår mycket att göra. En del texter saknas och andra behöver förbättras. Någon layout kanske inte fungerar i alla webbläsare men det är en 1.0 i alla fall.</p>
<p>kits.se kommer givetvis vara ett av våra ansikten utåt men dessutom tänker vi oss att det kommer vara en sida där vi experimenterar med nya tekniker för att bygga modern webb och skriver om vad vi kommer fram till. Allt detta finns redan idag tillgängligt på <a href="https://github.com/kits-ab/kits" target="_self" rel="noopener noreferrer">GitHub</a> så om ni vill rapportera ett fel eller bara är nyfikna så är ni välkomna. Vi kommer skriva mer här på bloggen om hur sidan är byggd inom kort.</p>
<!--more-->]]></description><link>https://kits.se/blogg-2015-11-06/valkommen-till-kits-se</link><guid isPermaLink="false">https://kits.se/blogg-2015-11-06/valkommen-till-kits-se</guid><dc:creator><![CDATA[Joakim Kemeny]]></dc:creator><pubDate>Fri, 06 Nov 2015 00:00:00 GMT</pubDate></item></channel></rss>