<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <id>https://blog.henningmu.com/</id>
    <title>Henning’s Blog</title>
    <updated>2022-05-11T12:00:00.000Z</updated>
    <generator>Henning</generator>
    <author>
        <name>Henning Muszynski</name>
        <email>mail@henningmu.com</email>
        <uri>https://henningmu.com/</uri>
    </author>
    <link rel="alternate" href="https://blog.henningmu.com/"/>
    <link rel="self" href="https://blog.henningmu.com/atom.xml"/>
    <subtitle>Remote work, async work, leadership, technology, and productivity.</subtitle>
    <icon>https://blog.henningmu.com/favicon/favicon-32x32.png</icon>
    <rights>All rights reserved 2022, Henning Muszynski</rights>
    <category term="Remote work"/>
    <category term="Async work"/>
    <category term="Leadership"/>
    <category term="Technology"/>
    <category term="Productivity"/>
    <entry>
        <title type="html"><![CDATA[Leaders Should Decrease Stress]]></title>
        <id>https://blog.henningmu.com/posts/decrease-stress</id>
        <link href="https://blog.henningmu.com/posts/decrease-stress"/>
        <updated>2022-05-11T12:00:00.000Z</updated>
        <summary type="html"><![CDATA[Strategies to reduce stressful situations for your team.]]></summary>
        <content type="html"><![CDATA[<p>As leaders, our job is to make sure our team is not burning out and can perform at a sustainable pace for a long time. When people are under a lot of pressure and stress, we need to act and correct course.</p>
<h2 id="check-ins">Check-ins</h2>
<p>I start all my 1on1s with a <em>"traffic light check-in"</em>: Both me and the team member rate our current mental state and stress level:</p>
<ul>
<li><em>green</em>: Everything is okay, no elevated stress levels, and ready to have the 1on1.</li>
<li><em>yellow</em>: A little stressed or distracted from other topics or ongoing problems.</li>
<li><em>red</em>: Not in a good head state for the usual 1on1 topics, high-stress level or urgent and important problems that need to be resolved first.</li>
</ul>
<p>Only after both parties have checked-in, we can decide to drill deeper on causes for anything that's not green or decide to let it be and focus on the other points on our agenda.</p>
<h2 id="reassurance">Reassurance</h2>
<p>If you notice that team members are stressed, and the next 1on1 is too far away, immediately reach out to them directly. First, dig deeper into the issue at hand. Listen closely (or read in async environment) to their problems, don't go immediately into problem-solving mode.</p>
<p>In case of stress sources outside the work environment (e.g. personal crises), remind them that work can wait and offer a health day.</p>
<p>If the source is part of a work project, you can slowly enter in problem-solving mode. I find it most helpful to first "ease the pain" by helping to renegotiate scopes, finding help or delegating tasks away from them. It's crucial to follow this up with a learning, though. Use the next 1on1 to drill deeper on how to avoid these stressful situations in the future. Maybe there's a communication or planning problem, maybe a training or better reviews are needed.</p>
<h2 id="leading-by-example">Leading By Example</h2>
<p>The final aspect to decrease stress levels in your team (and company) is destigmatizing it. Admit when you're stressed openly. Explain simply what you're going to do about it (taking a day, saying no, ...). Model the behavior you'd expect from your team.
Admitting to stress can be perceived as a sign of weakness. If you don't clearly take a stand that it is not, your team won't learn from it.</p>
]]></content>
        <published>2022-05-11T12:00:00.000Z</published>
    </entry>
    <entry>
        <title type="html"><![CDATA[On end-to-end testing]]></title>
        <id>https://blog.henningmu.com/posts/end-to-end-testing</id>
        <link href="https://blog.henningmu.com/posts/end-to-end-testing"/>
        <updated>2021-08-10T12:00:00.000Z</updated>
        <summary type="html"><![CDATA[Identifying core workflows, running them regularly and keeping them clean.]]></summary>
        <content type="html"><![CDATA[<p>At Doist, our team uses Cypress for end-to-end (e2e) testing core workflows of our application. This sentence already gave life to one of the most important aspects of a good end-to-end test suite: <strong>core workflows</strong>. Since e2e tests are slow to run (which equals expensive to run) and sometimes can be flaky, you shouldn't rely on them to fully test each edge-case of your app.</p>
<h2 id="core-workflows">Core Workflows</h2>
<p>In a cross-functional initiative, we've teamed up with other client teams (Android, iOS), the product team and the support team to identify the most important workflows in our products. Workflows that should never break to ensure a baseline user experience. They range from login and signup, to paid upgrades and basic app functionality like creating tasks or posting threads. Defining these workflows in a cross-functional manner has helped to take the whole picture into account and zoom-out from frontend-only concerns.</p>
<p>After having identified a set of core workflows, it's important to make sure they never break. For this, we run the test suite on every PR. No change is allowed to break a test, and the team gains maximum confidence that their changes are relatively safe to apply.</p>
<h2 id="test-hygiene">Test Hygiene</h2>
<p>It's in the nature of end-to-end tests to be flaky (with Cypress less so, but it can still happen). Sometimes they're working reliably, and occasionally, you get a test failure. It's important to be very vigilant about each flaky test. A test failure should be treated similar to breaking production. Drop what you're doing, look at it and fix it. At least that would be the ideal way. The day-to-day of engineers looks different: in most instances you'll re-run the test suite, everything passes, and you forget it ever happened (you have more important stuff to deal with anyway). This is a slippery slope to go down.</p>
<p>One of the worst things you can do is start merging changes, although the test suite failed. At that moment, you might brush it off as "it's just this flaky test, totally unrelated to my changes" – but what you're really doing is opening the door to merging PRs with failed status checks and undermining the trust in your test suite. If you're low on time and notice flaky tests hampering the shipping frequency of your team, comment the test out. It sounds radical, after all you're loosing a test and, hence, confidence in the correctness of your changes. On the other hand, how much confidence did a flaky test really provide? Log the broken test somewhere and try to fix it as soon as time allows. This way you'll never get into the habit of merging PRs with failed status checks.</p>
]]></content>
        <published>2021-08-10T12:00:00.000Z</published>
    </entry>
    <entry>
        <title type="html"><![CDATA[Deploy your Storybook]]></title>
        <id>https://blog.henningmu.com/posts/deploy-storybook</id>
        <link href="https://blog.henningmu.com/posts/deploy-storybook"/>
        <updated>2021-05-21T12:00:00.000Z</updated>
        <summary type="html"><![CDATA[Increase accountability and awareness by sharing your storybook widely.]]></summary>
        <content type="html"><![CDATA[<p>The journey to an organization-wide adopted design system is long and hard. That's why it's even more important to tackle it in a continuous manner – making small but constant progress is crucial. Rome wasn't built in a day. Heroic and large one-off efforts won't be the silver bullet for real adoption inside your organization you hope they will be.</p>
<p>We're building layout primitives and other components of our design system in <a href="https://storybook.js.org/">Storybook</a>. With that approach, we can constantly iterate on them and share them easily. Building components in isolation is a game changer for building truly reusable bits of UI, as you think about their API first and are not constrained to a single use case as during feature development. Iterating on your components is important. Be it based on feedback from your design team or feedback from developers using them or in the worst case from users discovering bugs. You likely won't be able to hit the perfect implementation on your first try.</p>
<p>An often overlooked system to increase visibility and adoption of your design system is to deploy it. Even if it's not public, it should be accessible to everyone in your organization. With Storybook, we can easily export a static version and host it in a S3 bucket. This can be adapted to whatever other host or technology you're using, this is not about the technology but the approach of sharing it widely. On every push to our main branch, we have an automated CI job that builds and deploys the newest storybook, making sure it's always up-to-date. This has the added benefit of ensuring that our Storybook never breaks through (unrelated) changes. We would at least notice the CI failure.</p>
<p>Sharing a link to your Storybook makes it dead simple to ask for design feedback during development, and also gives everybody the opportunity to discover and play with our design system components.</p>
]]></content>
        <published>2021-05-21T12:00:00.000Z</published>
    </entry>
    <entry>
        <title type="html"><![CDATA[Testing GitHub Actions]]></title>
        <id>https://blog.henningmu.com/posts/gh-actions-local</id>
        <link href="https://blog.henningmu.com/posts/gh-actions-local"/>
        <updated>2021-03-19T14:00:00.000Z</updated>
        <summary type="html"><![CDATA[How to test GitHub Actions effectively before merging them.]]></summary>
        <content type="html"><![CDATA[<p>At Doist, we're switching away from Azure Pipelines towards GitHub Actions as our only CI provider.</p>
<p>When improving any of our workflows or when switching an existing task from a Pipeline to an Action we're faced with the problem of asserting whether the CI is working as expected. We could use the "YOLO" approach: merge our changes into main and iterate on them there until they work. But that's rarely a nice or professional approach and causes too much noise and frustration for everybody involved.</p>
<p>When looking around for solutions to this problem, most people recommend using <a href="https://github.com/nektos/act">nektos/act</a>. Act can run GitHub Actions locally and allows you to test whether your workflow runs as you expect it to. Unfortunately, in our most recent use case we couldn't use act as we needed to access repository secrets which were not available locally.</p>
<h2 id="solution-1-change-trigger-to-the-pr">Solution 1: Change trigger to the PR</h2>
<p>Instead of succumbing to the YOLO workflow, we use another ingenious approach: while developing the Action we change the trigger to run on the pull request:</p>
<pre class="astro-code astro-code-themes github-light github-dark" style="background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="yml"><code><span class="line"><span style="color:#22863A;--shiki-dark:#85E89D">name</span><span style="color:#24292E;--shiki-dark:#E1E4E8">: </span><span style="color:#032F62;--shiki-dark:#9ECBFF">GitHub Action Workflow</span></span>
<span class="line"></span>
<span class="line"><span style="color:#005CC5;--shiki-dark:#79B8FF">on</span><span style="color:#24292E;--shiki-dark:#E1E4E8">: </span><span style="color:#032F62;--shiki-dark:#9ECBFF">pull_request</span></span></code></pre>
<p>Instead of running only when there's a new tag or a new push to a certain branch, we tell the Action to run on every PR. This way, we can push changes to our PR until we ensured everything works correctly. After that, we change the trigger back to the actual value, clean up the PR and ask for a final review before merging it with quiet conscience.</p>
<h2 id="solution-2-add-manual-action-trigger">Solution 2: Add manual action trigger</h2>
<p>When the code of your action works correctly (verified through solution 1) you might want to check that it behaves correctly under different circumstances and with different parameters. To do this, you can add a ˋworkflow_dispatchˋ to your triggers. Doing so will create a button in the GitHub UI which you can use to run your action manually and even supply it with various input parameters. Check the <a href="https://github.blog/changelog/2020-07-06-github-actions-manual-triggers-with-workflow_dispatch/">official announcement blog post</a></p>
<pre class="astro-code astro-code-themes github-light github-dark" style="background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="yml"><code><span class="line"><span style="color:#6A737D;--shiki-dark:#6A737D"># simple case, no inputs</span></span>
<span class="line"><span style="color:#005CC5;--shiki-dark:#79B8FF">on</span><span style="color:#24292E;--shiki-dark:#E1E4E8">: </span><span style="color:#032F62;--shiki-dark:#9ECBFF">workflow_disptach</span></span>
<span class="line"></span>
<span class="line"><span style="color:#6A737D;--shiki-dark:#6A737D"># with inputs</span></span>
<span class="line"><span style="color:#005CC5;--shiki-dark:#79B8FF">on</span><span style="color:#24292E;--shiki-dark:#E1E4E8">: </span><span style="color:#032F62;--shiki-dark:#9ECBFF">workflow_dispatch</span></span>
<span class="line"><span style="color:#22863A;--shiki-dark:#85E89D">    inputs</span><span style="color:#24292E;--shiki-dark:#E1E4E8">:</span></span>
<span class="line"><span style="color:#22863A;--shiki-dark:#85E89D">        logLevel</span><span style="color:#24292E;--shiki-dark:#E1E4E8">:</span></span>
<span class="line"><span style="color:#22863A;--shiki-dark:#85E89D">            description</span><span style="color:#24292E;--shiki-dark:#E1E4E8">: </span><span style="color:#032F62;--shiki-dark:#9ECBFF">"Log Level"</span></span>
<span class="line"><span style="color:#22863A;--shiki-dark:#85E89D">            required</span><span style="color:#24292E;--shiki-dark:#E1E4E8">: </span><span style="color:#005CC5;--shiki-dark:#79B8FF">true</span></span>
<span class="line"><span style="color:#22863A;--shiki-dark:#85E89D">            default</span><span style="color:#24292E;--shiki-dark:#E1E4E8">: </span><span style="color:#032F62;--shiki-dark:#9ECBFF">"warning"</span></span></code></pre>
]]></content>
        <published>2021-03-19T14:00:00.000Z</published>
    </entry>
    <entry>
        <title type="html"><![CDATA[Preparing work is work]]></title>
        <id>https://blog.henningmu.com/posts/preparing-work</id>
        <link href="https://blog.henningmu.com/posts/preparing-work"/>
        <updated>2021-02-02T22:00:00.000Z</updated>
        <summary type="html"><![CDATA[Protect your time off.]]></summary>
        <content type="html"><![CDATA[<p>One thing I needed to tell almost everybody on my team at one point or another is: <strong>Preparing work is work</strong>. What I mean by this is you should treat all the preparatory work, the daily reviews, the weekly planning and all other rituals you might have as work.</p>
<p>We ask people to work 40 hours per week – and that's plenty. I firmly believe people should completely disconnect over the weekend whenever possible. Properly resting and recharging will do more for your productivity and concentration than constantly being online, checking emails and messages on Saturdays and Sundays.</p>
<p>A lot of productivity articles have been written on the topics of weekly reviews and planning rituals – and doing them on Sundays. While I'm a firm believer in such rituals, I don't think you should sacrifice your Sunday morning or afternoon for them. The temptation to quickly check your emails, send that quick response or take a brief look at the newest pull requests is too big – and can easily become a huge time sink that keeps you busy for multiple hours.</p>
<p>The solution to this seems obvious in hindsight: do your rituals on Friday before leaving for the weekend, or on Mondays before starting your day. Doing these routines is important for your personal productivity, and hence, they should be important for your company. There should be no excuse necessary to do them in your regular 40 work hours. <em>Preparing your work is work.</em></p>
]]></content>
        <published>2021-02-02T22:00:00.000Z</published>
    </entry>
    <entry>
        <title type="html"><![CDATA[Writing modern CLI tools]]></title>
        <id>https://blog.henningmu.com/posts/how-to-cli</id>
        <link href="https://blog.henningmu.com/posts/how-to-cli"/>
        <updated>2021-02-02T21:00:00.000Z</updated>
        <summary type="html"><![CDATA[How to write small interactive scripts with a modern stack.]]></summary>
        <content type="html"><![CDATA[<p>I'm a huge fan of automation – where it makes sense. Normally, I'd either use our CI (GitHub Actions) for everything code related and small node scripts for everything else. Since we're betting on TypeScript, I spent some time upgrading my tech stack for these small scripts.</p>
<p>With <a href="https://github.com/TypeStrong/ts-node"><code>ts-node</code></a> we can run node scripts in TypeScript.</p>
<p><a href="https://github.com/tj/commander.js/"><code>commander.js</code></a> enables us to write interactive scripts with ease. Adding options, short hands and documentation for scripts becomes a breeze.</p>
<p>The final thing added to our tool chain is <a href="https://github.com/SBoudrias/Inquirer.js/"><code>inquirer.js</code></a> which allows us to ask for user inputs and confirmation in scripts.</p>
<h2 id="tutorial">Tutorial</h2>
<p>To use this tech stack in your next mini-project. Initialize your new project with <code>npm init</code> and then run</p>
<pre class="astro-code astro-code-themes github-light github-dark" style="background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="sh"><code><span class="line"><span style="color:#6F42C1;--shiki-dark:#B392F0">npm</span><span style="color:#032F62;--shiki-dark:#9ECBFF"> install</span><span style="color:#005CC5;--shiki-dark:#79B8FF"> --save</span><span style="color:#032F62;--shiki-dark:#9ECBFF"> typescript</span><span style="color:#032F62;--shiki-dark:#9ECBFF"> ts-node</span><span style="color:#032F62;--shiki-dark:#9ECBFF"> commander</span><span style="color:#032F62;--shiki-dark:#9ECBFF"> inquirer</span></span></code></pre>
<p>to install all required dependencies. To use modern syntax that you're used to from Frontend development (i.e. ES modules) add the following to your <code>tsconfig.json</code>:</p>
<pre class="astro-code astro-code-themes github-light github-dark" style="background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="json"><code><span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">{</span></span>
<span class="line"><span style="color:#005CC5;--shiki-dark:#79B8FF">    "compilerOptions"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">: {</span></span>
<span class="line"><span style="color:#005CC5;--shiki-dark:#79B8FF">        "esModuleInterop"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">: </span><span style="color:#005CC5;--shiki-dark:#79B8FF">true</span><span style="color:#24292E;--shiki-dark:#E1E4E8">,</span></span>
<span class="line"><span style="color:#005CC5;--shiki-dark:#79B8FF">        "resolveJsonModule"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">: </span><span style="color:#005CC5;--shiki-dark:#79B8FF">true</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">    },</span></span>
<span class="line"><span style="color:#005CC5;--shiki-dark:#79B8FF">    "include"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">: [</span><span style="color:#032F62;--shiki-dark:#9ECBFF">"your-script"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">],</span></span>
<span class="line"><span style="color:#005CC5;--shiki-dark:#79B8FF">    "exclude"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">: [</span><span style="color:#032F62;--shiki-dark:#9ECBFF">"node_modules"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">]</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">}</span></span></code></pre>
]]></content>
        <published>2021-02-02T21:00:00.000Z</published>
    </entry>
    <entry>
        <title type="html"><![CDATA[Content over Tech]]></title>
        <id>https://blog.henningmu.com/posts/content-over-tech</id>
        <link href="https://blog.henningmu.com/posts/content-over-tech"/>
        <updated>2021-01-13T23:00:00.000Z</updated>
        <summary type="html"><![CDATA[A blog should be about its content not its tech stack.]]></summary>
        <content type="html"><![CDATA[<p>This post serves mostly as a reminder for myself. When starting to blog, it should be mostly about creating content for your potential readers. It shouldn't be about configuring or building the best tech stack.</p>
<p>Especially, as a developer, it's easy to lose yourself in all details – and it's so much fun to do so. It might start with a harmless dark &amp; light mode toggle, and while you're at it, you start writing your own CMS or component library. Been there, done that.</p>
<p>Try to remember every time you're tempted to tweak your setup that it is the content that should shine. Most people won't care about your setup, they care about your content.</p>
<p>To keep myself in check, I collect all the ideas for improvements for this blog in a dedicated <a href="https://todoist.com">Todoist</a> project. This way, nothing is lost, and I won't get distracted from my original goal. From time to time, I'll allow myself to indulge in these optimizations and cross off tasks on my to-do list.</p>
]]></content>
        <published>2021-01-13T23:00:00.000Z</published>
    </entry>
    <entry>
        <title type="html"><![CDATA[Tech Stack of this Blog]]></title>
        <id>https://blog.henningmu.com/posts/blog-tech</id>
        <link href="https://blog.henningmu.com/posts/blog-tech"/>
        <updated>2021-01-13T22:00:00.000Z</updated>
        <summary type="html"><![CDATA[A look under the hood: what's powering this blog.]]></summary>
        <content type="html"><![CDATA[<p>A small overview of the tech stack that's powering this blog. In its first iteration, I focussed on getting something out of the door quickly. Don't expect the most complex setup with a lot of bells and whistles, but rather a down to earth one that focuses on me actually blogging.</p>
<h2 id="tech-stack">Tech Stack</h2>
<p>This blog uses <a href="https://nextjs.org/">Next.js</a> to produce a static HTML export using <code>next export</code>.</p>
<p>The posts are written using Markdown. Metadata of each post is managed with <a href="https://github.com/jonschlinkert/gray-matter">gray-matter</a>, which is a YAML block at the top of each file containing things like the title, excerpt and published date.</p>
<p>For coherent styling, this blog uses <a href="https://tailwindcss.com/">Tailwind CSS</a>. The code is authored using TypeScript.</p>
<p>On every push, the blog is deployed using Netlify's GitHub integration.</p>
<h2 id="official-template">Official Template</h2>
<p>If you want to kick-start your own blog, I can recommend starting with the official <a href="https://github.com/vercel/next.js/tree/canary/examples/blog-starter-typescript">Next.js Blog Starter with TypeScript</a>. It will get you going fast and doesn't come with a lot of complexities.</p>
]]></content>
        <published>2021-01-13T22:00:00.000Z</published>
    </entry>
    <entry>
        <title type="html"><![CDATA[Hello World!]]></title>
        <id>https://blog.henningmu.com/posts/hello-world</id>
        <link href="https://blog.henningmu.com/posts/hello-world"/>
        <updated>2021-01-13T21:00:00.000Z</updated>
        <summary type="html"><![CDATA[What to expect on this blog. What it's about and what not.]]></summary>
        <content type="html"><![CDATA[<pre class="astro-code astro-code-themes github-light github-dark" style="background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="js"><code><span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">console.</span><span style="color:#6F42C1;--shiki-dark:#B392F0">log</span><span style="color:#24292E;--shiki-dark:#E1E4E8">(</span><span style="color:#032F62;--shiki-dark:#9ECBFF">'Hello World!'</span><span style="color:#24292E;--shiki-dark:#E1E4E8">)</span></span></code></pre>
<p>Welcome to Henning's Blog. I'm Henning, Head of Frontend at Doist and working from Hamburg, Germany. I'm going to use this space to write about a couple of different things:</p>
<h2 id="working-remote-and-async">Working remote and async</h2>
<p>Since 2017 I'm working remotely for Doist. Doist is a fully remote-first and async-first company. Since starting here, I'm bullish on working from home and can't imagine ever trading my freedom and productivity for long commutes and open-plan offices. I'll share helpful tips and tricks on how I and we at Doist make remote work, work.</p>
<h2 id="leading-a-remote-team">Leading a remote team</h2>
<p>A couple of years ago, I switched from being an individual contributor and became a manager. While I never stopped contributing (and don't think I ever will) I've a couple of learnings to share on remote leadership. Especially, leading multidisciplinary teams and handling time zone differences. My team is currently 13 people strong and spreads from the west coast of America to Hong Kong / Perth – pretty much as remote as they get.</p>
<h2 id="all-things-frontend-and-developer-productivity">All things Frontend and developer productivity</h2>
<p>Although my role is management, I still try to spend a third of my time getting my hands dirty on actual Frontend work. I'm going to share different learnings on how to be a multiplier of your team's productivity. Occasionally, I'll share interesting challenges from the front*(end)* that we've faced and solved.</p>
]]></content>
        <published>2021-01-13T21:00:00.000Z</published>
    </entry>
</feed>