<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>pierreprinetti.com</title><link>https://pierreprinetti.com/</link><description>Recent content on pierreprinetti.com</description><generator>Hugo -- 0.147.9</generator><language>en</language><lastBuildDate>Tue, 05 Mar 2024 11:07:19 +0100</lastBuildDate><atom:link href="https://pierreprinetti.com/index.xml" rel="self" type="application/rss+xml"/><item><title>How to hire a software engineer: a panellist's guide to the technical interview</title><link>https://pierreprinetti.com/blog/2024-technical-interview/</link><pubDate>Tue, 05 Mar 2024 11:07:19 +0100</pubDate><guid>https://pierreprinetti.com/blog/2024-technical-interview/</guid><description>&lt;p>Many candidates struggle to express their full potential during a technical interview. As the interviewer, your job is to let them shine. You will certainly look out for red flags, and your attention will naturally be drawn to their technical weak spots. But you&amp;rsquo;ll have to be intentional if you don&amp;rsquo;t want to overlook talent.&lt;/p>
&lt;p>Your job in a technical interview: &lt;strong>prove that this very candidate is the best fit for the role&lt;/strong>. Of course they might not be, but the idea behind this approach is that if they are, you minimise the risk of not finding out. And if they are not, you will have given them a fair chance.&lt;/p></description></item><item><title>Hack: Rotate OpenShift clouds.yaml application credentials</title><link>https://pierreprinetti.com/blog/2023-hack-rotate-openshift-credentials/</link><pubDate>Thu, 16 Mar 2023 00:00:00 +0000</pubDate><guid>https://pierreprinetti.com/blog/2023-hack-rotate-openshift-credentials/</guid><description>&lt;p>Cloud credentials in OpenShift-on-OpenStack are stored in a secret in the &lt;code>kube-system&lt;/code> namespace.&lt;/p>
&lt;p>Rotating credentials entails:&lt;/p>
&lt;ol>
&lt;li>Create the new credentials in OpenStack&lt;/li>
&lt;li>Build a &lt;code>clouds.yaml&lt;/code> with the new credentials&lt;/li>
&lt;li>Upload the new &lt;code>clouds.yaml&lt;/code> to the Kubernetes secret&lt;/li>
&lt;li>Let the operators distribute the new secret.&lt;/li>
&lt;/ol>
&lt;p>When using application credentials, this translates to:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># Step 0: Get the current credentials for the cluster. Useful later to replace values&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># Step 1: Create the new credentials in OpenStack&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>openstack application credentials create new-creds-1
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># Step 2: Build a `clouds.yaml` with the new credentials.&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># Get the current credentials from OCP, and replace with the new values from Step 2.&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># Save as `c.yaml` for example.&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>oc -n kube-system get secret openstack-credentials -o jsonpath&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#39;{.data.clouds\.yaml}&amp;#39;&lt;/span> | base64 -d
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># Step 3: Upload the new `clouds.yaml` to the `openstack-credentials` secret&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>oc set data -n kube-system secret/openstack-credentials clouds.yaml&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;&lt;/span>&lt;span style="color:#66d9ef">$(&lt;/span>&amp;lt;&lt;span style="color:#e6db74">&amp;#34;c.yaml&amp;#34;&lt;/span>&lt;span style="color:#66d9ef">)&lt;/span>&lt;span style="color:#e6db74">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># Step 4: Enjoy.&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="automate-cloudsyaml-generation">Automate &lt;code>clouds.yaml&lt;/code> generation&lt;/h2>
&lt;p>First, build a script that creates new application credentials and directly outputs a &lt;code>clouds.yaml&lt;/code> based on a template. We asssume that the cloud in question is &lt;code>openstack&lt;/code>, which is what you&amp;rsquo;ll find in the OpenShift secret.&lt;/p></description></item><item><title>Bash notes</title><link>https://pierreprinetti.com/blog/2022-bash-notes/</link><pubDate>Wed, 03 Aug 2022 00:00:00 +0000</pubDate><guid>https://pierreprinetti.com/blog/2022-bash-notes/</guid><description>&lt;p>My personal &lt;a href="https://www.gnu.org/software/bash/">Bash&lt;/a> styleguide.&lt;/p>
&lt;h2 id="headers">Headers&lt;/h2>
&lt;p>The &lt;a href="https://en.wikipedia.org/wiki/Shebang_(Unix)">shebang&lt;/a> tells our operating system what interpreter to use to execute the script.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#!/usr/bin/env bash
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>These options make the execution of our script more predictable:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>set -o errtrace
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>set -o errexit
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>set -o nounset
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>set -o pipefail
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># or more concisely:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>set -Eeuo pipefail
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>When a command in a script fails, the failure is ignored by default. With &lt;code>-E&lt;/code> and &lt;code>-e&lt;/code>, errors stop the execution of the script.&lt;/p></description></item><item><title>Run in docker-compose, wait for the database</title><link>https://pierreprinetti.com/blog/2019-run-in-docker-compose-wait-for-the-database/</link><pubDate>Tue, 25 Jun 2019 00:00:00 +0000</pubDate><guid>https://pierreprinetti.com/blog/2019-run-in-docker-compose-wait-for-the-database/</guid><description>&lt;p>Do you use &lt;strong>docker-compose&lt;/strong> to run your local development environment? Do you write your commands into a &lt;strong>Makefile&lt;/strong> to protect your brain and your fingers from complex startup scripts?&lt;/p>
&lt;p>If so, then you know how painful it is to tell your service to wait for the database before starting.&lt;/p>
&lt;p>In a sane &lt;strong>production&lt;/strong> environment, a service should always boot and patiently wait for the dependencies to become available, and signal their state through something like a &lt;a href="https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/#define-readiness-probes">readiness probe&lt;/a>.&lt;/p></description></item><item><title>A short introduction to AWS IAM, including Roles</title><link>https://pierreprinetti.com/blog/2019-aws-iam-introduction/</link><pubDate>Sat, 22 Jun 2019 00:00:00 +0000</pubDate><guid>https://pierreprinetti.com/blog/2019-aws-iam-introduction/</guid><description>&lt;p>IAM stands for &lt;strong>Identity and Access Management&lt;/strong>. It is the service that lets you manage authentication and authorization within your AWS account.&lt;/p>
&lt;p>Authentication and Authorisation in AWS are based on six building blocks&lt;sup id="fnref:1">&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref">1&lt;/a>&lt;/sup>: &lt;strong>Account&lt;/strong>, &lt;strong>User&lt;/strong>, &lt;strong>Group&lt;/strong>, &lt;strong>Policy&lt;/strong>, &lt;strong>Action&lt;/strong> and &lt;strong>Role&lt;/strong>.&lt;/p>
&lt;p>Everything I write here, and much more, can be found in the AWS documentation. This post is nothing more than a quick introduction to get you started with the basics.&lt;/p></description></item><item><title>My first Rust project</title><link>https://pierreprinetti.com/blog/2019-learning-rust-1/</link><pubDate>Sat, 01 Jun 2019 00:00:00 +0000</pubDate><guid>https://pierreprinetti.com/blog/2019-learning-rust-1/</guid><description>&lt;p>At work, I keep a todo list vaguely resembling a &lt;a href="https://bulletjournal.com/pages/learn">bullet-journal&lt;/a>.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-plaintext" data-lang="plaintext">&lt;span style="display:flex;">&lt;span>+--------------+
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>| * Task |
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>| x Completed |
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>| &amp;gt; Migrated |
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>| - Cancelled |
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>+--------------+
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>## 2019-05-27
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>x Version-pin deploy tooling
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>x Build auth package
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>* Replace Marco&amp;#39;s deploy keys in the CI
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>## 2019-05-28
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>x Replace Marco&amp;#39;s deploy keys in the CI
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>* Write new ticket: failed logins on STG
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>* Write new ticket: Create users for Kubectl
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>* Investigate bug #123
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>## 2019-05-29
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>x Write new ticket: Create users for Kubectl
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&amp;gt; Write new ticket: failed logins on STG
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Every working day, I open the file with &lt;a href="https://neovim.io/" title="Neovim: hyperextensible Vim-based text editor">my favourite editor&lt;/a>, I add the date, and I report the unfinished items that I intend to work on.&lt;/p></description></item><item><title>Learning C++, day three: Integer overflow</title><link>https://pierreprinetti.com/blog/2019-learning-cpp-3/</link><pubDate>Tue, 07 May 2019 00:00:00 +0000</pubDate><guid>https://pierreprinetti.com/blog/2019-learning-cpp-3/</guid><description>&lt;p>I was happily playing with my shiny new prime-number-checker, trying out how loops work in C++.&lt;/p>
&lt;p>When I started entering stupidly big numbers, something strange happened.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-plaintext" data-lang="plaintext">&lt;span style="display:flex;">&lt;span>./main
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Enter a number: 5784320578432578493207508493
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Congratulations, it&amp;#39;s prime!
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Except, that is not actually a prime number. I can&amp;rsquo;t have typed a prime number by randomly banging on the keypad. What&amp;rsquo;s going on?&lt;/p>
&lt;p>I didn&amp;rsquo;t code any input sanitization in my prime-number-checker, so let&amp;rsquo;s check what my program actually gets.
I am now removing all the boring logic, and compiling this simple code:&lt;/p></description></item><item><title>Learning C++, day two</title><link>https://pierreprinetti.com/blog/2019-learning-cpp-2/</link><pubDate>Sun, 05 May 2019 00:00:00 +0000</pubDate><guid>https://pierreprinetti.com/blog/2019-learning-cpp-2/</guid><description>&lt;h2 id="my-first-steps">My first steps:&lt;/h2>
&lt;ol>
&lt;li>I have enrolled for a Pluralsight course&lt;/li>
&lt;li>I have installed a C++ syntax &lt;a href="https://github.com/bfrg/vim-cpp-modern" title="vim-cpp-modern: Extended Vim syntax highlighting for C and C++">extension&lt;/a> on my beloved &lt;a href="https://neovim.io" title="Neovim: hyperextensible Vim-based text editor">editor&lt;/a>.&lt;/li>
&lt;/ol>
&lt;h2 id="discovery-1-classes-feel-like-language-extensions">Discovery #1: Classes feel like language extensions&lt;/h2>
&lt;p>&lt;strong>In Go&lt;/strong>, primitive types are special. Some properties only apply to them; for example, there is no way of defining a behaviour for &lt;code>make(myType)&lt;/code>. Every primitive type brings its own built-in constructor, and custom types inherit the constructor from the primitive type they&amp;rsquo;re based on. If you want a new instance of your type to be any different than &amp;ldquo;the zero value for the underlying type&amp;rdquo;, then you have to declare a very explicit &lt;code>New&lt;/code> function and write a compelling comment advocating its use.&lt;/p></description></item><item><title>Learning C++, day one</title><link>https://pierreprinetti.com/blog/2019-learning-cpp-1/</link><pubDate>Sat, 04 May 2019 00:00:00 +0000</pubDate><guid>https://pierreprinetti.com/blog/2019-learning-cpp-1/</guid><description>&lt;p>A long time ago, &lt;strong>I started programming with Python&lt;/strong>. Everything was great and I was happy.&lt;/p>
&lt;p>Then &lt;strong>I discovered Go&lt;/strong>. Everything was fast and portable and powerful.&lt;/p>
&lt;p>This is my first day into &lt;strong>learning C++&lt;/strong>.&lt;/p>
&lt;h2 id="why-a-sql-metaphor">Why? A SQL metaphor&lt;/h2>
&lt;p>I used to be contributor to an opensource Go database adaptor: something like an object-relational mapper. Back then, I was fascinated by the idea of abstracting away SQL from my applications.&lt;/p></description></item><item><title>Credential Management API for passwords</title><link>https://pierreprinetti.com/blog/2019-credential-management-api-for-passwords/</link><pubDate>Thu, 10 Jan 2019 00:00:00 +0000</pubDate><guid>https://pierreprinetti.com/blog/2019-credential-management-api-for-passwords/</guid><description>&lt;p>Browsers let us save passwords and to retrieve them. This way, we can use strings too long and complex to be remembered. Some browsers, with or without the support of external password managers, generate new passwords for us and manage them seamlessly.&lt;/p>
&lt;p>However most of the time, everything regarding passwords is still based on the ability of the browser of &lt;strong>guessing which input field contains a username, and which one contains a password&lt;/strong>.&lt;/p></description></item><item><title>The Go 1.11 web service Dockerfile</title><link>https://pierreprinetti.com/blog/2018-the-go-1.11-web-service-dockerfile/</link><pubDate>Mon, 05 Nov 2018 00:00:00 +0000</pubDate><guid>https://pierreprinetti.com/blog/2018-the-go-1.11-web-service-dockerfile/</guid><description>&lt;h2 id="build-with-modules-ship-from-scratch">Build with Modules, Ship from Scratch&lt;/h2>
&lt;p>If you use dep, check out &lt;a href="https://pierreprinetti.com/blog/2018-the-go-dockerfile" title="The Go Dockerfile">this post&lt;/a> instead.&lt;/p>
&lt;h3 id="goals">Goals:&lt;/h3>
&lt;ul>
&lt;li>The application executable is compiled inside a container, in order to boost &lt;strong>reproducibility&lt;/strong>&lt;/li>
&lt;li>The resulting image must be as &lt;strong>small&lt;/strong> as possible&lt;/li>
&lt;li>The application must run in a container as &lt;strong>secure&lt;/strong> as possible: an unprivileged user in a minimal environment&lt;/li>
&lt;li>The application must be able to make &lt;strong>HTTPS&lt;/strong> calls&lt;/li>
&lt;/ul>
&lt;p>It is a multistage Dockerfile: the first throwaway stage is used for building, while the final image will only contain the compiled binary executable.&lt;/p></description></item><item><title>Test-Driven Development in Go</title><link>https://pierreprinetti.com/blog/2018-test-driven-development-in-go/</link><pubDate>Mon, 09 Jul 2018 00:00:00 +0000</pubDate><guid>https://pierreprinetti.com/blog/2018-test-driven-development-in-go/</guid><description>&lt;p>In &lt;a href="https://www.youtube.com/watch?v=qkblc5WRn-U" title="The Three Laws of TDD by Robert Martin on Youtube">this video&lt;/a>, Robert Martin uses Kotlin and JUnit to illustrate his Three Laws of TDD. But what about Go? Follow me and challenge the master! We will walk in his footsteps with the only help of &lt;a href="https://pierreprinetti.com/blog/2018-a-pattern-for-go-tests/" title="Blog: A pattern for Go tests">Brad Fitzpatrick’s checkFunc pattern&lt;/a>.&lt;/p>
&lt;h2 id="the-three-laws">The Three Laws&lt;/h2>
&lt;ol>
&lt;li>You are not allowed to write any production code unless it is to make a failing unit test pass.&lt;/li>
&lt;li>You are not allowed to write any more of a unit test than is sufficient to fail; and compilation failures are failures.&lt;/li>
&lt;li>You are not allowed to write any more production code than is sufficient to pass the one failing unit test.&lt;/li>
&lt;/ol>
&lt;h2 id="prime-factors">Prime factors&lt;/h2>
&lt;h3 id="step-1-the-api">Step 1: the API&lt;/h3>
&lt;p>We want a function to list the prime factors of a given number.&lt;/p></description></item><item><title>The Go Dockerfile</title><link>https://pierreprinetti.com/blog/2018-the-go-dockerfile/</link><pubDate>Wed, 14 Feb 2018 00:00:00 +0000</pubDate><guid>https://pierreprinetti.com/blog/2018-the-go-dockerfile/</guid><description>&lt;h2 id="build-with-dep-ship-from-scratch">Build With Dep, Ship From Scratch&lt;/h2>
&lt;p>For Go 1.11 modules, check &lt;a href="https://pierreprinetti.com/blog/2018-the-go-1.11-web-service-dockerfile" title="The Go 1.11 web service Dockerfile">this post&lt;/a> instead.&lt;/p>
&lt;p>In a devops environment, pushing some code to the repository is not enough. You have to ship it. And the first step is often writing a Dockerfile.&lt;/p>
&lt;h3 id="the-goals">The goals:&lt;/h3>
&lt;ul>
&lt;li>The code has to be &lt;strong>compiled in a container&lt;/strong>, to boost the chances my build will be reproducible.&lt;/li>
&lt;li>&lt;strong>Use &lt;a href="https://github.com/golang/dep" title="golang/dep on Github">dep&lt;/a> for fetching the dependencies&lt;/strong> in case the &lt;code>vendor&lt;/code> folder is not committed alongside with the code. NOTE: if &lt;code>vendor/&lt;/code> is in the .gitignore, it should be in the .dockerignore too.&lt;/li>
&lt;li>The final image should be as small as possible. Go applications compile to a single binary. We can have images as small as our compiled binary by leveraging &lt;a href="https://hub.docker.com/_/scratch/" title="scratch image on Docker Hub">the special &lt;code>FROM scratch&lt;/code> base image&lt;/a> in a multi-stage build.&lt;/li>
&lt;/ul>
&lt;p>Here is my base Dockerfile for Go services:&lt;/p></description></item><item><title>Event Sourcing in Go: the Event Handler</title><link>https://pierreprinetti.com/blog/2018-event-sourcing-in-go-the-event-handler/</link><pubDate>Sat, 03 Feb 2018 00:00:00 +0000</pubDate><guid>https://pierreprinetti.com/blog/2018-event-sourcing-in-go-the-event-handler/</guid><description>&lt;p>Recently, I have been working on an event-sourced application built around Command-Query Responsibility Segregation (CQRS). My job was to figure out how to implement a new command in Go.&lt;/p>
&lt;p>In order to act on a given object, we have to &lt;strong>build the current state&lt;/strong> of that object out of the events that created and modified it. Here I want to show how I have come up with the &lt;code>applier&lt;/code> interface to represent the Event logic.&lt;/p></description></item><item><title>A pattern for Go tests</title><link>https://pierreprinetti.com/blog/2018-a-pattern-for-go-tests/</link><pubDate>Sun, 28 Jan 2018 00:00:00 +0000</pubDate><guid>https://pierreprinetti.com/blog/2018-a-pattern-for-go-tests/</guid><description>&lt;p>I used to spend an unreasonable amount of time thinking about how to begin writing a test.&lt;/p>
&lt;h3 id="i-googled-test-patterns-in-go">I googled test patterns in Go.&lt;/h3>
&lt;p>Many people seem to rely on external dependencies for assertions. And in fact, I understand that generic (aha!) functions like &lt;code>isNil(v interface{}) bool&lt;/code> can initially bring speed to the development. But in the long run, I think that embracing the true strongly-typed nature of Go, instead of just searching for a way around it, is more rewarding. Writing more idiomatic code will be beneficial both for the quality of the code, and for the insights you can get by looking the Beast in the eye.&lt;/p></description></item></channel></rss>