<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Koodoo - Medium]]></title>
        <description><![CDATA[We are Koodoo, and we are building tech to power the next generation of mortgages - Medium]]></description>
        <link>https://medium.com/koodoo?source=rss----d73c858525b0---4</link>
        <image>
            <url>https://cdn-images-1.medium.com/proxy/1*TGH72Nnw24QL3iV9IOm4VA.png</url>
            <title>Koodoo - Medium</title>
            <link>https://medium.com/koodoo?source=rss----d73c858525b0---4</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Wed, 11 Nov 2026 21:24:10 GMT</lastBuildDate>
        <atom:link href="https://medium.com/feed/koodoo" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[Using interactive data tools to get a better understanding of how monetary policy may impact your…]]></title>
            <link>https://medium.com/koodoo/using-interactive-data-tools-to-get-a-better-understanding-of-how-monetary-policy-may-impact-your-5e926e1f7f2e?source=rss----d73c858525b0---4</link>
            <guid isPermaLink="false">https://medium.com/p/5e926e1f7f2e</guid>
            <category><![CDATA[uk-economics]]></category>
            <category><![CDATA[streamlit]]></category>
            <category><![CDATA[mortgage]]></category>
            <category><![CDATA[data-visualization-tools]]></category>
            <category><![CDATA[data-analysis]]></category>
            <dc:creator><![CDATA[Kojo Hinson]]></dc:creator>
            <pubDate>Fri, 07 Oct 2022 12:09:08 GMT</pubDate>
            <atom:updated>2022-10-07T12:08:43.706Z</atom:updated>
            <content:encoded><![CDATA[<h3>Using interactive data tools to get a better understanding of how monetary policy may impact your mortgage payments</h3><h3>Table of Contents</h3><blockquote>1. Introduction<br>2. How did we get here?<br>3. Looking back to look ahead<br>4. Building a good scenario visualiser (the data interactive tools bit)<br>5. Understanding your options</blockquote><figure><img alt="" src="https://cdn-images-1.medium.com/max/996/1*PW1ccPIacT9nF5kdXP-CLA.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/997/1*mFoGxmSV3r4wSVlCmWF1iw.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1016/1*S6wNJmajMiHLDFqaogkw7g.png" /><figcaption>A period of uncertainty marked by sharp increases in inflation and quantitative tightening</figcaption></figure><p>It’s a tricky time to be a borrower, with many of us facing lots of uncertainty around current markets, making it difficult to know what the future holds for our mortgage payments. Interest rates are on the rise, and naturally so are the concerns of many homeowners.</p><p>Government policy can have a big impact on mortgage payments, both in the short and long term. It’s important to understand how these policies can affect you, so you can make the best decisions for your financial future.</p><p>In this article, we’ll explore the current landscape of mortgage rates, what’s driving the increases, and how to leverage a data analysis and visualisation tool like <a href="https://frescodev-mortgage-analysis-streamlit-app-f5uewc.streamlitapp.com/">Streamlit</a> to understand how to best navigate the tricky economic climate we’re currently in.</p><h3>How did we get here?</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1007/1*3AfCsc6jm899Fn70HTamhg.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/507/1*8pupHaEtG6K8cJG6SguZMQ.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1001/1*zSil_lKnpb45y8MxAlzogA.png" /><figcaption>Government boosts the economy with low base rates which drives up consumer spending fuelled by cheap debt</figcaption></figure><p>The last few months mark a clear upward trend in mortgage rates. We’re now firmly exiting a sustained period of historically low interest rates set by governments and central banks, after an unprecedented amount of quantitative easing measures (policies designed to encourage growth) post the 2008 housing crisis, and most lately through the global pandemic.</p><p><strong>The end of the sub 2% mortgage rate era</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*uCcIeGddFKUh44Ju8O9zyA.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*At5My-g_snBuR7ViPIZx3w.png" /><figcaption><a href="https://koodoo.io/">Koodoo</a> platform insights showing a clear increase in mortgage rates starting around March of this year. (Source: <a href="https://omsci.koodoo.co.uk/">https://omsci.koodoo.co.uk/</a>)</figcaption></figure><p>Higher base rates as set by the central bank leads to higher interest rates on mortgages and other lending products across the country. The recent hike in base rate was the <a href="https://www.bankofengland.co.uk/knowledgebank/will-inflation-in-the-uk-keep-rising#:~:text=We%20expect%20inflation%20to%20start,target%20in%20around%20two%20years.">Bank of England’s response to an increase in living costs</a>, primarily driven by a surge in energy prices.</p><p><strong>A quick recap on inflation</strong></p><p>Inflation is the sustained increase in the general price level of goods and services in an economy. This means that the purchasing power of a unit of currency falls and, as a result, <strong>inflation essentially erodes the value of money</strong>. Rising inflation in the U.K. is a complex topic but can be <a href="https://www.ons.gov.uk/economy/inflationandpriceindices/articles/priceseconomicanalysisquarterly/march2022#energy-prices-have-contributed-to-rising-inflation">partially attributed to a wide mixture of factors</a> including rising import prices, an intense winter period placing pressure on our energy supply chains, and of course, socio economic uncertainty due to events such as Brexit, the ongoing war in Ukraine, and the global pandemic.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1018/1*OlGhxsT0U5EL7KyNrCTp6g.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/509/1*8GewIQ4CglYvJ7tAN1m1UQ.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1001/1*pU--qe3VJmQIqyyw9mv_lA.png" /><figcaption>The BoE makes debt cheap, people buy more things, demand starts to outweigh supply, and the cost of things increases.</figcaption></figure><p>In an attempt to keep inflation in check, the <strong>Bank of England has raised rates seven times since December 2021</strong>, most <a href="https://www.bankofengland.co.uk/monetary-policy-summary-and-minutes/2022/september-2022">recently in September to 2.25%</a>, the highest level in 14 years.</p><p>The aim of these measures is to <a href="https://www.bankofengland.co.uk/monetary-policy">lower inflation to a Monetary Policy Committee recommended target of 2%</a> (as opposed to the currently much higher value of around 9–10%), although the raise in the base rate also means that households are likely to see their real incomes squeezed in the short to medium term. <strong>Increasing the base rate and consequently borrowing costs incentivises consumers to save rather than spend</strong>, as incomes get squeezed and we become more mindful of future financial commitments.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*8dyso1FUhfBipqMX-gnZvA.png" /><figcaption>Source: <a href="https://www.bankofengland.co.uk/boeapps/database/Bank-Rate.asp">Bank of England Database</a></figcaption></figure><p>The Bank of England’s decision to increase the base rate may help to curb inflation in the short-term by lowering demand for goods and services, therefore lowering prices. However, it remains to be seen how effective this will be in the long-term and what impact it will have on the economy overall.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1007/1*MKCTi06gKspdaqSaM2c48A.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/502/1*mqfJ3l6birzG7HeHXLRndg.png" /><figcaption>Rate increases incentivises consumers to save their cash.</figcaption></figure><p><strong>Impact on mortgage lending</strong></p><p>With concerns mounting around further interest rate rises and in the face of increasing market uncertainty, most consumer lenders will take measures to adjust their pricing to account for increased costs of borrowing, adjust their affordability assessments to account for inflation (and also potentially reduced house prices), and revise their risk assessments in accordance with heightened market volatility. Some major mortgage lenders have even gone to the length of temporarily halting their mortgage products altogether in an attempt to maintain a strong position on risk aversion.</p><p>This means that<strong>, for many people looking to buy a home or remortgage, the process has become more expensive and more difficult</strong>. It’s not <em>all</em> bad, though. If you’re currently on a fixed rate mortgage, your repayments are unlikely to change until this rate expires. And if you’re <a href="https://app.getmortgagerates.co.uk/remortgage">looking to remortgage</a>, there are still plenty of deals out there to be had — you just might have to shop around a bit more to find one that suits your needs and to set your expectations that the you’re now more likely to start paying a higher price.</p><h3>Looking back to look ahead</h3><p>The base rate may not mean much to most people, but it’s a big deal for those with mortgages. And right now, the markets are predicting that the <strong>base rate could rise to nearly 6%</strong> by next spring.</p><p>In order to know what to expect if you’re due to remortgage in the next few years or to purchase your first home in a similar time span, it’s useful to look at the wider historical context of the base rate and the various factors that impact it.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*i6xomJEGkQ41s4l4rfsw0A.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*bWoPXDCA3NfGyiunmAHN2g.png" /><figcaption>A sharp rise in inflation in 2021 precedes some of the largest relative base rate increases we’ve seen in the last few decades. (Source: <a href="https://www.ons.gov.uk/economy/inflationandpriceindices/timeseries/l55o/mm23">Office for National Statistics</a>)</figcaption></figure><p>Historically speaking, base rate increases and decreases tend to closely follow inflation as the base rate is the main instrument of monetary policy. So when inflation rises sharply, the base rate is likely to rise also.</p><p>Given what we know about the current levels of inflation, energy prices as an underlying contributing factor, and how current levelling compares to historic levels — it’s reasonable to assume that we’ll continue to see levels of inflation above the 2% target well into next year and <strong>we should probably expect to see further base rate hikes until inflation levels eventually start to decrease and normalise</strong>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*-IVZrkCqOYLrpdHlbB6qQQ.png" /><figcaption>Source: <a href="https://www.ons.gov.uk/economy/inflationandpriceindices/bulletins/consumerpriceinflation/august2022">Office for National Statistics</a></figcaption></figure><p>So, what does this mean for those that locked in fixed rate mortgages during the period of historically low base rates? How much can you expect to pay when the initial rate on your mortgage expires and it’s time to remortgage? Trying to do a good job of answering these questions can get pretty difficult, and it’d be great to get some help to allow us to easily understand and visualise the potential scenarios ahead.</p><h3>Building a good scenario visualiser</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1005/1*x7xeKFZr8EDR7vj4R5uicg.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1018/1*i1kL25Ar4iAqBWgvY6oz4Q.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1010/1*fY_vkEM2kNV_hDM1MRyoJA.png" /></figure><p>Before we build our tool, let’s get a clear idea of what insight we’re trying to gain and what assumptions we’re willing to make.</p><p><strong>Key insights we’re looking to get</strong></p><ul><li>Assuming, I’ve currently got a mortgage and I’m on a fixed rate for a set term. What will my monthly debt repayment schedule look like? How about annually or over the lifespan of my mortgage?</li><li>What am I paying now and what am I likely to pay when I remortgage? and how will that change depending on what’s happening with the economy?</li><li>How do some of these different options compare?</li></ul><p><strong>Carefully thinking about how we visualise our data</strong></p><p>There’s something special about a hand-drawn diagram or graph. It’s a reflection of the thinker’s mind, a trace of their thought process as they worked through a problem. It’s a snapshot of a moment in time, of a particular way of seeing the world.</p><p>Most modern visualisations are generated by computers, using a single description to create a static picture for any dataset. This has its advantages — it’s efficient, and can be tailored to the specific needs of the viewer.</p><p>The power of <strong>interactive</strong> data visualisation lies in its ability to give us flexibility in how we capture the essence of a problem, and the way we think about it.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1010/1*yx_fd-D85twaMfaBezNjJg.png" /></figure><p>A key difference in creating interactive data visualisations as opposed to static ones (for a static example, think of a graph you produce in excel, which you then display as an image in a presentation), is that it enables for rapid feedback in the data exploration process. This dexterity is what makes it such a powerful tool for understanding complex problems as <strong>it allows us to quickly see the data in different ways</strong>, and to find patterns in information that might otherwise be hidden.</p><p><strong>Putting things in practice: Building an interactive data visualisation interface with </strong><a href="https://streamlit.io/"><strong>Streamlit</strong></a></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1009/1*azUVC4ph5Y56NKFN67OZ6w.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/600/1*HyCHADPdQOz1Kh4ZaliXpQ.gif" /></figure><p>To build a simple dynamic visualiser we’ll start by thinking of our inputs (control variables) and the outputs (charts, graphs, tables etc)</p><p>What are the scenario control parameters?</p><ul><li>Properties of your current mortgage</li><li>Properties of your mortgage deal when you’re next due to remortgage</li></ul><p>What are the calculated outcomes?</p><ul><li>Amortisation (mortgage repayment) schedule</li><li>Monthly and lifetime costs</li><li>Comparative cost analysis</li></ul><p><a href="https://www.streamlit.io/">Streamlit</a> is a really powerful Python utility that makes it easy to create dynamic, custom data apps in just a few minutes. Using this library we can construct our control panel in just a few lines of code!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/600/1*5wt3VxM_ID5a8GP_19N9Hg.gif" /><figcaption>Building our control panel using the Streamlit library</figcaption></figure><p>Next, we’ll use this package, in a combination with a few others to calculate and <strong>visualise our key insights</strong>. There are a few more pieces needed to complete our interactive data puzzle and properly connect our control panel to the visualised outputs.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*OhEKeAE1oDPWop2K85gF1w.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*16KjWxCYUP6ZBhykGnd76g.png" /><figcaption>Key insights calculated using a few Python libraries and visualised using Streamlit</figcaption></figure><p>A few of the Python packages leveraged to help us make the right calculations:</p><ul><li>We use the <a href="https://numpy.org/numpy-financial/latest/pmt.html">NumPy financial</a> python library in order to calculate interest payments and monthly payments in a few lines of code.</li><li>We use the <a href="https://pandas.pydata.org/">Pandas</a> python library in order to allow us to manipulate and represent tabular data such as the repayment schedule (<em>Think excel but in code</em>).</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/946/1*AzWDMIkg0GfGARI6EsT1uQ.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/349/1*b2JmH-7o6_qjtB0NHA1TGA.png" /><figcaption>Using the NumPy financial library, we can use the PMT function to work out principal and interest monthly repayment values</figcaption></figure><p><strong>Putting it all together</strong></p><p>The finished product allows us to leverage an interactive way to analyse and compare how your mortgage future might pan out depending on a few key assumptions.</p><p>You can use a demo version of this app <a href="https://frescodev-mortgage-analysis-streamlit-app-f5uewc.streamlitapp.com/">here</a>, to try and see how different scenarios may impact your individual circumstances.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/600/1*W8lmTdfYxDmvDFEZ-ontNw.gif" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/600/1*8-JUxWYTpZGYSCdh-sNAog.gif" /><figcaption>Connecting the above elements together allows us to quickly see the impact of changing our remortgaging options</figcaption></figure><p><a href="https://www.moneysavingexpert.com/news/2022/09/mortgage-market-turmoil-what-to-do/">Money Saving Expert</a> states that, for each 1 percentage point your mortgage rate increases, you should <strong>expect to pay roughly £50 more a month (£600/year) per £100,000 of mortgage debt</strong>. We can use our app to validate this case using some friendly numbers for illustration.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Gb9XFKEZ89xQ3_Hb6dKXkw.png" /><figcaption>Illustrative static example</figcaption></figure><p>Assuming,</p><ul><li>Your current mortgage loan value is £100,000</li><li>You’re currently paying 1% in interest rate charges</li><li>You remortgage at the end of your initial term with a rate of 2%</li><li>With a new loan term of 24 years</li></ul><p>Our tools tells us that we can expect our monthly payments to increase by around £42 per month, and around £89 per month when we increase the rate again to 3%.</p><p>We can also use our tool to see how the cumulative repayments look over the course of the loan’s full term (using a few assumptions around rate consistency and the type of mortgage you’re on). You can see the impact on how much interest you’re paying by the jump in the light blue line below around the end of the initial term, when the rate increases.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*OqxARRGIWNxQEg3xCJgl2A.png" /><figcaption>Repayment schedule for a £100,000 1% mortgage, remortgaged at a 2% rate over a combined full term of 26 years</figcaption></figure><h3>Understanding your options</h3><p>The current situation is unprecedented, and it is impossible to know for certain what the future holds. However, there are some things that we can do to protect ourselves from the worst of the inflationary pressure. For example, switching to a cheaper mortgage deal at the right time and overpaying when we can are two options that can potentially help to ease the financial burden.</p><p>All in all, one of the things that has become clear is that our ability to make quick and smart data driven decisions will become even more key to modern economies as we face periods of high uncertainty and growing rates of inflation. To that end, understanding our data and how it can help us make informed decisions about our financial future is more important than ever.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=5e926e1f7f2e" width="1" height="1" alt=""><hr><p><a href="https://medium.com/koodoo/using-interactive-data-tools-to-get-a-better-understanding-of-how-monetary-policy-may-impact-your-5e926e1f7f2e">Using interactive data tools to get a better understanding of how monetary policy may impact your…</a> was originally published in <a href="https://medium.com/koodoo">Koodoo</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Secrets Management: why we love Hashicorp Vault!]]></title>
            <link>https://medium.com/koodoo/secrets-management-why-we-love-hashicorp-vault-db30edbb7281?source=rss----d73c858525b0---4</link>
            <guid isPermaLink="false">https://medium.com/p/db30edbb7281</guid>
            <category><![CDATA[google-cloud-platform]]></category>
            <category><![CDATA[kubernetes]]></category>
            <category><![CDATA[hashicorp-vault]]></category>
            <category><![CDATA[secrets]]></category>
            <category><![CDATA[infrastructure-as-code]]></category>
            <dc:creator><![CDATA[Xan Manning]]></dc:creator>
            <pubDate>Thu, 14 Apr 2022 14:21:54 GMT</pubDate>
            <atom:updated>2022-04-14T14:21:54.815Z</atom:updated>
            <content:encoded><![CDATA[<h3>Introduction</h3><p>As a Platform Engineer at Koodoo, one of the many challenges my colleagues and I face is management of secrets, ensuring that they are protected and that only the right people and applications are able to access them. We have been somewhat fortunate that in the early days of Koodoo we adopted Kubernetes which has its own secret storage configuration objects, however this does also present its own challenges. On top of the challenges presented in Kubernetes we also have to address the challenges of “single source of truth”, secret life cycles and access management, all of which become very difficult when there are multiple systems outside of Kubernetes also relying on secrets.</p><h3>Challenges with Kubernetes Secrets</h3><p>To write secrets to Kubernetes, it will require either a manifest to be written with the secret values base64 encoded (NOT ENCRYPTED!) or for a raw kubectl command to be called to write a secret from stdin.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/597/0*sjwg4WOnbzepmDsi" /></figure><p>The temptation to write the secret manifest to a Github repository is high, especially so that it is included in our pipelines. However, this could end very badly given the fairly open and distributed nature of the setup of our Github Organisation for our team. On the other hand, writing a secret using a kubectl command means one or more individuals are responsible for ensuring that secret exists and is backed up somewhere should it need to be re-created. This is a mess either way because we could very easily lose control of who has access to secrets, particularly when restricting access to secrets in-line with our Joiners/Movers/Leavers procedures. Also equally messy is knowing which version of the secret is the right one, knowing where the secret is ultimately stored outside of the cluster, and where we need to go to change or delete the secret when requirements change.</p><p>Once the secrets are in Kubernetes, you need to <a href="https://kubernetes.io/docs/reference/access-authn-authz/authorization/">configure RBAC</a> to ensure only the right people and principals can access the secrets, however when you manage multiple clusters it can become harder to administer as you scale out.</p><p>You also have to take steps towards safely configuring the storage. Secrets by default <a href="https://kubernetes.io/docs/concepts/configuration/secret/">are stored unencrypted in etcd</a> (the cluster’s underlying data store). Normally this is resolved by enabling <a href="https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/">Encryption at Rest</a> for secrets, a capability GKE makes available which is fine and since we are using GKE, this capability is available to us <a href="https://cloud.google.com/kubernetes-engine/docs/how-to/encrypting-secrets">out of the box</a>.</p><p>Another challenge is how to manage secrets that are shared between different environments and services. In an ideal world, every environment would be completely separate and isolated: dev, test and RC should have absolutely nothing in common in terms of resources or data storage. Different services and workloads should also be isolated, which in Kubernetes can be achieved by creating namespaces. In reality though, some of the 3rd party services we rely on means that complete isolation is not always possible. While we do always ensure separation between production and non-production workloads, dev, test, and RC might be required to share certain secrets. For example, to be able to connect to an email delivery service. That secret might also need to be shared between services, so needs to be available across multiple namespaces. Imagine a situation where our provider comes along and says “you’re using a v1 format authentication token, we’ve moved on to v2 and you need to update by the end of the month”. That update has to be done multiple times across multiple namespaces and clusters. Yes, toil can always be automated away and tied into some sort of automated process, but you often have to first experience the pain before you do anything to fix it, balancing the time to automate against the manual effort given your working day is stretched across dozens of workstreams.</p><p>Lastly, there is also a need to access secrets outside of our Kubernetes cluster, for example in our CI/CD pipelines in Github, or for developers to share secret keys for their Postman calls, argh! Nightmare, how do we access those from outside of the cluster?!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/600/0*Kte2n2t-MRkbLxj7" /></figure><h3>Enter Hashicorp Vault</h3><p>After some consideration, it was decided that we needed to look at a solution that would allow us to avoid some of the headaches associated with the above challenges and give us new capabilities that have not got a convenient solution within Kubernetes. What we decided to implement was <a href="https://www.vaultproject.io/">Hashicorp Vault</a> which promises to Manage Secrets and Protect Sensitive Data.</p><p>Predominantly we were interested in the following key features in Vault that would potentially be advantageous to our platform:</p><ol><li>Configuration management — all of this can be defined as Infrastructure as Code (IaC) using Terraform!</li><li>Identity-based Access — Not only can we authenticate and apply policies to users, authorising them to manage secrets, but we can do the same for applications and machines.</li><li>Kubernetes Integration — secrets can be securely injected into our applications across multiple clusters, all obtained from our single source of truth.</li><li>Secrets Management — we are able to centralise our secrets into one place and make them available to multiple applications, systems and environments.</li><li>Storage backends — there’s <a href="https://www.vaultproject.io/docs/configuration/storage">a lot of choice</a> as to where to store our secrets data!</li><li>“Encryption as a Service” — our applications can pass data to Vault to be encrypted before it is stored in an event or database.</li><li>Automated PKI Infrastructure — we can reduce the manual steps to update certificates for inter-service communications, for example with monitoring.</li><li>Dynamic Secrets — credentials can be created on-demand rather than having to store static secrets that are manually managed. Dynamic secrets often can be configured with a time-to-live (TTL), ensuring that they expire when no longer needed.</li></ol><h3>Configuration Management</h3><p>At Koodoo, the Platform Team’s number 1 tool for Infrastructure as Code is <a href="https://www.terraform.io/">Terraform</a>. Whenever we look for a new infrastructure solution we tend to favour those that can be defined in code using Terraform.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/400/0*K4fxM4gC7IsFA2xr" /></figure><p>The perceived advantages of adopting IaC are reduced cost in terms of the number of people and amount of effort required to configure a solution. Speed and efficiency means that new requirements and configuration changes are often faster to deliver, particularly with the use of modular reusable code. IaC also reduces risk in that automation can avoid human error from manual reconfiguration, this particularly works well when you include testing in your pipelines, but also increases reliability and repeatability.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/559/0*skZO0GCmYYTgCn2z" /></figure><h3>Identity-based Access and Kubernetes Integration</h3><p>This was a big selling point for us in the Platform team, as we have many squads working on multiple services and engineers responsible for application development, infrastructure and data pipelines. There are secrets that we would want our application to be able to access, however we’d want to also restrict who within the organisation can access those secrets, who specifically can access secrets in production and before you know it we have a crazy matrix of authorisation that needs to be applied to multiple environments. There are secrets that only the developers should have access to and be responsible for managing (such as for authenticating with third-party integrations), as well as secrets that only the data team should see (such as data warehouse credentials). On top of all this, we need to consider production support team members who are the only individuals who can access secrets pertaining to the production environment.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/400/0*JQUH8JZP43sbIHbQ" /></figure><p>With Vault we are able to perform identity brokering with our main identity service provider that our users rely on for their day-to-day activities. This means that when a new engineer joins our team, as part of their onboarding process they are added to specific groups and their group membership grants access to specific secret mounts in Vault.</p><p>In a similar way, we use Kubernetes to perform identity brokering for our applications. Kubernetes service accounts provide an identity for processes running in a pod, what we have found awesome about Vault is that we can authenticate a service against Kubernetes, then an application is able to have a policy applied to it based on the service account name and namespace. This means service A cannot access secrets for service B because it does not have the correct service account and/or namespace! All of this is made possible with the vault-agent-injector which is able to mount secret data into the pod.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*kSCU_pJOgGSxVJ0P" /></figure><h3>Secrets Management</h3><p>What can I say? It’s a lot easier now to update secrets because we only need to do it in one place — Vault. All of our environments connect to and pull secrets from our shared Vault, so we have immediately reduced our workload. Secrets are versioned, so if someone mucks up we can roll back to a previous version of the secret. In addition to this, we can now start to consolidate the secrets used for Github Actions and other 3rd-party cloud services using AppRoles as an authentication method.</p><h3>Storage Backends</h3><p>Vault can write its secrets storage to so many different types of backend. At Koodoo we host a lot of our infrastructure in GCP, so it made sense for us to leverage Google Cloud Storage buckets as a storage backend. We then keep the GCS bucket in sync with an Azure Storage Account container as part of our backup procedure. On top of this, we use GCP Cloud KMS to unseal Vault, so we have this rather cool situation where the data in Vault can only be accessed when it lives in a specific GCP Project. It’s like having a safe that you can only unlock with your key when you’re in a specific location.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/481/0*-Zj94lD8FM9ldNKf" /></figure><p>That’s cool and all, but given that we use GCP heavily, why not just put secrets into <a href="https://cloud.google.com/secret-manager">Google Cloud Secret Manager</a>? Surely everything discussed above is available with the solution provided in GCP? In the initial stages Secret Manager was considered and would provide a lot of the features we required, however as discussed below, Vault goes that little bit further with regards to what it can offer.</p><h3>“Encryption-as-a-Service”</h3><p>When handling PII you should always ensure the best security practices of encryption at rest and even more importantly encryption in transit. For this we use <a href="https://www.vaultproject.io/docs/secrets/transit">Vault’s Transit secrets engine</a>, and this is personally one of my favourites!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/250/0*bMffD1MfJj13QL30" /></figure><p>At Koodoo our applications are event-driven so we use tools like Google Cloud’s Pub/Sub to move the data from the application into the data pipeline for processing and analytics. Ultimately, the data does go on a journey that even traverses cloud providers! Whilst we use TLS to encrypt communications from the browser, and all the way until we reach the end of the data pipeline, we also encrypt any private data before it starts its journey to its final destination. Typically such an operation would require <a href="https://en.wikipedia.org/wiki/Public-key_cryptography">asymmetric encryption</a> (such as GnuPG), where the backend API of Koodoo’s platform would have the public key, meaning it could only encrypt data, and the end of the data pipeline would have the private key allowing for decryption of that data. To avoid this overhead of managing PGP keys, we have written policies in Vault that makes the transit secret engine behave a bit like asymmetric encryption whilst using AES256 encryption (which is symmetric). Our APIs (and some of our engineers) only have access to the encryption endpoint, so they can pass data to Vault and receive an encrypted response body. If the API were then to attempt to post to the decrypt endpoint, it will receive an authorization error. All along the data pipeline the PII data remains encrypted until it reaches the data warehouse at which point it is decrypted by a job prior to loading into the data warehouse where it is re-encrypted at rest.</p><h3>Automated PKI Infrastructure</h3><p>As mentioned previously in “Encryption-as-a-Service”, we use TLS for encrypting our inter-service communication as well as verifying the identity of the service. At the moment we still often use static certificates from well known and trusted Certificate Authorities (CAs), however updating these certificates can be a burden as they appear in multiple places within our infrastructure. Vault has a solution! Vault is able to act as a Certificate Authority and issue certificates to services within our infrastructure automatically, this is particularly effective in Kubernetes when using something like <a href="https://cert-manager.io/docs/">cert-manager</a>. This works well for authenticating and encrypting all communication between services used for monitoring, for example such as Prometheus, Loki, etc., where we hope to issue short lived certificates dynamically as part of the process. Why short-lived certificates? This is because if a certificate is leaked, the potential damage is limited to the TTL of the certificate and reduces the need for managing long revocation lists.</p><h3>Dynamic Secrets</h3><p>As is the strategy for our PKI Infrastructure, any chance to use short-lived secrets is a bonus! Vault provides you with a KV store used for keeping static secrets, however with static secrets there is a requirement to keep on top of the management of updating and deleting secrets as they age. Dynamic secrets on the other hand are great for providing short-term access to services, such as credentials for a database or service accounts for Google Cloud. These can be issued to both users and to applications with a short TTL, so that if credentials were to leak they would only be valid for maybe an hour or so before being deleted. It’s a lot harder to hit a moving target!</p><h3>Where next?</h3><p>At the moment, it often feels like we are only scratching the surface of what Vault can do. New releases bring some new functionality which might even replace or enhance the features of another third-party service or application. As Koodoo develops its platform and ventures into new areas we re-assess the way we do things and if there’s a use case will increase our usage of Vault.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/414/0*btFALodrjB4aV5FP" /></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=db30edbb7281" width="1" height="1" alt=""><hr><p><a href="https://medium.com/koodoo/secrets-management-why-we-love-hashicorp-vault-db30edbb7281">Secrets Management: why we love Hashicorp Vault!</a> was originally published in <a href="https://medium.com/koodoo">Koodoo</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[#IWD2022 with Claire Lowry-Hubball]]></title>
            <link>https://medium.com/koodoo/iwd2022-with-claire-lowry-hubball-6ccb889d1ee0?source=rss----d73c858525b0---4</link>
            <guid isPermaLink="false">https://medium.com/p/6ccb889d1ee0</guid>
            <dc:creator><![CDATA[Jess Bateson]]></dc:creator>
            <pubDate>Tue, 08 Mar 2022 15:58:34 GMT</pubDate>
            <atom:updated>2022-03-08T15:58:34.853Z</atom:updated>
            <content:encoded><![CDATA[<p>Koodoo’s Head of Delivery <a href="https://www.linkedin.com/in/claire-lowry-hubball/">Claire Lowry-Hubball</a> reflects on why it is important to celebrate IWD, today and every day.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/465/1*G3qfeIvOARligJhX1lFfHw.jpeg" /><figcaption>Claire and Apollo</figcaption></figure><h3><strong>1. What makes International Women’s Day special to you?</strong></h3><p>It’s so important to look at how far we’ve come but also how far we still have to go. I feel completely in awe of the women who paved the way for me to live my life as a gay woman working in technology, living safely, able to vote. I’m not sure I would ever have been as brave as those women to drive the change they did.</p><p>I feel an incredible responsibility, as a parent, colleague, friend and human to ensure I am able to do what I can to make the world a better place for all people, to ensure I keep my eyes &amp; ears open to the challenges women still face today, all over the world.</p><p>In summary I think it’s so important to remember, to celebrate and to reflect on the work we still have ahead of us.</p><h3><strong>2. Have you faced any barriers in your career due to being a woman? If so, how did you overcome them?</strong></h3><p>In general terms I am super emotive. I’m a crier, it’s just who I am. For a long time I saw it as a sign of weakness or that I wouldn’t be taken seriously, because at times I wasn’t. I was told I shouldn’t wear my heart on my sleeve or that what I was saying wasn’t valuable because I was emotional, hormonal or on my period.</p><p>Well sometimes it’s true I’m hormonal, it’s what women have to deal with!</p><p>Now I see it as my super power, I’m so emotive because I have high emotional intelligence and I feel things, I care and I’m passionate. I’ve learnt to use this to my benefit in the same way you would with any other super power or strength you discover about yourself.</p><p>Have I stopped myself from crying? No, in fact I’ve just stopped hiding it and I talk about it. I’ll say if I think I’m going to and that they should still listen to what I’m saying. I’ll tell my team and I let them cry when they need to. Ultimately we all feel better, have better conversations and come out with better actions.</p><h3><strong>3. What is the most important message you want to send out to young women thinking about their careers?</strong></h3><ul><li><strong>Be you</strong></li></ul><p>There is no value in forcing yourself to be someone you are not and you will be miserable.</p><ul><li><strong>Be open</strong></li></ul><p>Have open dialogue with your colleagues, building strong working relationships is how we are able to have more challenging conversations and learn from each other.</p><ul><li><strong>Don’t stay where you aren’t happy</strong></li></ul><p>Every job teaches us something about ourselves and what we want from a career and in a workplace, good or bad. Don’t stay in those environments that make you unhappy because you feel you have to. You don’t. No workplace is right for everyone and there is no shame in acknowledging somewhere isn’t right for you, find the places where you thrive and people who share your passions and values.</p><p>Challenge companies on their values when you interview, working somewhere that has values that align with your own personal values will create a much more harmonious environment for you to be fulfilled.</p><h3><strong>4. Is there anyone that inspires you?</strong></h3><p>So so so many people, I find so many things inspiring and maybe that’s because I’m a fan of the little things, the times people stand up for themselves in a meeting or out on the street. When I see women standing together and supporting each other, the little gestures we can all do that have an impact.</p><h3><strong>5. Why do you think diversity in the workplace is so important?</strong></h3><p>I think it’s important everywhere. It’s critical to learning, broadening our minds and being more empathic human beings. If we surround ourselves with people just like us we won’t ever consider different perspectives or in the case of work, how people might use or benefit from our products.</p><p>It’s been said before but a diverse workforce is far more representative of the world we live in and the people likely to engage with your products or services. As an employee it makes the world of work far more interesting, there is so much value in needing to articulate your view in a way others can understand, in a way your customers need to understand.</p><p>Personally I really enjoy exploring different perspectives and evolving the way I think about things.</p><h3><strong>6. What are you most proud of doing?</strong></h3><p>Gosh this is a tricky one, I think the times I’ve pushed myself out of my comfort zone. I have not always been confident in my abilities throughout my career, no only as a women in a male dominate environment but also being dyslexic I feared people would think me lazy, rushed or even stupid.</p><p>I’ve spent a long time gathering feedback and understanding where I have the greatest value to add to a business. I’m also really upfront about my dyslexia to get it out of the way, manage expectations but also be really upfront about who I am.</p><p>It took me a long time to be able to take the risks in life and career than I have done, in the end if was the fear of all the missed opportunities and adventures that drove me forward and now I remind myself of a quote I love “Fear is the thief of dreams” any time I feel the fear.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/837/1*kAG3Z4IxybwtHZJ31riexQ.png" /><figcaption>“Fear is the thief of dreams”</figcaption></figure><h3><strong>7. What did you dream of when you were little?</strong></h3><p>Well my family mocked me because as a kid I told everyone I wanted to be a butterfly when I grew up… In some ways that hasn’t changed I do like to visit people and hopefully bring some joy to them all!</p><p>Sport was my real passion and if anyone told me that I’d be doing what I am now 15 years ago I wouldn’t have thought it was possible. However sport provided me with so many skills I’ve brought to work, passion, leadership, understanding the needs of the team and of management, being able to bridge the gap between.</p><p><strong>More than everything it gave me confidence, it surrounded me with lots of women; strong, passionate women, who taught me so much about who I wanted to be as a person and that’s who I try to be everyday.</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/636/1*yUY-lnzSI5Vghvb7LzK9rg.jpeg" /><figcaption><strong>Playing hockey at the Commonwealth Games, Delhi 2010</strong></figcaption></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=6ccb889d1ee0" width="1" height="1" alt=""><hr><p><a href="https://medium.com/koodoo/iwd2022-with-claire-lowry-hubball-6ccb889d1ee0">#IWD2022 with Claire Lowry-Hubball</a> was originally published in <a href="https://medium.com/koodoo">Koodoo</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How do we approach theming for white-label applications?]]></title>
            <link>https://medium.com/koodoo/how-do-we-approach-theming-for-white-label-applications-672163019731?source=rss----d73c858525b0---4</link>
            <guid isPermaLink="false">https://medium.com/p/672163019731</guid>
            <category><![CDATA[white-label-app]]></category>
            <category><![CDATA[tailwind]]></category>
            <category><![CDATA[mortgage]]></category>
            <category><![CDATA[react]]></category>
            <category><![CDATA[component-libraries]]></category>
            <dc:creator><![CDATA[Thomas Dargon]]></dc:creator>
            <pubDate>Mon, 31 Jan 2022 11:29:12 GMT</pubDate>
            <atom:updated>2022-01-31T11:29:12.009Z</atom:updated>
            <content:encoded><![CDATA[<h3>How do we approach styling for white-label applications?</h3><figure><img alt="Gif of a FE web application under different theme" src="https://cdn-images-1.medium.com/max/500/1*jiyimUUXbANLH3H20a9C0g.gif" /><figcaption>One application under different themes.</figcaption></figure><h4>TL;DR</h4><p>At build time our frontend application dynamically imports a tailwind config file and a style-overrides file based on the value of a “THEME” environment variable. This allows us to apply different styles to every single component in our UI, effectively creating a customisable application.</p><h4>1) Introduction 💭</h4><h4>2) A Component’s World🌏</h4><ul><li>2.1 — Creating theme-able components 🌈</li><li>2.2 — Using custom CSS classes🖌</li><li>2.3 — Using default Tailwind CSS classes 🎨</li></ul><h4>3) Applying a theme to a site 🖥</h4><ul><li>3.1 — Injecting a theme prop ⚙️</li><li>3.2 — Applying a Tailwind configuration file 🏋️‍♀️</li></ul><h4>4) Conclusion 🔮</h4><h3>1 — Introduction</h3><p>At Koodoo, we are building a mortgage distribution platform with the end goal to match people with mortgages that suit them, hassle free. To achieve our mission we want to make our applications available to the widest audience. A key element in our distribution strategy is to partner up with price-comparison websites such as <a href="https://mortgages.thetimes.co.uk/">The Times</a>, <a href="https://www.confused.com/mortgages">Confused.com</a>, and <a href="https://www.nerdwallet.com/uk/mortgages/">Nerdwallet</a> and power their mortgage services.</p><p>This is a win-win: our partners can focus on what they are good at, which is gathering wide audiences onto their website and promote services via their own channels while we can focus on what we are good at — building applications to connect people with mortgages. A key element to a successful integration with a partner is styling: to be attractive we need to provide applications that integrate seamlessly with our partner’s website and brand theme.</p><p>To achieve this, we develop “white label”<strong> </strong>applications. This means that when you visit any of our partners websites, you will have access to a seamless mortgage journey designed and developed by Koodoo but each have their own unique theming and content. This approach comes with additional complexity with regards to hosting, journey design (content customization) and styling but the benefits are enormous, we can focus our development efforts on a single code base and avoid the risk of divergence that would come from maintaining multiple applications.</p><p>In this article we will focus on the styling challenges and answer the question: How do we approach styling for white label applications. Let’s dive in! 🐇</p><h3>2) A Component’s World 🌍</h3><p>Modern web applications often use frameworks that promote UI componentization. At Koodoo, we typically use Next.js and Tailwind CSS as our frontend frameworks which means that our UIs are made of components.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*7_CCTBZ6-KnfEM1jrCroZw.png" /><figcaption>Breakdown of a User Interface into multiple components</figcaption></figure><p>We can define a “theme” as simply being a group of CSS rules which when put together represents the identity and the brand image of one of our partner. Theming is style customisation, so it is tightly coupled with how our components are written and styled. The first step in creating a customisable UI is creating theme-able components.</p><p>As we maintain multiple “white-label” applications across different teams we have our own React component library, that provides our applications with theme-able components.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*xuCYsUwBI_UszPz-7AQXOQ.png" /><figcaption>FE application using components from our shared central component library.</figcaption></figure><p><em>Note: Having a component library is not necessary to achieve theming for white label applications, (we could also have all our components in the same code repository as our application), it just happens that as we develop multiple white label applications, having our own component library in a separate repository avoids duplications and facilitates maintainability in the long run.</em></p><h4>2.1) Creating theme-able components 🧩 🌍</h4><p>The code snippet below is for a <strong>&lt;Button /&gt; </strong>component and shows how our components are written to be theme-able. If we overlook the imports and the propTypes definition, our component is a simple function which does 3 things:</p><ol><li>Defines three string variables (<em>primaryClasses</em>, <em>secondaryClasses</em> and <em>criticalClasses</em>) holding CSS utility classes. Each of these strings define a design variant ( “primary”, “secondary” and “critical” respectively).</li><li>Defines one <em>attributes</em> object which can contain any of the classes defined above.</li><li>Returns a JSX expression: <em>&lt;Component &gt;</em> which receives each of these classes defined as a value for its className property.</li></ol><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/45c5a612583c79c0a96238b39a26a6d4/href">https://medium.com/media/45c5a612583c79c0a96238b39a26a6d4/href</a></iframe><h4>Enabling design variants</h4><p>This component can be rendered under different <strong>design variants </strong>depending on the “primary”, “secondary” and “critical” props it receives.</p><p><em>Our button component also supports “small” and “base” design variants, but I removed them from the code snippet for simplicity.</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*OxLaSVz3qXXvXV1RRj3fYA.png" /><figcaption><em>&lt;Button/&gt; component rendered in our Component Library explorer under the “Koodoo” theme.</em></figcaption></figure><p>⚠️ <strong>Design Variants of a component are different from the Theme</strong>: each of these &lt;Button /&gt; design variants should be available under a given theme:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*sTK-Tcua6_pGnnnI7hRwdg.png" /><figcaption><em>&lt;Button/&gt; component rendered in our Component Library explorer under the four different themes.</em></figcaption></figure><h4>2.2) Using custom CSS utility classes 🎨</h4><p>To make components theme-able, we use custom css utility classes which are defined differently in different tailwind config files.</p><p>To see how this works we will focus on the theme-able “primary” button:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*p3wJZjJaQqVWDtafSmzCow.png" /><figcaption>&lt;Button/&gt; component in its “primary” design variant and default state (not being hovered or activated) under four different themes.</figcaption></figure><p>If we zoom on the primaryClasses definition, We have styles defined for each state our &lt;Button /&gt; can be in (<em>default</em>, <em>hover</em>, <em>focus-visible</em> and <em>pressed</em>).</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/17c75a1252c378e09a6adb052629229c/href">https://medium.com/media/17c75a1252c378e09a6adb052629229c/href</a></iframe><p>Zooming in further on the 3 utility classes used for the primary &lt;Button/&gt; in a “default” state, we see that these utility classes simply apply the following styles:</p><ol><li>background-colour</li><li>box-shadow</li><li>text-colour</li></ol><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/66f8e6e8a0bb9a657c2003ea6bfb4b40/href">https://medium.com/media/66f8e6e8a0bb9a657c2003ea6bfb4b40/href</a></iframe><p>If you are familiar with Tailwind, you would have noticed that these 3 utility classes are not the default tailwind utility classes, and you are right my friend ! 😉 Indeed, we are leveraging <a href="https://tailwindcss.com/docs/theme#customizing-the-default-theme">tailwind extendibility</a> to extend it with our custom classes on top of the default classes Tailwind offers out of the box. This works particularly well for custom values such as “colour palettes” aka our own theme.</p><p>In our component library repository we define a tailwind.config.jsfile where we “tell” tailwind what each utility class (i.e. ‘bg-buttons/primary/fill/default’ etc.. ) should mean, and they each have a different meaning for each theme: one class multiple flavours 🍦.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/a205b14768923e5d780545974b9c0688/href">https://medium.com/media/a205b14768923e5d780545974b9c0688/href</a></iframe><p>Thanks to this file we are able to use the notation bg-[customColorClass] , text-[customColorClass]and shadow-[customBoxShadowClass]to apply each style defined in the tailwind.config.jsfile to the component. Then at build time, Tailwind generates the CSS file containing the styles defined in this tailwind.config.js file. So when our component renders, the browser will match the .bg-buttons/primary/fill/defaultclass with the CSS rule {background-color:#495ce9;} and render the following &lt;Button /&gt;:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/400/1*6E3K4hxfoqhiaSsUTrPG_g.png" /><figcaption>✨ Primary &lt;Button /&gt; under Theme1 ✨</figcaption></figure><p>For another theme, we have another tailwind.config.js where the same custom classes are pointing to different values:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/ddb532087bc857be3d60af50cb9121ee/href">https://medium.com/media/ddb532087bc857be3d60af50cb9121ee/href</a></iframe><p>My primary button under the theme3 has a different background colour and text colour:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/404/1*DAE8WoMd0Br-91Ibt5Jkvg.png" /><figcaption>✨ Primary &lt;Button /&gt; in default state under Theme3✨</figcaption></figure><p>Each time we want to support an additional theme, we just need to add a new tailwind.config.jsfile for that theme.</p><p>💡 We have one component, using the same className value under each theme but we simply “pair” it with a different theme file (at build time) in order to render the &lt;Button/&gt; under the theme we want: <strong>one class, multiple flavours! 🍻</strong></p><h4>2.3) Utilizing default Tailwind CSS classes</h4><p>There are scenarios where we actually want to use the default utility classes that Tailwind offers out of the box. Imagine you have a <strong>&lt;Button /&gt;</strong> component<em> (hello again </em>👋 😁<em>)</em> that you would like to render with let’s say different border-radius between two themes. My theme1 &lt;Button /&gt; should have slightly rounded corners and I want my theme2 &lt;Button /&gt; to be rounder and maybe be uppercased and bold:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/400/1*6E3K4hxfoqhiaSsUTrPG_g.png" /><figcaption>✨ &lt;Button /&gt; <strong>Theme1</strong> ✨</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/392/1*Lw5wuKjdEUq5-A56y_Cb_w.png" /><figcaption>✨ &lt;Button /&gt; <strong>Theme2</strong> ✨</figcaption></figure><p>You wouldn’t want to have to write a custom class for each border radius and font weight the buttons should have under each theme. Some styles such as border-radius, font-weight, text-transform are so common that most websites only use a small variation of values these properties can have. Tailwind already comes equipped with the default classes to support these properties:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/602/1*e9XRMpFilv17pXKrO6EmKA.png" /><figcaption><em>Tailwind default </em><strong><em>border-radius</em></strong><em> styling utility classes</em></figcaption></figure><ul><li><a href="https://tailwindcss.com/docs/text-transform">Text Transform - Tailwind CSS</a></li><li><a href="https://tailwindcss.com/docs/font-weight#setting-the-font-weight">Font Weight - Tailwind CSS</a></li></ul><p>Instead of passing custom classes taking different meanings for each theme, we would like to simply inject different <em>already defined</em> classes for each theme that my &lt;Button/&gt; component should support.</p><p>Let’s take a look at the code again:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/0f67f61d0921522c7b98a166336fffc5/href">https://medium.com/media/0f67f61d0921522c7b98a166336fffc5/href</a></iframe><p>Notice that our &lt;Button /&gt; component can receive a <strong>theme</strong> property and whatever is held inside <strong>theme?.button</strong> will be applied to the Button <strong>className</strong>, effectively changing its style based on the<strong> theme props. 💡</strong></p><p>🙋‍♂️ “ Excuse me“ …BUT, where is this prop coming from? does the application has to define a theme props and pass it into <strong>every</strong> single components it is using ? ? ? 🙀 🙀 🙀</p><p>The <strong>theme</strong> prop can still be defined in the theme files inside the component library so it can be maintained in one place an re-used in different frontend applications!</p><p>Let’s introduce some nuance: 💡 each of the themes we support is defined by not one but <strong>two files</strong>: one <strong>tailwind-config</strong> file (that we previously discussed) and one <strong>style-overrides</strong> file.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*lf8VDiF9KX8ZNZL898zvLw.png" /><figcaption>A more accurate representation of the /themes folder inside our Component Library repository.</figcaption></figure><p>Let’s take a look at the style-overrides file for the theme1:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/93495b902bc0000fdeab32163dc7d331/href">https://medium.com/media/93495b902bc0000fdeab32163dc7d331/href</a></iframe><figure><img alt="" src="https://cdn-images-1.medium.com/max/400/1*6E3K4hxfoqhiaSsUTrPG_g.png" /><figcaption>✨ &lt;Button/&gt; with border-radius value of rounded-md =&gt; theme1✨</figcaption></figure><p>The same file for the theme2:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/69c73ce6f5d524247eafa6f37bf638c4/href">https://medium.com/media/69c73ce6f5d524247eafa6f37bf638c4/href</a></iframe><figure><img alt="" src="https://cdn-images-1.medium.com/max/392/1*Lw5wuKjdEUq5-A56y_Cb_w.png" /><figcaption>✨ &lt;Button/&gt; with border-radius value of rounded-full (uppercase and bold text) =&gt; theme2✨</figcaption></figure><p>Multiple classes, multiple flavours 🌈 🍦🍦🍦</p><h3>3) Applying a theme to a site:</h3><p>So we have two files that fully define the style rules to achieve a specific “theme”:</p><ul><li>style-overrides.js which contains default Tailwind classes</li><li>tailwind.config.js which contains custom utility classes</li></ul><p>When we deploy a new instance of the front end application we specify the “theme” it should use as an environment variable and use dynamic import to require the appropriate files with a few dynamic imports:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/2b6ece78ea0195c6bbba7bbae285f4c7/href">https://medium.com/media/2b6ece78ea0195c6bbba7bbae285f4c7/href</a></iframe><p>💡 Using Next.js we can easily<a href="https://nextjs.org/docs/basic-features/environment-variables#exposing-environment-variables-to-the-browser"> expose environment variables</a> to the browser.</p><h4>3.1) Injecting a theme prop</h4><p>Based on the value of the NEXT_PUBLIC_THEME environment variable we can inject different `theme` objects inside our components at import time by wrapping each components we export from our component library with an injectTheme function.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/d1f7f1c360dcfbdc4409196e4236db3a/href">https://medium.com/media/d1f7f1c360dcfbdc4409196e4236db3a/href</a></iframe><p>The injectTheme function simply relies on dynamic import to apply the desired styleOverrides :</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/285bcf6d3ecbcbf8c7ba17d72c303153/href">https://medium.com/media/285bcf6d3ecbcbf8c7ba17d72c303153/href</a></iframe><p>So every classes defined inside my theme1/style-overrides.js will be applied to my component via the “theme” prop effectively achieving conditional styling based on a “theme” required by the app.</p><h4>3.2) Applying a Tailwind configuration file</h4><p>We also have a “master” tailwind.config.js files in our frontend app which directly points out to the right config file defined in the component library:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/ae7370dc09b4357bba3cf4197e164aa1/href">https://medium.com/media/ae7370dc09b4357bba3cf4197e164aa1/href</a></iframe><p>When building the application, Tailwind will automatically generate the CSS files needed to apply the styles defined in the imported tailwind.config.js . The same custom class in our component will point to different styles.</p><p>Let’s visualize what has been said so far:</p><ul><li>Each theme folder contains one tailwind.config.js file and one style-overried.js file with classes name and classes value specific the the theme it defines.</li><li>Our components are exported through one index.js file which injects a theme prop in each of our theme-able components.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*4Jx-YJIVUviOo32M6tuTyQ.png" /><figcaption>Structure of the Component Library. (which could be a folder in the FE app if you don’t need an external component library)</figcaption></figure><ol><li>We define a component once, in <strong>one</strong> place (can be in app or in external repo if the use case is justified for your needs). This component uses custom utility classes which are defined differently in different tailwind config files.</li><li>For each theme we have a tailwind.config.js which defines custom classes differently (one class which associated with different values achieve different styles)</li><li>For each theme we create a style-overrides.js which contains Tailwind default classes to be applied to our components (different classes achieving different styles).</li><li>We specify a theme value in our frontend application environment variables: NEXT_PUBLIC_THEME=theme1</li><li>At build time, our frontend application which is configured has tailwind installed will generate the appropriates styles based (defined in tailwind.config.js ) and inject the appropriate theme prop (defined in style-overrides.js) in the components it imports.</li></ol><figure><img alt="full system view" src="https://cdn-images-1.medium.com/max/1024/1*Js01po21iKT8bxAj40z37w.png" /><figcaption>Full system view</figcaption></figure><p>And voilà 🪄 🎩 🐇: 👏</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*vytKob2lrIJo6X-47URB3A.png" /><figcaption>If we set our environment variable “NEXT_PUBLIC_THEME=theme1” the app will have the theme1.</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*TGGFhU7nISAsVUvnKidsMA.png" /><figcaption>If we set our environment variable “NEXT_PUBLIC_THEME=theme3” the app will have the theme3.</figcaption></figure><p>The system is so flexible that we could have multiple application picking and choosing components and a theme from out component library:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*RO5gU6GNDnYTQfZS2pkuEQ.png" /><figcaption>Multiple white-label apps using themes defined in one central place.</figcaption></figure><h3>4) Conclusion 🎬</h3><h4>Drawbacks ⚖️ :</h4><ul><li>As you can imagine our theme files are way bigger than the small extract I have shared. Their length vary depending on how complex and specific the UI design is for a given theme but they are generally <strong>MASSIVE. </strong>Which means, the creation of a new theme to integrate with a new partner still requires intensive work driven by the Design team.</li><li>Also the dynamic imports that the system is heavily based on and the way we integrate Tailwind with Next.JS means we have to <a href="https://nextjs.org/docs/deployment#nextjs-build-api">re-build</a> our application every time we want to switch between themes which adds an extra step in the release process.</li><li>Currently, the complexity of the system and the size of theme files, are the biggest drawbacks we can honestly share: complex system means a lot of overhead for a new joiners to implement a new theme and lots of time spent implementing a new design (manual and error prone). Which can impact the speed at which we can integrate with new partners.</li></ul><h4>Advantages ✨:</h4><ul><li>The system is incredibly flexible: we can achieve every single design requirements, style variations to meet the demands of our partners without having to develop a different application.</li><li>It is predictable and reusable<strong>, </strong>the themes and components created are reusable across different Frontend apps and app instances, no matter how the application evolves.</li><li>The main advantage of the current system, something that we often overlook in our quest for improvement: it works! We have a system that allows us to develop theme-able white label applications, yes there is room for improvements but currently this system powers every single Frontend app instances for each white-label app we develop. 👊</li></ul><h4>Future thoughts 🔮</h4><p>🎬 As I write these lines, our Component Library is undergoing a massive update, we are moving away from JavaScript and Tailwind CSS in favour of TypeScript and Styled Components with <a href="http://bit.dev/">Bit.dev</a> as a library manager which will allow huge simplification of the current system, theming granularity at a component level and at runtime! Stay tune for more tech updates from Koodoo. 🤘</p><p><em>Let’s give back to Caesar what is Caesar’s: I am not the creator of the system presented here, merely the user and messenger</em>. <em>A massive thank you to all the people at Koodoo who contributed and are contributing to building great things.</em></p><p>I hope that sharing our experience as a development team will help you and your team succeed whatever your mission might be. 🚀 🌕</p><p>Take Care and Stay Awesome ✌️!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=672163019731" width="1" height="1" alt=""><hr><p><a href="https://medium.com/koodoo/how-do-we-approach-theming-for-white-label-applications-672163019731">How do we approach theming for white-label applications?</a> was originally published in <a href="https://medium.com/koodoo">Koodoo</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Growing with Koodoo: My Journey as a Data Scientist]]></title>
            <link>https://medium.com/koodoo/growing-with-koodoo-my-journey-as-a-data-scientist-7a1d7679dadd?source=rss----d73c858525b0---4</link>
            <guid isPermaLink="false">https://medium.com/p/7a1d7679dadd</guid>
            <category><![CDATA[career-development]]></category>
            <category><![CDATA[data-science]]></category>
            <dc:creator><![CDATA[Nerea Béjar Muñoz]]></dc:creator>
            <pubDate>Mon, 06 Dec 2021 11:11:30 GMT</pubDate>
            <atom:updated>2021-12-06T11:11:30.582Z</atom:updated>
            <content:encoded><![CDATA[<blockquote>My name is Nerea, and I am a Data Scientist at Koodoo. Here I’ll talk about how I found myself in Data Science, and my experience of being part of a fast-growing start-up.</blockquote><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*8ryW0CQbwzc8JYnd6r0hzA.jpeg" /></figure><p>It all started in Madrid, after finishing my undergraduate degree in Industrial Electronics and Automation Engineering, my first job was actually working as a Business Analyst. To be honest, I didn’t really have a career path in mind, and that was the first job offer I received. I didn’t really know much about it but I knew that I enjoyed maths and tackling problems by using analytical thinking, so I decided to give it a go. Fast forward a few months into the role, and I realised that I loved working with data: exploring it, designing tests to validate its veracity and looking for answers, trends and patterns. I also figured out that I prefer work of a more technical nature.</p><p>Serendipitously, around this time I discovered that there was a “Data Science” career path which combined Maths and Computer Science, and I realised that was exactly what I wanted to do. To pursue my goal, I enrolled into an MSc in Computer Science and Artificial Intelligence at the University of Nottingham.</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fgiphy.com%2Fembed%2FLoUmCyntgoQA6Rf2Mz%2Ftwitter%2Fiframe&amp;display_name=Giphy&amp;url=https%3A%2F%2Fmedia.giphy.com%2Fmedia%2FLoUmCyntgoQA6Rf2Mz%2Fgiphy.gif&amp;image=https%3A%2F%2Fmedia1.giphy.com%2Fmedia%2Fv1.Y2lkPTc5MGI3NjExZXBwMDZmYnF3ZmVwem0xbjE5bnAxbG1yb3Ewa3htbmZ4dGx1ampvdiZlcD12MV9naWZzX2dpZklkJmN0PWc%2FLoUmCyntgoQA6Rf2Mz%2Fgiphy.gif&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=giphy" width="435" height="363" frameborder="0" scrolling="no"><a href="https://medium.com/media/1cb7d00c360666991f4c2eb406331b22/href">https://medium.com/media/1cb7d00c360666991f4c2eb406331b22/href</a></iframe><h3>Finding Koodoo</h3><p>Toward the end of the program in 2019, I attended an inspiring talk that was being given by the former CTO of Koodoo, a Fintech start-up looking to transform the mortgage industry. I added him on LinkedIn and soon after this, he invited me to their office in Nottingham where I met the team. I really enjoyed the atmosphere and was excited at the prospect of working for such a driven, young tech company. The selection process was amazing, especially the last stage, which consisted of a two-day hackathon. Not only did I learn a lot, I also got to meet interesting people and had a lot of fun.</p><p>When I first joined the team, everyone was very welcoming and friendly. Being the first Data Scientist in the company was very challenging, but I had a lot of support from everybody. I was very excited to be part of a team with such skilled people that I could learn a lot from and were always willing to help. An exciting aspect of working at such a young company is that you feel your work matters and you’re able to see its impact in the company’s progress.</p><h3>Hackathons and more</h3><p>A very cool part of the Koodoo culture are the hackathons, in which we all work together on a challenge using tools and frameworks that aren’t part of the company’s day-to-day tech stack. In one very memorable challenge, we built a model to predict the probability of our mascot, Kenny the koodoo, surviving poacher attacks.</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fgiphy.com%2Fembed%2FE6jscXfv3AkWQ%2Ftwitter%2Fiframe&amp;display_name=Giphy&amp;url=https%3A%2F%2Fmedia.giphy.com%2Fmedia%2FE6jscXfv3AkWQ%2Fgiphy.gif&amp;image=https%3A%2F%2Fi.giphy.com%2Fmedia%2FE6jscXfv3AkWQ%2Fgiphy.gif&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=giphy" width="435" height="435" frameborder="0" scrolling="no"><a href="https://medium.com/media/8cd4ba127724c5cecc1fffb050dbcc52/href">https://medium.com/media/8cd4ba127724c5cecc1fffb050dbcc52/href</a></iframe><p>Aside from the hackathons, I really like that we are encouraged to learn new things in our daily work and look for new technologies that best suit the projects we are working on. At Koodoo we work hard but it’s not all just about that, we have fun too! We’ve done a lot of things together such as go-karting, spinning, yoga, bungee fit and recently an offsite in the countryside! Even during the lockdown we found exciting virtual activities, such as murder mystery, whiskey tasting or painting a ceramic Kenny.</p><h3>What’s next?</h3><p>I have been at the company for two years now and recently got promoted to Senior Data Scientist. To say the time has flown by would be an understatement. I’ve grown a lot, both personally and professionally and worked on very interesting and engaging projects, some of which I have gotten to see be applied in the real world, while others are still in development or at very early stages. I’m looking forward to growing and leading the Data Science team at Koodoo and can’t wait to see what lies ahead of this fast growing company of amazing Koodoods!</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fgiphy.com%2Fembed%2FqrnZoHSIRCEeUzacfB%2Ftwitter%2Fiframe&amp;display_name=Giphy&amp;url=https%3A%2F%2Fmedia.giphy.com%2Fmedia%2FqrnZoHSIRCEeUzacfB%2Fgiphy.gif&amp;image=https%3A%2F%2Fi.giphy.com%2Fmedia%2FqrnZoHSIRCEeUzacfB%2Fgiphy.gif&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=giphy" width="435" height="435" frameborder="0" scrolling="no"><a href="https://medium.com/media/8064b5d36a7cee3844067e0eb8af49c4/href">https://medium.com/media/8064b5d36a7cee3844067e0eb8af49c4/href</a></iframe><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=7a1d7679dadd" width="1" height="1" alt=""><hr><p><a href="https://medium.com/koodoo/growing-with-koodoo-my-journey-as-a-data-scientist-7a1d7679dadd">Growing with Koodoo: My Journey as a Data Scientist</a> was originally published in <a href="https://medium.com/koodoo">Koodoo</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Using automation to power a next-gen development workflow]]></title>
            <link>https://medium.com/koodoo/using-automation-to-power-a-next-gen-development-workflow-3fc2143578d6?source=rss----d73c858525b0---4</link>
            <guid isPermaLink="false">https://medium.com/p/3fc2143578d6</guid>
            <category><![CDATA[software-development]]></category>
            <category><![CDATA[sofware-engineering]]></category>
            <category><![CDATA[github]]></category>
            <category><![CDATA[workflow-automation]]></category>
            <category><![CDATA[automation]]></category>
            <dc:creator><![CDATA[Kojo Hinson]]></dc:creator>
            <pubDate>Mon, 09 Nov 2020 08:51:13 GMT</pubDate>
            <atom:updated>2020-11-09T08:51:13.690Z</atom:updated>
            <content:encoded><![CDATA[<p>2020…what a ride! My team and I have been quite fortunate to have been kept busy with lots of new projects this year. We’re finally maturing out of the the start up infancy stage, and are now embarking on a scary but exciting journey towards the next level of scale as more and more businesses find out how our technology services can best help them serve their customers.</p><h3>Growing pains</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/750/1*rlwrUQz4DfbbqfK6ZEkGnw.gif" /></figure><p>One of the <em>many</em> challenges that this new level of scale brings us as a tech company, is retaining our ability to deliver at pace whilst extending the number of contexts, dimensions and channels the different teams within the company must operate on. Richard Hackman’s famous team communication diagram quite effectively displays how this manifests itself within growing teams by clearly surfacing the exponential growth of communication channels as numbers within an org increase.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*LjAK_rGY_N0imx2THFFe8Q.png" /><figcaption>More people, more problems</figcaption></figure><p>This growth in complexity can be <em>even</em> more pronounced when coupled with a software delivery process that heavily relies on effective and clear communication happening between the right parties at the right time.</p><h3>Breaking down the development workflow</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/480/1*fsfPNudo71RTnPAnCXDEzQ.gif" /></figure><p>One of the key requirements to creating an effective delivery process is having a thorough and clear understanding of how the team delivering the work are likely to structure their development. A combination of rich literature on well defined (and refined) design principles made available through various mediums, a good amount of proliferation in cloud services and an industry wide embrace for open source software has thankfully brought about some level of convergence in the components that together form a robust software delivery workflow.</p><ul><li><strong>Structured change management and auditing capabilities</strong></li></ul><p>Software development teams need a convenient way which enables them to quickly and reliably see how the code has changed over time, in particular what changed and at what point. This is especially crucial for enabling reliable rollbacks if (when) things go wrong.</p><ul><li><strong>Facilitating the generation of common code segments with internal modules, harnesses and templates</strong></li></ul><p>One of, if not, the only guaranteed strategy known for being effective when it comes to preventing software defects is to <strong>not</strong> writing any software at all. With libraries and frameworks being at the helm of most production apps, a lot of code nowadays is actually setup of boilerplate code or configuration. Creating easy to use code generating harnesses, using easily duplicated code templates or creating internal libraries to allow developers to not to have to worry about this at all are all common and well understood practices within software development teams.</p><ul><li><strong>A Technical design and documentation process</strong></li></ul><p>A good way to measure the developer user experience of a software system itself is to judge how easy it is for a new member of the team to own and deliver a code change to production. The key differentiator here is almost always the levels and forms of up to date documentation covering the system and how to build against it.</p><ul><li><strong>Continuous Integration and Continuous Deployments</strong></li></ul><p>Frequent releases should be the norm, which almost requires a high degree of automation for modern technology stacks due to the distributed nature of most newly built systems. Thankfully, CI/CD is now fairly common practice, with most technology service providers offering a range of tools, frameworks and integrations for your build technology and deployment methodology of choice.</p><ul><li><strong>A robust peer review process</strong></li></ul><p>People often overstate the purpose of pull requests by focusing on approving, or declining and critiquing code changes and sure, that’s certainly a large part of the deal. But there’s also something about general team awareness of how the code is being developed and a familiarity in reading how the code is being constructed that even a passive contribution to a PR helps build and maintain across the team.</p><ul><li><strong>A robust QA process</strong></li></ul><p>We come fully equipped with a test driven development process, automated testing, dedicated testing environments, user acceptance testing sessions with stakeholders and <em>still </em>we manage to release software with bugs. There is no right or wrong amount of testing, and it all depends on the specifics of your org, project and team but a QA process as a whole is basically a non-negotiable for most modern tech companies.</p><ul><li><strong>Monitoring and Debugging tools</strong></li></ul><p>A common yet often fatal flaw I’ve observed in software teams is overly siloed team functions with a hard handover or “throw it over the fence” approach to delivery. Most commonly, you see this in the form of a development team producing code for a product feature to then have this sent to a testing team which hopefully passes some QA bar to then finally be deployed by a release team. What this often turns into is a complete lack of wider ownership and teams narrowly focusing on their individual functions causing issues to fall by the cracks that software bugs often love to creep into.</p><p>One of the ways to combat this is to allow system health and system monitoring to be a team wide activity, hopefully detached from hard deliverables as to allow this to be something any engineer is empowered to engage in.</p><ul><li><strong>Integrations with task management and tracking tools</strong></li></ul><p>Save some of the video call exhaustion by allowing your stakeholders, project managers and anyone else who might be interested, to easily understand the status of the project and how it’s most likely to pan out going forward - instead of having <em>another</em> meeting.</p><ul><li><strong>Unopinionated code formatting tools</strong></li></ul><p>Another time saver! This is isn’t so much about sticking to the “<em>right</em>” way to write and structure code but more about leveraging standardisation to allow developers to rapidly parse code that has a familiar structure.</p><h3>Putting it all together using automation within GitHub’s toolset</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/480/1*UVXAx8VZmLNyBqT1PLdxvg.gif" /></figure><p>GitHub have spent the last few years expanding their developer tools to nicely accommodate more and more of the software development process. This feels like a sensible direction given that so much of the developer workflow is entrenched in version control and the code itself which naturally sits quite nicely in GitHub’s favour!</p><p>Let’s breakdown a few of the key features to demonstrate how they can empower a realistic use case when assembled together with a few other powerful tools.</p><p><strong>Our example use case: Building a web application with our 🔥 workflow</strong></p><p>Let’s take the common example of a business who needs to create a simple user data capture form in the style of a single page web application.</p><p>A fictional company (Koo2 ©) needs to build an application, which their users can access and use to submit their details. This web application will present the user with a series of questions, to then capture the user’s submitted answers and then finally securely store this user’s information in some fashion for later usage.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/200/1*JQvdFZ0kIISCNJjk-vQJBA.png" /><figcaption>Our fake tech company obviously needs branding</figcaption></figure><ul><li><strong>Breaking down and detailing the work via issues and using labels to keep things tidy 🕋</strong></li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*8-eULovP0SSWeBrwr6wgig.png" /></figure><p>Issues are a great way to define and categorise granular tasks. Project managers and/or engineers can easily create formatted documents using markdown, categorise and label tasks with things like priority and complexity, assign ownership, raise discussion points and tie these tasks back to a wider set of deliverables via milestones and projects.</p><p><em>Labels</em> are also great for detailed search, as you can essentially filter down task boards and progress trackers by any category that you choose to define.</p><ul><li><strong>Organising the Project using GitHub’s automation tools to allow tasks to track themselves 🚀</strong></li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*K0HZ62iVNRZmm4NDAS4ibQ.png" /></figure><p>This is where things start to get a bit more interesting. There are two key features about GitHub projects in particular that I <em>really</em> like.</p><ol><li>Linking repositories to projects means they automatically get added to your progress board.</li><li>You can use project settings to allow these to automagically update the status of a task upon key events like pull requests being approved or branches being merged.</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*z2bAZQjRR_RMLxc-_UjTCg.png" /></figure><ul><li><strong>Using Milestones to structure progress 📈</strong></li></ul><p>Milestones are a great way to “bundle” related tasks together to form broader deliverables and to track the progression rate of high level features.</p><p>Simply link the repository to the milestone and GitHub updates the status of the task in the milestone for you. 🤖</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*JcuWOzReyMCwlNsRNO0ITQ.png" /></figure><p>This gives us a really solid template to work from as the development team can now place their core focus on technical delivery by allowing their tools to facilitate project management and coordination with other team members.</p><ul><li><strong>Using GitHub Actions to automate the build and release process 📦</strong></li></ul><p>In order to fulfil our ambitions of creating a <strong>complete</strong> developer workflow, we’ll need to bring in a few more tools and tricks to round out our build process. We’ll then use GitHub actions to string this all together.</p><p><strong>Workflow components</strong></p><ol><li><a href="https://github.com/commitizen/cz-cli">Conventional commits</a> to formally version code changes. This is a really useful tool which facilitates the use of predefined commit message conventions in order to better communicate expectations to potential contributing team members.</li><li><a href="https://jestjs.io/">Jest</a> to run unit tests</li><li><a href="https://www.qawolf.com/">QAWolf</a> to run automated UI tests</li><li>Submitting changes for peer review</li><li><a href="https://www.chromatic.com/">Chromatic</a> and <a href="https://storybook.js.org/">Storybook</a> to help the team review and visualise in-progress visual changes</li><li><a href="https://developers.google.com/web/tools/lighthouse">Lighthouse</a> in order to audit the app for performance, accessibility, progressive web app friendliness, and SEO suitability</li><li><a href="https://www.zaproxy.org/docs/desktop/start/features/ascan/">ZAP Scan </a>to ensure the app is keeping in line with OWASP</li><li>Release 🎉</li></ol><p><strong>Putting our workflow into action</strong></p><p>Let’s start with the task of adding a telephone number question input to our Koo2 app.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1006/1*eboVmOLxRt7xxQV3PpOVpQ.png" /></figure><p>Most development teams use some variation of a <a href="https://guides.github.com/introduction/flow/">branch based workflow</a> to manage multiple and frequent changes to the code base. A great way to ensure that you’re getting the most out of this is to use a tool like <a href="https://github.com/commitizen/cz-cli">commitizen</a> to help us structure each commit in this way without having to think <em>too</em> hard about it.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/557/1*shdkgrQzxli1aHV29G4LNQ.png" /></figure><p>Once the code required to service our new telephone question screen has been added and corresponding unit or component tests have been written, the branch can be pushed up to the build server where we let our GitHub actions <strong>automatically</strong> kick in. Here’s exactly what’ll happen in sequence once we submit our pull request for peer review.</p><ol><li>The project board automatically picks up the change and updates itself with the task status</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*YpgjB6KVNVGEbS9z4ilo1Q.png" /></figure><p>2. Unit tests and automated tests are ran to check everything works as expected</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/742/1*zzdqeF0V1xLF0ZoGPzeqFg.png" /><figcaption>The build server installs the dependencies before running the build and test commands</figcaption></figure><p>3. Our UI components are rendered in Storybook to allow the team to visually review the changes and easily inspect what’s new at an interface level</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Jgf89pCRwbP9lnKbztRkjA.png" /><figcaption>Storybook provides a nice interface for inspecting your UI components and how they’ve changed</figcaption></figure><p>4. A ZAP scan is executed to ensure no major security vulnerabilities are compromising our system</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*dm9EUnHHWnbUtErwD1fmkg.png" /><figcaption>The output as produced on the build server</figcaption></figure><p>5. A lighthouse report is produced to ensure that our app is as performant and as accessible as possible. You also get a nice diff of how these latest changes impact the app’s lighthouse metrics.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*DpSOxkDv6r8vUSZPu0KftQ.png" /></figure><p>It’s completely up to your team what the bar is but this should give you a rough flavour of what a set of criteria for a good workflow could look like.</p><p>The final piece of our workflow is to allow the team to review and approve/decline the changes and for the pull request to be merged. Once this is done, the project board will once again automatically update the status of this task as completed and slot it in the right column. 🏁</p><p>All of this — automated via GitHub action scripts and commonly provided jobs to allow you to quickly compose the right workflow for your project! 🙏</p><p>Here’s a (simplified) sample of what these actions can actually look like at a code level.</p><pre>name: Run Security Scan</pre><pre>on: push</pre><pre>jobs:</pre><pre>  zap_scan:</pre><pre>    runs-on: ubuntu-latest</pre><pre>    name: Scan the webapplication</pre><pre>    steps:</pre><pre>      - name: ZAP Scan</pre><pre>      uses: zaproxy/action-full-scan@v0.2.0</pre><pre>      with:</pre><pre>      target: &quot;https://uri.to.your.app/&quot;</pre><pre>name: Deploy Story Book</pre><pre>on: push</pre><pre>jobs:</pre><pre>  test:</pre><pre>    runs-on: ubuntu-latest</pre><pre>    steps:</pre><pre>       - uses: actions/checkout@v1</pre><pre>       - run: npm install</pre><pre>       - uses: chromaui/action@v1</pre><pre>name: Test and Build</pre><pre>on: push</pre><pre>jobs:</pre><pre>  test:</pre><pre>    runs-on: ubuntu-18.04</pre><pre>    steps:</pre><pre>      - uses: actions/checkout@v2</pre><pre>     - run: npm install &amp;&amp; npm install -g @lhci/cli@0.5.x</pre><pre>     - name: Create production build</pre><pre>     run: npm run build</pre><pre>     - name: Run lighthouse audit</pre><pre>     run: lhci autorun</pre><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=3fc2143578d6" width="1" height="1" alt=""><hr><p><a href="https://medium.com/koodoo/using-automation-to-power-a-next-gen-development-workflow-3fc2143578d6">Using automation to power a next-gen development workflow</a> was originally published in <a href="https://medium.com/koodoo">Koodoo</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[5 tips  for running a remote Google Ventures Design Sprint for a B2B company]]></title>
            <link>https://medium.com/koodoo/5-tips-for-running-a-remote-google-ventures-design-sprint-for-a-b2b-company-66cc1dc68d12?source=rss----d73c858525b0---4</link>
            <guid isPermaLink="false">https://medium.com/p/66cc1dc68d12</guid>
            <category><![CDATA[product-management]]></category>
            <category><![CDATA[b2b]]></category>
            <category><![CDATA[design-sprint]]></category>
            <dc:creator><![CDATA[Andrei Lebed]]></dc:creator>
            <pubDate>Tue, 27 Oct 2020 11:21:45 GMT</pubDate>
            <atom:updated>2020-10-27T11:21:45.217Z</atom:updated>
            <content:encoded><![CDATA[<h3>5 tips for running a remote Google Ventures Design Sprint for a B2B company</h3><p><em>Intro: Starting from Monday 5th October, </em><a href="http://www.koodoo.io/"><em>Koodoo</em></a><em>’s product team ran a Google Ventures Design Sprint, focusing on a new product we’ve been looking to test and launch for a while, but haven’t had the bandwidth to give the time and effort that it deserves. It was our first ever Google Ventures Design Sprint, and we learned loads.</em></p><h3>What’s a Google Ventures Design Sprint?</h3><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2FK2vSQPh6MCE%3Ffeature%3Doembed&amp;display_name=YouTube&amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DK2vSQPh6MCE&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FK2vSQPh6MCE%2Fhqdefault.jpg&amp;type=text%2Fhtml&amp;schema=youtube" width="854" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/732d80bfb8f0d57256dd2c9a7e0494d0/href">https://medium.com/media/732d80bfb8f0d57256dd2c9a7e0494d0/href</a></iframe><p>Great video, thanks <a href="https://medium.com/u/f230699aec44">Jake Knapp</a>! If videos aren’t your thing, here’s a quick overview of the 5 day process and what it aims to achieve:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/589/1*eOvFuyDzGfSWeWv5lHd32Q.png" /></figure><h3>Tip 1: Expert interviewees don’t need to be members of your team/company</h3><p>The problem area that we were addressing was one that our team was very familiar with, so we decided to look further abroad and ask if other people in the industry would help be our experts. That way we could validate or invalidate our assumptions, and hopefully learn something new. For example, we had:</p><ul><li>Head of Mortgages from a Top 10 UK lender</li><li>Head of Mortgages Products and Pricing at a leading UK specialist lender</li><li>Head of Product from a leading software provider to a large proportion of the UK mortgage market</li><li>CEO from a leading open banking FinTech</li></ul><p>Honestly, at first I was a bit sheepish about asking people if they’d be experts in our process. <strong>Fortunately, people love being asked for their expert opinion, and we only asked for 30 minutes each.</strong> We got great insights and thoughts from all of our experts, who were really happy to help.</p><h3>Tip 2: In B2B companies, involving your business customers in the design sprint is incredibly powerful if you can manage it</h3><p>We are a bit unique in that we work incredibly closely with all of our partners, to the point that they often view us as an extension of their own team. Nevertheless, some of our expert interviewers were actually customers, and some of our Friday user tests were also potential customers.</p><p>On reflection, it was the quickest consultative sales cycle we’ve ever done, starting with “<em>understand your customers pain points and needs” </em>on Monday, and ending with <em>“present them with a prototype of a product that addresses them”</em> by Friday,<em> </em>with a clear idea on whether they want to buy it or not.</p><h3>Tip 3: Choose your sprint medium carefully, and in advance</h3><p>Ok, this is more practical, but it’s an important one. My team pointed out that there were already some great remote design sprint templates out there that we could utilise, rather than trying to reinvent the wheel.</p><p>We used the ‘official’ template on Mural. (<a href="https://design-sprint.com/remote-design-sprint-template/">https://design-sprint.com/remote-design-sprint-template/</a>) — which was awesome because it had the entire process, instructions and resources already set up for you, and the collaboration settings like timers, voting, and ‘following users’ were perfect for the design sprint. Arguably, it was easier to run remotely than in person!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*9ydAfpgHmrcu8c0yX5lrvg.png" /><figcaption>The remote design sprint template on Mural that we started with</figcaption></figure><h3>Tip 4: Be realistic — allow for ‘business’ time with clear boundaries and breaks</h3><p>As much as you’re meant to be 100% focused on the design sprint for a week between 10–5pm, when you’re a small product team in a scaling startup in the middle of two major launches, having a no-distraction week just isn’t possible.</p><p>We accepted this from the start, and carefully planned the design sprint around the commitments in the diary that we couldn’t miss. We also accepted that not everybody would be needed for every part of the design sprint, and the flexibility worked out pretty well, and we managed to deliver on our launch. <strong>Boy it was a tough week though.</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/500/1*6lLKfGx8DPlG1eTIs5pAVw.gif" /><figcaption>Koodoo’s product team on Friday of the design sprint</figcaption></figure><h3>Tip 5: The design sprint week is just the beginning — have a plan for how the outputs feed into your wider strategy</h3><p>This is the most important one for me. Ask yourself: <strong>What’s next after the design sprint? How will we take the learnings and the outputs and progress them to the next stage of sales or development?</strong></p><p>Rightly or wrongly, before we even started the design sprint, we had agreed to unveil a new product at an industry webinar a few weeks after the sprint. We just needed to work out what that product was and how it looked, which is what the design sprint was for.</p><p>Having a clear ‘next stage’ after the design sprint gave us even more focus, and was really helpful in deciding scope. When considering whether to include features in our prototype, we could make sensible decisions such as ‘<em>we don’t </em><strong><em>need</em></strong><em> that as a feature to test our sprint hypotheses this week, but we’ll </em><strong><em>want</em></strong><em> to put that in the prototype before the big reveal in a few weeks’ time’.</em></p><p>In summary, a design sprint can be a powerful tool for a B2B business, providing you frame it correctly. Before you launch one, you’ll want to make sure that you:</p><ul><li>Have a clear vision for how the design sprint feeds into your wider product strategy</li><li>Know who your business customers are and how you can involve them in the design sprint process (arguably this takes more planning and effort than the B2C flavour)</li><li>Frame the output of the design sprint to customers as something that can be ‘bought’— as well as learning what works and what doesn’t, you’ll want to get that magical early product validation that it is something that your customers find valuable enough to pay for, before you spend precious time and money building it.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/800/0*UFdj9AWmKF_AGH2R.png" /></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=66cc1dc68d12" width="1" height="1" alt=""><hr><p><a href="https://medium.com/koodoo/5-tips-for-running-a-remote-google-ventures-design-sprint-for-a-b2b-company-66cc1dc68d12">5 tips  for running a remote Google Ventures Design Sprint for a B2B company</a> was originally published in <a href="https://medium.com/koodoo">Koodoo</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[TLA+ for startups (part 2)]]></title>
            <link>https://medium.com/koodoo/tla-for-startups-part-2-1ef288adab39?source=rss----d73c858525b0---4</link>
            <guid isPermaLink="false">https://medium.com/p/1ef288adab39</guid>
            <category><![CDATA[specifications]]></category>
            <category><![CDATA[tla-plus]]></category>
            <category><![CDATA[formal-methods]]></category>
            <category><![CDATA[software-design]]></category>
            <category><![CDATA[systems-thinking]]></category>
            <dc:creator><![CDATA[Neil O'Connor]]></dc:creator>
            <pubDate>Fri, 06 Dec 2019 10:58:31 GMT</pubDate>
            <atom:updated>2019-12-12T15:18:47.001Z</atom:updated>
            <content:encoded><![CDATA[<h4>The elevator pitch</h4><p><em>This is the second in a series of articles on why the use of formal specification languages — and specifically the language TLA+ — isn’t a completely mad idea for startups. In fact, </em><a href="https://medium.com/koodoo/tla-for-startups-part-1-8b162863824b"><em>I made the case in the first article</em></a><em> that they could actually prove to be a match made in heaven.</em></p><p><em>You may agree or disagree with my claim at your own discretion. But I will plough on and start working through a problem using TLA+, and we’ll see if it helps or hinders.</em></p><h3>Caveat emptor</h3><p>Let’s clear one thing up from the start: <strong>I’m not going to attempt to teach you about the theory of TLA+ or how to use it</strong>. I’m also not going to make any further attempts to sell its merits to you, beyond what I wrote in the first article.</p><p>At the time of writing, I have learned what I consider to be the minimum amount necessary to roll my sleeves up and make a start. I have read Hillel Wayne’s book, <a href="https://www.amazon.co.uk/Practical-TLA-Planning-Driven-Development/dp/1484238281/ref=sr_1_1">Practical TLA+</a>, I have worked through <a href="http://lamport.azurewebsites.net/video/videos.html">Leslie Lamport’s Video Tutorials</a>, I have installed the <a href="https://lamport.azurewebsites.net/tla/toolbox.html">relevant tools</a>, and I have watched and read a few interesting blog posts and conference talks.</p><p>I have a background in Computer Science and a reasonable head for mathematics, but I think any logically-minded person could get to the same stage as I am currently at, with a little application.</p><p>From this point on, I’ll dive straight into describing the problem domain and attempting to model it in TLA+. I’ll talk you through my thought processes as I go along, and will add the occasional explainer for certain important constructs, but otherwise will assume you know what they mean.</p><h3>The Elevator Pitch</h3><p>Our problem domain will be <strong>elevator control software</strong>. Over on this side of the pond we call them lifts.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*44o14m7kvJAvIKkhpTtOtQ.jpeg" /><figcaption>A typical British lift</figcaption></figure><p>Why do I think this is an interesting problem to model?</p><ol><li>Everyone reading this, with the possible exception of claustrophobes, will have used an elevator. Even the claustrophobes will understand the basics of how an elevator operates.</li><li>At its simplest, the control software for elevators should be pretty straightforward to model, so we can start with some easy but valid examples (e.g. 1 car, 2 storeys).</li><li>However, the problem gets exponentially more complex as you add more cars, more storeys and more safety features. This should allow us to validate that TLA+ is indeed capable of modelling these more complex scenarios without brain-melting amounts of extra effort.</li><li>They are a nice example of a finite state machine, which TLA+ is ostensibly good at modelling.</li><li>We can make suitable abstractions without compromising the usefulness of the solution. For example, we can model the logic about how calls to the elevator are received and serviced, without having to worry about the mechanics of how the elevator actually moves — gears, pulleys, power, door mechanisms, etc. We can reasonably assume that someone else has got all that covered.</li></ol><p>Agreed? OK, let’s get stuck in.</p><h3>The entry-level elevator</h3><p>Leaving aside the simplest possible elevators, such as manually operated ones or stairlifts, the entry-level elevator that would benefit from control software would be one that:</p><ul><li>Has a single car</li><li>Travels between just two floors/storeys (I’ll use the words interchangeably, sorry!)</li><li>You can press a button from either floor to call the car (and even if it’s in use, it remembers your call request)</li><li>Once inside the car, you just press a ‘go’ button and don’t have to select the destination floor</li><li>Doesn’t have any pauses built into its behaviours (allowing passengers time to enter and exit)</li></ul><p>We might visually represent it like this:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/503/1*l8_RAk4OlgtPXR5afRd1QA.png" /></figure><p><em>(American readers will be happy with the numbering above, but may not realise we Europeans call the storey at ground level the “ground floor” or simply “0”. I prefer the European convention, but we’ll go with the American convention for one simple reason: TLA+ sequences are 1-based!).</em></p><p>You might at this point wish to politely point out that elevators without doors are a little dangerous. But they wouldn’t be the first — I spent many a happy afternoon hopping on and off the <a href="https://www.bbc.co.uk/news/av/uk-england-south-yorkshire-42997131/sheffield-university-s-paternoster-lift-in-motion">paternoster elevator</a> during my university years in Sheffield. For now, let’s accept it as a valid simplification.</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fgiphy.com%2Fembed%2FdvvcYruZSxAfm%2Ftwitter%2Fiframe&amp;url=https%3A%2F%2Fmedia.giphy.com%2Fmedia%2FdvvcYruZSxAfm%2Fgiphy.gif&amp;image=https%3A%2F%2Fi.giphy.com%2Fmedia%2FdvvcYruZSxAfm%2Fgiphy.gif&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=giphy" width="435" height="435" frameborder="0" scrolling="no"><a href="https://medium.com/media/1f149cfcbadddf02b54d07524aeb7d96/href">https://medium.com/media/1f149cfcbadddf02b54d07524aeb7d96/href</a></iframe><h4>Let’s make a start</h4><p>Let’s start writing our TLA+ spec. We’ll start by trying to define our constants, variables and initial state. Let’s say the set of known Storeys is a subset of the set of Integers, with the car’s initial location being at an arbitrary storey.</p><p>We’ll prefix our state formulas and actions with EC for “Elevator Controller”.</p><pre><strong>CONSTANTS</strong> Storeys</pre><pre><strong>VARIABLES</strong> carLocation</pre><pre><strong>ASSUME</strong> Storeys \subseteq Int</pre><pre>ECInit == carLocation = <strong>CHOOSE</strong> s \in Storeys : TRUE</pre><p><em>Remember that the CHOOSE operator indicates that an arbitrary value could be selected for carLocation from the set of available storeys. This is not the same thing as saying it WILL select one of those values or telling it HOW to select one— we are building a specification to check, not code to execute.</em></p><p><strong><em>UPDATE: </em></strong><em>Following helpful feedback from the TLA+ community, it was pointed out that the use of the CHOOSE operator here could mask an error, as it may leave some states unexplored (it will fix the carLocation to an arbitrarily chosen value). Instead, we can simply use carLocation \in Storeys to explore all possible starting states.</em></p><p>Are we happy with that? Well, for one thing, it assumes the system is starting up with the car positioned at a storey and not between two storeys. Probably a reasonable assumption for the time being. Perhaps we should’ve called the <em>carLocation</em> variable <em>carLastHaltedLocation</em>, but let’s keep it simple for now!</p><p>What else can we assume about our starting state? We can assume something about the car’s movement. For now we will define the car’s potential movement states as “idle”, “going up” or “going down”, which we will represent numerically as 0 for idle, 1 for going up and -1 for going down.</p><p>The changed bits of the spec now look like this:</p><pre><strong>VARIABLES</strong> carLocation, carTravelStatus</pre><pre>ECInit ==<br>    /\ carLocation \in Storeys<br>    /\ carTravelStatus = 0</pre><p>We can also assume something about the status of the two ‘call’ buttons on the walls and the ‘go’ button inside the car, namely that they are all in a ‘clear’ state.</p><pre><strong>VARIABLES</strong> carLocation, carTravelStatus, callRequest, goRequest</pre><pre>ECInit ==<br>    /\ carLocation \in Storeys<br>    /\ carTravelStatus = 0<br>    /\ callRequest = [s \in Storeys |-&gt; 0]<br>    /\ goRequest = 0</pre><p><em>I’m not going to explain every concept or construct as we go along, but this one, or a variant of it, is something you will see a lot of in TLA+ specs:</em></p><pre>callRequest = [s \in Storeys |-&gt; 0]</pre><p><em>callRequest is here defined as a function where each value of set Storeys maps to the value of 0. As the set Storeys currently only contains the values 1 and 2 for our simple elevator, this might be written as follows: callRequest[1] = 0 and callRequest[2] = 0.</em></p><p><em>This is an example of a very elegant operator in TLA+, which enables you to describe something fairly complex about the properties of the system you are modelling without having to worry about how you might implement it in code.</em></p><h4>What’s next?</h4><p>We’ve defined a fairly rudimentary starting state. Now we will go about identifying some potential next states (known as “actions” in TLA+).</p><p><strong><em>Car is called</em></strong></p><p>The first ‘next state’ action we will describe is that the elevator is called from the other floor. Visually we could represent this as follows (a button is lit up after being pressed):</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/503/1*OQxHCuodPonEm6k-O0GfhA.png" /></figure><p>Here’s how we’ll write this in TLA+:</p><pre>ECNextCall(s) ==<br>    /\ callRequest[s] = 0<br>    /\ callRequest&#39; = [callRequest <strong>EXCEPT</strong> ![s] = 1]<br>    /\ <strong>UNCHANGED</strong> &lt;&lt; carLocation, carTravelStatus, goRequest &gt;&gt;</pre><p><em>Let’s break this down into plain English as best we can.</em></p><p><em>callRequests[s] = 0 means that, for the storey our elevator is being called from, the callRequest record has a ‘before’ value of 0 (i.e. it wasn’t already called).</em></p><p><em>callRequest’ = [callRequest EXCEPT ![s] = 1] means that the elevator hasn’t been called from any other storey, only s, so the value of the callRequest[s] will be 1.</em></p><p><em>The UNCHANGED line means that none of our other variables are modified.</em></p><p>So essentially what we have described here is that one possible next state is that a call request is made, turning the 0 to 1 in the relevant <em>callRequest</em> record, and nothing else changes in the process.</p><p><strong><em>Service a call</em></strong></p><p>Another ‘next state’ action we will describe is that the elevator proceeds to the storey from which it has been called:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/503/1*VE_zsN5NB5xoQ6zppU1qVg.png" /></figure><p>In our specification, we now need to reflect the fact that the car is moving in this state:</p><pre>ECNextServiceCall(s) ==<br>    /\ carLocation # s<br>    /\ carTravelStatus = 0 <br>    /\ carTravelStatus&#39; = <strong>IF</strong> s &gt; carLocation <strong>THEN</strong> 1 <strong>ELSE</strong> -1<br>    /\ <strong>UNCHANGED</strong> &lt;&lt; callRequest, goRequest, carLocation &gt;&gt;</pre><p><em>What does this mean?</em></p><p><em>carLocation # s means that the car’s current location is not the same as the storey it was called from.</em></p><p><em>The two conditions for carTravelStatus mean that the car was not already moving, and that it either goes up or down depending on whether the call came from the upper floor or the lower floor.</em></p><p><em>The UNCHANGED bit means that the callRequest remains in place, and carLocation remains unchanged, until the elevator gets there (and goRequest is also unaffected).</em></p><p><strong><em>Car arrives after call</em></strong></p><p>Our next potential action will describe the car arriving at the requested floor, as shown by:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/503/1*nQUn5OJ85dGHjGeWXRMeCw.png" /></figure><p>We will specify this in TLA+ as:</p><pre>ECNextArriveCall(s) =<br>    /\ carLocation # s<br>    /\ carTravelStatus # 0<br>    /\ callRequest[s] = 1<br>    /\ carLocation&#39; = s<br>    /\ carTravelStatus&#39; = 0<br>    /\ callRequest&#39; = [callRequest <strong>EXCEPT</strong> ![s] = 0]<br>    /\ <strong>UNCHANGED</strong> &lt;&lt; goRequest &gt;&gt;</pre><p><em>Breaking this down:</em></p><p><em>carLocation before entering this state was NOT the storey being arrived at (s), but after entering this state it is.</em></p><p><em>carTravelStatus # 0 describes that the car was in motion, but upon arriving carTravelStatus’ = 0 means it then stops moving.</em></p><p><em>callRequest was 1 for the target storey before the car arrives, but becomes 0 after the car arrives; all other callRequest records remain unchanged.</em></p><p><strong><em>Go request</em></strong></p><p>So people can request the car from another storey, but passengers can’t yet tell it to go once they get in! So let’s visualise that:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/503/1*xtK9mrkk5h2B6w0OrkJvow.png" /></figure><p>We will specify this as follows:</p><pre>ECNextGoRequest ==<br>    /\ goRequest = 0<br>    /\ carTravelStatus = 0<br>    /\ goRequest&#39; = 1<br>    /\ carTravelStatus&#39; = <strong>IF</strong> carLocation = 1 <strong>THEN</strong> 1 <strong>ELSE</strong> -1<br>    /\ <strong>UNCHANGED</strong> &lt;&lt; carLocation, callRequest &gt;&gt;</pre><p>So when the passenger hits the Go button, if it wasn’t pressed already, the car starts moving towards its destination.</p><p>Oh wait. There might be a flaw in this. Just by starting to write out the action formula, and identifying the preconditions (unprimed variables) and postconditions (primed variables) of the action, it made me realise something: what if I got in the car, and before I could hit the Go button, someone else on the other floor hit the Call button? Should I then be able to hit Go anyway and see it light up? I think I should.</p><p>The point here is not that we need to find the perfect solution right away, but the act of attempting to write the specification has forced me to think about edge cases or “non happy path” behaviours. It’s a perfectly valid behaviour for an elevator — and one that is no doubt happening all over the world right now as we speak — for the car to start moving towards another storey before the passenger has managed to select their preferred destination. TLA+ helps us to reason about these behaviours in a formal way.</p><p>For now, let’s split out the Go request from the servicing of the request:</p><pre>ECNextGoRequest ==<br>    /\ goRequest = 0<br>    /\ goRequest&#39; = 1<br>    /\ <strong>UNCHANGED</strong> &lt;&lt; carTravelStatus, carLocation, callRequest &gt;&gt;</pre><p><em>Translated, this now means the goRequest moves from a 0 to 1 when entering this state, and that’s it. We’re assuming nothing else about the location or travel status of the car, or any call requests made from the storeys.</em></p><p><strong><em>Service the Go request</em></strong></p><p>So now we can have an unfulfilled Go request, we need an action where that request is serviced — i.e. the elevator heads to its requested destination.</p><pre>ECNextServiceGoRequest ==<br>    /\ goRequest = 1<br>    /\ carTravelStatus = 0<br>    /\ carTravelStatus&#39; = <strong>IF</strong> carLocation = 1 <strong>THEN</strong> 1 <strong>ELSE</strong> -1<br>    /\ <strong>UNCHANGED</strong> &lt;&lt; goRequest, carLocation, callRequest &gt;&gt;</pre><p><em>That is: given a go request and a non-moving car, in this state the elevator will start moving up or down, depending on the current location.</em></p><p><strong><em>Car arrives after Go request</em></strong></p><p>Similar to the call request, we will specify the action where the car arrives after fulfilling its go request. Note that in this action and the previously described action, we did not specify (s) behind the action name. This is because it does not need to be parameterised for the storey — there’s only one go button, whereas there are <em>n</em> call buttons (where <em>n</em>=2<em> </em>in our simple elevator system).</p><pre>ECNextArriveGoRequest ==<br>    /\ carTravelStatus # 0<br>    /\ goRequest = 1<br>    /\ carLocation&#39; = <strong>IF</strong> carLocation = 1 <strong>THEN</strong> 2 <strong>ELSE</strong> 1<br>    /\ carTravelStatus&#39; = 0<br>    /\ goRequest&#39; = 0<br>    /\ <strong>UNCHANGED</strong> &lt;&lt; callRequest &gt;&gt;</pre><p><em>As the elevator arrives from servicing a go request, the carLocation will flip from either storey 1 to storey 2, or vice versa.</em></p><p><em>The carTravelStatus will change from moving (not 0) to not moving (0).</em></p><p><em>The goRequest will be cancelled once the car arrives; callRequests remain unchanged.</em></p><h4>Putting it all together</h4><p>We’ve so far specified an elevator system that has one car, travelling between two storeys, which can be called by waiting passengers, will move to service such a call, and will cancel the call request once it has arrived.</p><p>If a passenger enters the elevator car and hits the Go button, the car will move to the other storey, and when it arrives, the ‘go’ request will be cancelled.</p><p><strong><em>The full next-state formula</em></strong></p><p>Given all the individual actions described above, our full next-state formula can be defined as follows:</p><pre>ECNext ==<br>    \/ \E s \in Storeys :<br>        \/ ECNextCall(s)<br>        \/ ECNextServiceCall(s)<br>        \/ ECNextArriveCall(s)<br>    \/ ECNextGoRequest<br>    \/ ECNextServiceGoRequest<br>    \/ ECNextArriveGoRequest</pre><pre>vars == &lt;&lt; carLocation, carTravelStatus, callRequest, goRequest &gt;&gt;<br>Spec == ECInit /\ [][ECNext]_vars</pre><p><em>In case you weren’t already aware, the indentation in TLA+ is significant. The above means that our universal next state (ECNext) is a logical disjunction between the three possible actions parameterised by a storey identifier (elevator is called) and three possible actions without a storey identifier (elevator is asked to go by a passenger inside it).</em></p><p><em>The construct \E s \in Storeys : can be read as “there exists a value s in the set of all Storeys where…”. The TLC model checker will interpret this construct by attempting to fulfil the next state using any valid value from the set Storeys.</em></p><p><strong><em>Invariants</em></strong></p><p>We also want to describe in a formula all of the things that should remain true in all states of our system. We’ll start simple, as follows:</p><pre>ECTypeOK ==<br>    /\ carLocation \in Storeys<br>    /\ carTravelStatus \in {-1, 0, 1}<br>    /\ callRequest \in [Storeys -&gt; {0, 1}]<br>    /\ goRequest \in {0, 1}</pre><p><em>The above is pretty uncontroversial. We’re checking that the car is always at a valid floor, that it’s always either stationary, going up or going down, that the callRequests are from the valid combination of call requests for our known floors, and that the Go request is either on or off.</em></p><p><em>These aren’t particularly taxing — we’ll have a go at making those a bit more meaningful later.</em></p><h4>Does it work?</h4><p>We’re ready to give our specification a spin. I won’t share the complete source code, as I think there’s more value in you putting it together yourself and understanding each bit at a time :)</p><p>Here’s how your model might look:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*I4ydmOSUfvhEE2eAZ9S1zw.png" /></figure><p>When we run this through the model checker, it works! We get 90 states and 32 distinct states. We have a working elevator!</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fgiphy.com%2Fembed%2F101FTJFnTnNi5W%2Ftwitter%2Fiframe&amp;url=https%3A%2F%2Fmedia.giphy.com%2Fmedia%2F101FTJFnTnNi5W%2Fgiphy.gif&amp;image=https%3A%2F%2Fi.giphy.com%2Fmedia%2F101FTJFnTnNi5W%2Fgiphy.gif&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=giphy" width="435" height="244" frameborder="0" scrolling="no"><a href="https://medium.com/media/f718c082f562273ec566163a65ed8b96/href">https://medium.com/media/f718c082f562273ec566163a65ed8b96/href</a></iframe><h3>What have we learned?</h3><p>This was a pretty simple elevator, and only our first iteration.</p><p>But despite this, I think that just going through the process of identifying the different significant components of our system, and considering how that translates to variables and state changes (actions), helped me to conceptualise my system better.</p><p>We’ve made several important simplifications, such as not modelling doors, and keeping to one car and two storeys. By identifying those simplifications and attempting to codify them in a TLA+ specification, I feel I have a better understanding of the dimensions along which my system is going to get more complex.</p><p>Although I didn’t talk you through every step of my thought process, I found the construction of the next-state formulas (“actions”) to be particularly useful. In my first attempt, I started writing the <em>ECNextGoRequest</em> state formula with a behaviour in mind that as soon as the elevator passenger hit the Go button, it would set off for its destination. However, just by starting to write down the conditions of this action formula, I realised that there was a perfectly valid edge case behaviour I’d missed, and this led to the addition of the <em>ECNextServiceGoRequest</em> action.</p><blockquote>The very act of trying to describe your system in unambiguous terms is itself a very thought-clarifying process. This is why many advocates of TLA+ consider the journey of formal system specification to be just as important as the destination.</blockquote><p>There were other micro-decisions like this that I’ve not documented in this article which helped me conceptualise my system.</p><p>There were also decisions I’m not happy with yet: for example, the formulas for servicing/arriving for calls are very similar in nature to those for Go requests, and I wonder if I should refactor them... but then I am also aware that I’m not trying to write clean code here, I’m trying to model a system’s intended behaviours with as much clarity as possible. So the jury’s out on that one! I’m sure the dilemma will evolve as we add complexity to the system.</p><h3>A couple of gotchas</h3><p>There were a couple of things I noticed were wrong as I was writing my specification. Did you notice them too?</p><p>I’ll let you try to find them. If you spotted them straight away, then well done, you are clearly able to reason about multivariate state machines better than most! But even if you are feeling smug about that, I hope you can also see that spotting anomalous behaviours in a system will only get exponentially harder as we increase the complexity. After all, this is a really, <em>really</em> simple elevator!</p><p>If you didn’t spot them, sorry but I’m not going to reveal them yet. I want to see if the next iteration of our specification helps us to tease out these anomalies.</p><p>The model checker didn’t spot these gotchas because our model is currently very naive. Our invariant check formula only checks for things that really ought to be true unless something went badly wrong (e.g. we somehow managed to send our elevator to floor 3 even though we don’t have one).</p><p>It doesn’t check for more subtle behaviours that might result in our elevator behaving erratically or counterintuitively for the passengers. For these we need more sophisticated checks — and this is where the T in TLA+ comes in. We need temporal checks (i.e. things that we want to be true across an end-to-end behaviour, rather than true simply for all reachable states).</p><p>This will be the subject of the next blog post in this series.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=1ef288adab39" width="1" height="1" alt=""><hr><p><a href="https://medium.com/koodoo/tla-for-startups-part-2-1ef288adab39">TLA+ for startups (part 2)</a> was originally published in <a href="https://medium.com/koodoo">Koodoo</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[TLA+ for startups (part 1)]]></title>
            <link>https://medium.com/koodoo/tla-for-startups-part-1-8b162863824b?source=rss----d73c858525b0---4</link>
            <guid isPermaLink="false">https://medium.com/p/8b162863824b</guid>
            <category><![CDATA[specifications]]></category>
            <category><![CDATA[startup]]></category>
            <category><![CDATA[software-design]]></category>
            <category><![CDATA[software-development]]></category>
            <category><![CDATA[tla-plus]]></category>
            <dc:creator><![CDATA[Neil O'Connor]]></dc:creator>
            <pubDate>Mon, 25 Nov 2019 16:36:18 GMT</pubDate>
            <atom:updated>2019-12-12T15:02:00.218Z</atom:updated>
            <content:encoded><![CDATA[<h4>Why formal specifications are not a completely insane idea for startups and small teams</h4><p><em>This is the start of my personal and professional journey into the formal specification language TLA+. Before we dive into the details, I should probably begin by explaining my motivation for creating this series of articles.</em></p><h4><strong>Startup life: right thing, right time, done right</strong></h4><p>In my professional life, I build and run software development teams that create business systems using some of the latest technologies and methodologies. The systems we build are complex, but not Apollo programme or nuclear power plant complex. Thousands of lives may not depend on us writing robust, reliable and correct code; but if we write brittle, unreliable and faulty code, the company’s reputation will suffer, our clients’ reputation will suffer, and we will lose money.</p><p>The quality of the systems we build could make the difference between us winning in our chosen business domain and failing, badly. As I work in startups, marginal losses from poorly thought-out business strategies, poor tactical choices, or badly written code can take you very quickly indeed to the end of the road.</p><p>So there is a very real incentive in my world to create software systems that are <strong><em>right</em></strong>. Now there’s a funny word. That could mean a lot of different things to a lot of people. At one end of the spectrum, I could spend millions (somebody else’s millions, that is) creating a software solution that fully solves every significant problem in my company’s chosen business domain… only to find that there is no market appetite for 90% of what we’ve built, and as a result we will never come close to recovering the cost of the build.</p><p>Or I could create a super-lean, MVP solution to a very specific problem, promote it aggressively to gain traction in the market quickly… only to find that the shortcuts we made in getting there quickly come home to roost, while I watch a competitor coolly and calmly launch their product three months later that fixes all the shortcomings in our solution.</p><p>In short, the reason why startup life is a lot harder than it looks is that you generally have one shot at getting it right. And that means you have to <strong>build the right thing</strong>, and you have to <strong>build that thing right</strong>. Oh, and you have to do all that <strong>at exactly the right time</strong>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/960/1*f77fO4kegpIMMNwXg9q5dg.png" /></figure><h4><strong>Pragmatism is King</strong></h4><p>Common sense would have it that, to hit the sweetspot in the middle of the Venn diagram above, the startup tech lead has to be supremely pragmatic. If you think you can succeed in the startup world by overburdening your team with detailed processes, design frameworks and formal practices, you will have a very rude awakening. You have to be lean and mean; fast and furious. You have to be the gazelle to the corporate dinosaur; the speedboat to the corporate oil tanker.</p><blockquote>Conventional wisdom would tell you that formal specification languages are wholly unsuited to startup life</blockquote><p>If common sense tells you that you have to be fast, lean and supremely pragmatic, then conventional wisdom would also tell you that formal specification languages are wholly unsuited to startup life. It would probably be safe to assume that, on a continuum of the amount of effort invested in the design stage of software, most people would place formal specification languages way over on the right. Startups should be picking from somewhere near the left, and ought to be leaving formal specification languages to the superbrains designing missile targeting systems for fighter jets.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/955/1*r-9XtO85rsozhW6jaLhGHw.png" /><figcaption>How we typically think of the amount of design effort, and who it is suited to</figcaption></figure><p>But is that true?</p><h4><strong>Luck be a lady tonight</strong></h4><p>Thinking about the Venn diagram and the continuum diagram together, we have a contradiction. On the one hand, we’ve identified that startups typically have one shot at getting it right (right thing, right time, done right). But on the other hand, conventional wisdom tells us that we need to do it with almost the lowest possible amount of investment in the design stage (also known as the thinking stage).</p><p>In other words, if we are to succeed, we’re going to need to get very, very lucky.</p><p>So what are you, our long-suffering startup tech lead, to do? Should you gradually and gently be moving rightwards on the continuum of pain? Maybe at first asking your team to sketch out their designs on a whiteboard before writing code? Then when that no longer feels fit for purpose, employ a BA to start writing something that at least <em>looks</em> a bit more thought-out? And then maybe 12 months later give one of your best developers an “architect” title and ask them to start drawing proper diagrams? You vaguely remember that formal specification module you did for a semester on your CS degree all those years ago, and you tell yourself that maybe you’ll find a use for it one day… but of course you’re not building software for controlling the coolers in nuclear reactors so… y’know.</p><p>While you are pondering your journey along the continuum of formal design, there’s a pretty decent chance that you have been distracted by some pretty major firefights in v1 of your solution; the lead developer you would’ve given the architect title didn’t turn up to work three weeks ago last Monday and you haven’t seen her since; the client you were counting on winning won’t sign the contract because they kept getting timeouts on your demo environment.</p><p>Perhaps all this could have been avoided if you had done a bit more design upfront, but hindsight is a wonderful thing, and frankly you didn’t have the time.</p><p>Before you know it, your startup dream is lying in tatters.</p><p>As I say, you’re going to need a lot of luck.</p><h4><strong>Thinking is underrated</strong></h4><p>That was a lot of preamble to bring me to the real point of this first article in the series ‘<em>TLA+ for startups’</em>.</p><p>I guess the title gives it away. I would like you to throw out your preconceptions about formal specification languages. Despite what you might think, they’re not just reserved for arcane computer science problems or hyper-critical systems.</p><blockquote>Most importantly of all, TLA+ <strong>helps you THINK</strong> about the problem you are trying to solve</blockquote><p>Although it builds on a rich history of formal specification theory and practice, TLA+ has been designed for solving real-world computing problems. But most importantly of all, TLA+ helps you THINK about the problem you are trying to solve.</p><p>It can be applied to a wide range of computing problems from simple algorithms through to large scale distributed architecture designs. It does not require years of training or a PhD to get started, just a grounding in some relatively straightforward mathematical concepts.</p><p>I believe that TLA+ enables software engineers and systems analysts, for the first time, to <em>practically</em> and <em>formally </em>reason about the code they are going to write before they write it.</p><p>The <em>formally </em>part I will leave to a later article, or indeed point you to some of the links sprinkled throughout this or later articles. Other people far smarter than me can explain why <em>formal</em> reasoning about systems using the universal language of mathematics is an incredibly powerful and useful thing to do.</p><blockquote>The very act of attempting to describe the properties of some code you are planning to write is often enough to spark a new way of thinking about it</blockquote><p>But <em>practically</em>, because despite what you might assume, it is definitely possible to get started with TLA+ quickly and start leveraging value from it right away. The very act of attempting to describe the properties of some code you are planning to write is often enough to spark a new way of thinking about it; to reveal a nuanced insight into the problem that you are trying to address; to tease out a logical flaw in your assumptions.</p><p>I often advise engineers on my teams to either sketch a design or write down in plain English the main tasks that they will need to complete before writing any code. The reason I suggest this is that doing so forces your brain to conceptualise the problem in a subtly different way, and the result will often be quite enlightening.</p><p><em>***In these two similar lectures (</em><a href="https://channel9.msdn.com/Events/Build/2014/3-642"><em>here</em></a><em> and </em><a href="https://www.youtube.com/watch?v=-4Yp3j_jk8Q"><em>here</em></a><em>), Leslie Lamport, inventor of TLA+, explains the importance of thinking above the code, and how TLA+ helps you to do that.***</em></p><h4><strong>Eating the elephant</strong></h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/771/1*WFTvyTduroh8RMpVjM3-aw.png" /><figcaption>There’s no need to eat the whole elephant</figcaption></figure><p>You can start by using TLA+ or its alter-ego PlusCal to describe a small part of your system. Perhaps there is a short but non-trivial algorithm or logical flow in your system that you are pretty sure you can just go ahead and code, but you want to just validate your thinking on it before you do. Once you’ve got your head around the basic structures and semantics of TLA+, this would be a perfect candidate to get started on.</p><p>Importantly, you do not need to eat the whole elephant in one go. If your first use case for employing TLA+ in your design process is describing a high throughput, highly parallelised, distributed software architecture, you’re going to get your fingers burned. Or should I say you’re going to choke on a tusk.</p><h4><strong>Recalibrate your thinking</strong></h4><p>I would urge you to recalibrate your thinking about the role that formal specification languages can play in your design process. I would argue that TLA+ makes it possible for you to introduce some formality into your design process much, much earlier than before, and indeed I would recommend introducing it BEFORE considering other structured design practices such as UML.</p><p>I’m not arguing against using these practices — they can be extremely useful. I’m arguing for easing into the habit of formally describing the intended behaviours of your system so early on that it becomes second nature. It is something that you and your engineers and analysts <em>can practically do </em>before you need to consider more heavyweight, structured processes that will inevitably come as your company grows.</p><blockquote>This series of articles attempts to make the case that TLA+ and startups are actually very happy bedfellows</blockquote><p>In short, this series of articles attempts to make the case that TLA+ and startups are actually very happy bedfellows. It gives you a toolset by which you can improve your thinking and reduce your chances of making those critical design mistakes early on, with surprisingly low upfront investment. For the specific challenges that startups face, as discussed at the top of this article, that little bit of extra <em>thinking</em>, done in the right way, could be the difference between glory and ignominy.</p><p><em>*** In </em><a href="https://www.youtube.com/watch?v=_9B__0S21y8"><em>this video</em></a><em>, Hillel Wayne (author of </em><a href="https://www.amazon.co.uk/Practical-TLA-Planning-Driven-Development/dp/1484238281/ref=sr_1_1"><em>Practical TLA+</em></a><em> and the </em><a href="https://learntla.com/"><em>LearnTLA+ website</em></a><em>), does a very good job of demystifying the core concepts of TLA+ and demonstrating how it can be used practically for smaller problem domains.***</em></p><h4><strong>What to expect</strong></h4><p>Now I’ve made the case for tech startups considering adding TLA+ into their armoury, in subsequent articles I will get practical. I’m going to build up an example of a real-world system that everyone can relate to, one that is simple to understand but a little more difficult to reason about. I’ll use TLA+ to help me do so.</p><p>I am definitely not an expert on TLA+, and might never be. Rather than just talking the talk, I am going to attempt to walk the walk of proving that TLA+ can be usefully employed at an early stage of system design thinking, with an <em>appropriate</em> amount of time investment for a small business, and can grow with you as your system matures.</p><p>I may fail in my quest. But hey, I work in startups, so I’m not scared of that as long as I’ve given it my best shot!</p><h4><strong>A few important links</strong></h4><p><a href="http://lamport.azurewebsites.net/video/videos.html">Leslie Lamport’s official video course</a></p><p><a href="https://lamport.azurewebsites.net/tla/hyperbook.html">Leslie Lamport’s TLA+ Hyperbook</a></p><p><a href="https://learntla.com/introduction/">Hillel Wayne’s Learn TLA+ website</a></p><p><a href="https://groups.google.com/forum/?fromgroups#!forum/tlaplus">The TLA+ Google Groups community</a></p><p><a href="https://www.amazon.co.uk/Specifying-Systems-Language-Hardware-Engineers/dp/032114306X/ref=sr_1_2">Leslie Lamport’s seminal work, Specifying Systems</a>, also available in <a href="https://lamport.azurewebsites.net/tla/book-02-08-08.pdf">PDF format here</a></p><p>I’ll introduce more links as we go along, but these are, in my opinion, the building blocks upon which you should begin your TLA+ journey. Also buy Hillel Wayne’s <a href="https://www.amazon.co.uk/Practical-TLA-Planning-Driven-Development/dp/1484238281/ref=sr_1_1">excellent book</a>.</p><p><a href="https://medium.com/koodoo/tla-for-startups-part-2-1ef288adab39"><strong><em>Go to Part 2 &gt;&gt;</em></strong></a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=8b162863824b" width="1" height="1" alt=""><hr><p><a href="https://medium.com/koodoo/tla-for-startups-part-1-8b162863824b">TLA+ for startups (part 1)</a> was originally published in <a href="https://medium.com/koodoo">Koodoo</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[CTO Secrets: How to get the best companies fighting to hire you (part 3 of 3)]]></title>
            <link>https://medium.com/koodoo/cto-secrets-get-the-best-companies-fighting-to-hire-you-part-3-of-3-29ed4a464115?source=rss----d73c858525b0---4</link>
            <guid isPermaLink="false">https://medium.com/p/29ed4a464115</guid>
            <category><![CDATA[interview]]></category>
            <category><![CDATA[tech-test]]></category>
            <category><![CDATA[hiring-tips]]></category>
            <category><![CDATA[tech-career]]></category>
            <category><![CDATA[dddem]]></category>
            <dc:creator><![CDATA[Neil O'Connor]]></dc:creator>
            <pubDate>Tue, 05 Nov 2019 12:25:16 GMT</pubDate>
            <atom:updated>2019-11-25T11:40:12.772Z</atom:updated>
            <content:encoded><![CDATA[<p><em>I recently gave a talk at the inaugural </em><a href="http://dddeastmidlands.com/"><em>DDD East Midlands</em></a><em> conference in Nottingham, UK. Here is a transcript of that talk, in three parts. </em><strong><em>UPDATE: the video of the original talk is now available </em></strong><a href="https://www.youtube.com/watch?v=FHhgTXiv-Rw"><strong><em>here</em></strong></a><strong><em>.</em></strong></p><p><a href="https://medium.com/@neil.oconnor/cto-secrets-get-the-best-companies-fighting-to-hire-you-part-1-of-3-808819940f6e"><strong>&lt;&lt; Back to part 1</strong></a></p><p><a href="https://medium.com/@neil.oconnor/cto-secrets-get-the-best-companies-fighting-to-hire-you-part-2-of-3-424965f4ed86"><strong>&lt;&lt; Back to part 2</strong></a></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*U4A2uOr9LY8tMyTRh7HXbw.png" /></figure><h3>PART 3: Getting the job</h3><h4>Before the interview</h4><p>So you’ve started hitting some of those sweet career goals, you’re making a name for yourself in the tech community as a bit of a badass, you’ve crafted a killer CV, and you’ve got yourself that plum interview. Now what?</p><p>OK, so first of all <strong>do a bit of research about the interview</strong>. Find out what the interview structure is and in particular whether there will be a technical assessment and what sort of assessment. More on that shortly.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*p8K46X_ILrfyX8DV12pVAA.png" /></figure><p>Do at least some basic research on the company. You don’t need to be able to reel off facts about profits and what their first office dog was called. But at least be able to describe in a sentence or two what they do and why you find that super interesting.</p><p>Find out who is interviewing you. Look them up and try to assess how technical they are from their online presence or previous jobs. <strong>Do not attempt to connect with them on </strong><a href="http://linkedin.com/"><strong>LinkedIn</strong></a><strong>.</strong></p><p>Have a look at <a href="http://glassdoor.com/">Glassdoor</a>. It might give you some clues about the culture, but also there are sometimes reports about what the interview experience was like.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ZajDADvwMS7fWFngb3530w.png" /></figure><p><strong>Prepare some answers to behavioural questions</strong>. These are the sorts of things where you are asked how you have handled yourself in certain situations. They’re straight out of the corporate interview playbook, and you can train yourself to answer them better. Find a list online somewhere, write down bullet points against each, and just memorise as many of the bullet points as you can. Get a friend to randomly ask you similar questions until you’re confident you’re remembering enough of the bullet points.</p><p>But the main thing to remember about these behavioural questions is not that there is a right and wrong answer. Instead, view them as an opportunity to sell some of your achievements or knowledge. If you’re asked some random question like “how do you deal with conflict”, don’t answer that in the abstract, “err I try not to raise my voice” or “I’m a black belt in krav maga”.</p><p>Instead, use it as an opportunity to say something like, “I was working in a team where we had a disagreement about using SQL Server or Mongo. I could see the pros and cons of each, but one guy was arguing loudly for Mongo, so I spent half an hour writing the pitch for SQL, and we presented our boss with both options”…. or something along those lines.</p><p>And here’s the thing: it doesn’t even matter if you’ve used a bit of poetic licence. <strong>That exact scenario may never have happened in the way you describe it</strong>. As an interviewer, I don’t care. I’ve asked a question, you’ve engaged with it, you’ve managed to bring a technical angle into it, we may get to talk about that technical subject later, and I’ve learned that you understand the importance of not bringing a knife to a fist fight. Everyone is happy.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*CqwHFuZYP4wLkecuu-bHag.png" /></figure><p>Some other prep you should do. Read your own CV carefully before you go in. Partly to remind yourself how awesome you are, and partly to remind yourself what you’ve said. I’ve lost count of the times I’ve asked someone in an interview about something they’ve claimed to be an expert in on their CV, only for them to tell me that they’ve not really used it. Those interviews didn’t last very long.</p><p>OK, listen carefully to the next three pieces of advice.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*miTKZ_OAcNCsivmmwV-BZA.png" /></figure><p>In preparation for the interview, <strong>write down the key projects</strong> that you have worked on in the last couple of years. Then write down what your contribution was that made it a success, and write down what you learned from that project.</p><p>You may think it’s pointless writing this down because it’s all in your head and you won’t forget. Well in fact, the act of writing something down accesses a different part of your brain and forces you to structure your thoughts. You are then more likely to remember it when asked about it — rather than looking like a fool, you’ll be able to crisply and eloquently describe these previous projects and what you gave to them and took from them.</p><p>Which leads me to the next thing: <strong>can you draw the architecture of the last project you worked on in 60 seconds?</strong> You would not believe the number of times I have asked someone to draw a simple visualisation — ANYTHING — of a system they were supposedly a key contributor to, and they can’t do it. With a whiteboard marker in their hand and an empty whiteboard in front of them, no matter how comfortable I try to make them feel, they turn into a blithering idiot. It might be stage fright, but what comes across is that they have never attempted to explain their work to another human being.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*0oWydZrle_IWT_ZaWHCMCA.png" /></figure><p>You might think you know in your head how your system is put together, but you will be proved wrong the first time you attempt to actually draw it in boxes and arrowed lines. So think about which project you are going to talk about the most in your interview, and practice drawing a diagram that represents it the best. And practice it again.</p><p>It might be a physical architecture diagram, or a logical system diagram, or a data flow diagram, or a sequence diagram, or a use case diagram. That’ll depend on your job and what points you want to get across. But it needs to be obvious to the interviewer that it comes very naturally to you to be able to visualise and explain a system you have worked on.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*6zVzVtLkM7YZ-ayywfl2Fw.png" /></figure><p>The third thing: you will often be asked <strong>what you would do differently if you had the chance for a do-over</strong> on a particular project. Think about this one in advance. Knowing what you know now, would you choose different tech or make different architectural choices? Would you put a greater emphasis on some non-functional aspect such as monitoring or performance testing? Why didn’t that happen first time around? Was it an oversight or were someone’s arguments to management not sharp enough?</p><p>I’m telling you to think about this not just so you can prepare a well-rehearsed answer. After all, you may not even get asked the question. But even just by asking yourself this question, you are training yourself to think about how you can learn from your mistakes or experiences. It may trigger a thought process about best practices and how to win the argument for adopting them.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*6i19aYD2X86iKjFl-BDhWQ.png" /></figure><p>So those last few things I mentioned are about demonstrating that you can see the bigger picture. You can move comfortably between the concrete and abstract details, and you can demonstrate ownership and personal accountability through being able to describe, visualise and reflect upon the projects you have contributed to. These all help me as an interviewer to feel confident in your ability to be net positive contributor if you join the team.</p><h4>During the interview</h4><p>OK, those were my tips for interview prep. Now a few words about the interview itself. I won’t dwell on this because there’s reams of stuff written on this topic, but here are a few quick pointers on what I value.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*tULj9MVBT9fXRduEey-opQ.png" /></figure><p><strong>Turn up on time. </strong>I had an interviewee arrive 10 minutes late and offer no apology or explanation. I asked him, “did you have trouble finding us?”, “oh no, it was easy”. “OK, did you have a long way to come?, “no, I just live round the corner!”. Bad impression from the off.</p><p><strong>Be polite and professional. </strong>Even if you know they have a very casual dress code, that’s not a reason to turn up in your favourite 20 year-old Napalm Death t-shirt. Little things like this matter. I once interviewed a guy who had a bag with him, and he left it open on the floor between us. I could see one condom sitting proudly at the top of his bag. Just one. Ribbed. I still wonder exactly how he thought that interview was going to pan out.</p><p><strong>Ask about the tech culture.</strong> They should be selling this to you, but if not you should ask. Ask what they do to encourage and support the team keeping on top of the latest practices and technologies, and what they do to share knowledge in the team.</p><p><strong>Don’t ask questions that sound like you’re a jobsworth.</strong> If you’re asking in the interview whether you can finish at 4pm every day, you may already be talking yourself out of it. If you have a specific requirement such as childcare commitments, it’s much better to bring this up once you have an offer but before you start, because they’ll be more psychologically committed to you as a candidate by then.</p><p><strong>Remember that they want you to succeed. </strong>In most cases, they will be willing you to do well and hoping you are the right person for the job. They’ve already taken time out of their day to speak to you and have already rejected a bunch of other CVs. They’ve seen something in you they like. Take a positive mindset into the interview.</p><p><strong>Unfortunately, there are bad interviewers. </strong>I said at the top of this talk that we all make snap judgments, and sadly that can work against you or for you. Some other bad types of interviewers are:</p><ul><li>The one that’s trying to catch you out or make you feel small. Usually this is because they have are having marital problems</li><li>The one that persists with a specific question because there’s a particular thing they seem to want to hear</li><li>The one who talks about themselves the whole time</li><li>The one who is super friendly but doesn’t ask you any probing questions you can use to bring out your best</li></ul><p>The best you can do in these cases is be polite and patient, but look for opportunities, little openings, to turn the conversation in a direction you want to take it. Have those bullet points about yourself and your projects that I talked about at the ready. It may or may not work, but this is where the prep pays off in an unexpected way.</p><p><strong>Speaking of bad interviewers, </strong>you do unfortunately still get otherwise sane people asking you in interviews what your spirit animal is, or what kitchen utensil you’d like to be reincarnated as, or asking you to estimate how many grains of sand there are in the Sahara. One guy on my team had to talk for 5 minutes about a rock that was placed on the desk in front of him.</p><p>I have to admit to having tried all these things in the past. They might tell me something about your reasoning skills or your sense of humour, but I’ve concluded they are usually pretty pointless. But play them with a straight bat and answer them as best you can, because if you laugh in their face you will probably insult them, because they obviously think it’s a really clever question.</p><h4>Ace the interview</h4><p>Right, so I’ll repeat a few points here, but for me these things are key to delivering a great interview, rather than a decidedly OK interview.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*3bisZWBSdMlbpqbDMaSIPw.png" /></figure><p><strong>I keep talking about having a point of view. </strong>Don’t be afraid to let that come out. Take the initiative in the interview and set out a narrative, a theme or common thread around which you can build your answers. You might want to make the case, for example, for automating as much as you can in the development pipeline. Lay that out as something you are passionate about early on, and keep referring back to that in your answers to subsequent questions.<strong> </strong>It is great to hear when someone has an opinion on the state of tech or the industry, and can speak passionately and informatively about it.</p><p><strong>Listen to and answer the questions put to you. </strong>In doing so, try to work out why they were asking that. What were they really trying to get out of you by asking that question?</p><p>But then <strong>use their questions as springboards </strong>to get across the points you want to make that help you sell your skills and experience. Think of it like the tennis player who uses the power of the opponent’s serve to generate a cracking return, and then adds a bit of spin on top as well.</p><p><strong>Expect the unexpected. </strong>That’s an awful cliché, but here’s what I mean. Let’s say they ask you about something on your CV that you weren’t expecting to be asked about, whether it’s a particular framework you’d forgotten about or something more leftfield. The natural response is to go on the defensive.</p><p>But again, think of these as an opportunity. Even if you give a mediocre answer, you’ve still got a free hit for you to bring up some of the attributes or skills that YOU want to talk about.</p><p>This is where it really helps if you have practised those bullet points about what you’re good at and what you’ve achieved. Because you’ll often find opportunities suddenly arising at the most unexpected time to get across some point you wanted to make, and you’ll have those little phrases and examples at the tip of your tongue just when you need them.</p><p><strong>Try to balance confidence with humility.</strong> It’s a very British thing. We like people who are capable and intelligent, but we don’t like them to show off about it. A bit of self-deprecating humour can go a long way, used judiciously. You want to get across the message that “I’ve got this. But I don’t take myself too seriously, so other people will go along with me”.</p><p>If you’re going for a <strong>senior role</strong>, I read a <a href="https://medium.com/swlh/you-need-better-senior-software-developers-4c762950fe1">great article</a> about what companies are looking for, whether they realise it or not, when they say they want a senior.</p><p><strong>Firstly</strong>, they want someone who is a skilled mentor. It’s not just about bringing mad skills; you need to be excited about and able to transfer those skills to more junior team members.</p><p><strong>Secondly,</strong> they want someone who is an accelerator. Are you someone who makes things go faster, because you’re always looking at ways to optimise and improve? Or are you going to keep things as they are, or worse slow things down? Every manager in the world thinks the dev team aren’t delivering fast enough. So they want an accelerator.</p><p><strong>Thirdly</strong>, they want someone with perspective. This often means experience, but you can gain perspective with every new thing you learn. There are always at least two sides to every story, and being able to balance off competing priorities using experience and insight is a valued skill.</p><p><strong>Be comfortable visualising technical concepts you are talking about.</strong> Don’t be afraid to ask if you can jump up and draw it on a whiteboard. If you ask them, rather than wait to be asked, if you can draw it, you will give them a warm fuzzy feeling that you have a good handle on the big picture and are a natural explainer.</p><p>Interviewers for dev positions will listen carefully to your answers about<strong> technical debt and non-functional requirements. </strong>It’s a sore subject in most teams, and usually a source of tension between product and tech. The trick is not to come down hard on one side of the argument or guess what side you think they are likely to be on, but to demonstrate (ideally with examples) that you realise it’s a balancing act. It shows maturity and good judgment.</p><h4>Nail the tech test</h4><p>The tech test is where the chickens on your CV can come home to roost.</p><p>There are various flavours of technical test, and I’ve tried them all at various stages. Right now, I do a combination of a simple whiteboard test in the first interview stage to check you have got the rudimentary thinking skills, and a more in-depth coding exercise with the team if you get through to the second stage.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*iu_v6AGx9_0RFg63MaSY7A.png" /></figure><p>I’ll go through the main types of tech test you might encounter:</p><p><strong>Standard screening</strong> test before you get an interview. I think these are generally a bad idea — it’s like they’re <em>trying</em> to put you off the company. I can’t give you any specific advice on how to approach these ones, other than that you can get better at them with practice.</p><p><strong>At-home tests</strong> after you’ve already had a positive first interview. I’ve used these before, and they can be pretty useful. What I’m generally looking for here is that you a) understood the thing I’m asking you to do, and that means it’s OK for you to come back and ask questions about the challenge; b) can write solid and elegant code; and c) understand the importance of good housekeeping.</p><p>So take a bit of care with your solution, don’t rush through it. And for that last point, be sure to comment your code appropriately, even if you aren’t a big believer in doing that; write unit tests that pass; and commit to whatever repo you are using as though you were working on a team project. Clear some time in your weekend to work on it, because if you tell me you were busy and did a quick hack, I’ll assume you’re not that bothered about the job.</p><p><strong>Locked away like a hostage in a meeting room </strong>for an hour with a challenge and a laptop. For these, before you start, ask the interviewer what success looks like; what are they are most interested in seeing from you? Are they more interested in having something working, something complete, or something well-written?</p><ul><li>Realistically, they might tell you to use your own judgment, but even asking them sends a good signal. If they do say that, tell them you’ll focus initially on having something working.</li><li>In which case, you need to be disciplined about continuously compiling and running, so spend a few minutes at the beginning making sure you are set up for that.</li><li>If they want something complete, it’s pretty much a test of your ability to hit a deadline. In this case, take a few minutes at the start to plan out your hour, and give yourself milestones to hit.</li><li>If they want something well-written, take a few moments to consider what you want to showcase. Look for clues that suggest what they want to see — maybe it’s a particular code structure or implementation pattern. If you just dive in without considering what an elegant solution might look like, you will probably just write bad code.</li></ul><p>Whatever your approach, explain at the end what approach you took and any assumptions or shortcuts you made.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*QaQxY7o_JLyxcfrvFYprYA.png" /></figure><p><strong>Coding in front of a technical interviewer</strong>. For this one, you want to appeal to their instincts as a peer. They will, or at least should, appreciate you doing things like writing unit tests, perhaps even following a TDD style, observing concepts such as single responsibility principle and patterns such as dependency inversion.</p><p>They will probably also admire your pragmatism if you say, “Oooh I bet there’s an NPM package for this, can I have a look?”. In any case, the most important thing is to talk them through what you are thinking. Explain your reasoning, and if they guide you down a different path, be sure to listen.</p><p><strong>Whiteboard coding</strong>. Don’t be deceived into thinking that you’ve dodged a bullet by not having to write working code. A good interviewer in a software company will actually ask you to solve a particularly thorny question in this format because it means you can focus on logic and reason and fundamental computer science concepts, without getting bogged down in the syntax of a particular language.</p><ul><li>Remember that — don’t get bogged down into writing working code. It’s a whiteboard, not an IDE. Write it in pseudo-code, or if you are more comfortable, write it in your favourite language but tell them you aren’t going to get hung up on semicolons</li><li>If they ask, “are you happy with your solution?”, that’s often code for them saying they think there is a mistake. If you can’t see it, I’d be impressed if you started writing some pseudo tests for your pseudo code. Because this simultaneously shows you understand the importance of validating your code AND it may actually help you tease out the logical flaw if there is one.</li><li>Also, don’t be afraid of just scrubbing it and starting again — it’s a whiteboard, that’s what they’re designed for. If you are really stuck in a rut, think about it as a TDD problem. Tell them you’re going to break it down into the smallest unit of a problem, write the simplest case that will pass, and then build on it. If you are still stuck, ask them for a clue.</li></ul><p>As you go through your tech test, remember we’re looking for people who, in the words of <a href="https://www.joelonsoftware.com/">Joel Spolsky</a>, are <strong>smart and get things done</strong>. Focus on what the problem is they are asking you to solve, listen to what they are trying to guide you towards, explain your thinking, and prioritise getting to a working solution.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*0a0Lvz5KgW3MwvBbipXLIQ.png" /></figure><p>Thanks for listening, and I hope you found some of that useful. And of course I would be stupid not to use this opportunity to tell you: <strong>I’m hiring</strong>!</p><p><em>(Opinions are those of the author, not the company. All images used are copyright of the original publishers, who are too numerous to track down given the sheer volume of memes in this talk!)</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=29ed4a464115" width="1" height="1" alt=""><hr><p><a href="https://medium.com/koodoo/cto-secrets-get-the-best-companies-fighting-to-hire-you-part-3-of-3-29ed4a464115">CTO Secrets: How to get the best companies fighting to hire you (part 3 of 3)</a> was originally published in <a href="https://medium.com/koodoo">Koodoo</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>