<?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>webcodr</title>
    <link>https://webcodr.io/topics/developer-tools/</link>
    <description>Recent content on webcodr</description>
    <generator>Hugo</generator>
    <language>en-us</language>
    <lastBuildDate>Fri, 24 Jul 2026 20:28:38 +0000</lastBuildDate>
    <atom:link href="https://webcodr.io/topics/developer-tools/index.xml" rel="self" type="application/rss+xml" />
    
    <item>
      <title>jwtd - your fully local CLI JWT decoder</title>
      <link>https://webcodr.io/2026/07/jwtd-your-fully-local-cli-jwt-decoder/</link>
      <pubDate>Fri, 24 Jul 2026 20:28:38 +0000</pubDate>
      <guid>https://webcodr.io/2026/07/jwtd-your-fully-local-cli-jwt-decoder/</guid>
      <description>A few months ago I looked for a local JWT decoder and didn’t like what I found, so I decided to write a small CLI-based decoder that works fully offline. No token will ever leave the machine it’s running on.
Nothing big, just a tiny program written in Go to decode a JWT with go-jose and print the JSON contents to the console. I wanted a short name. JWT decode or jwtd. No fancy name, just a useful tool.
</description>
      <content:encoded><![CDATA[<p>A few months ago I looked for a local JWT decoder and didn&rsquo;t like what I found, so I decided to write a small CLI-based decoder that works fully offline. No token will ever leave the machine it&rsquo;s running on.</p>
<p>Nothing big, just a tiny program written in Go to decode a JWT with go-jose and print the JSON contents to the console. I wanted a short name. JWT decode or <code>jwtd</code>. No fancy name, just a useful tool.</p>
<p>A friend asked if it could verify signatures or decrypt JWE contents. Nope, but that was a perfect opportunity to try Opus 4.6 which was pretty new at the time.</p>
<p>Many iterations and tokens later, the <code>jwtd</code> can do much more. Yes, it&rsquo;s mostly written by AI agents, but it&rsquo;s still small enough to understand what&rsquo;s going on and there&rsquo;s a pretty large test suite to ensure quality. I use multiple models and regularly check if something can be improved, make security audits etc. &ndash; I will not ship a program I can&rsquo;t understand or I feel insecure about.</p>
<h2 id="what"><a href="#what" class="heading-anchor">What?</a></h2>
<p>The main focus is still decoding JWTs and showing the contents. Of course with colored output and human-readable timestamps (an expiration warning for <code>exp</code> fields is coming soon). We support a wide variety of JWS signatures, JWE key types and JWE content encryption algorithms.</p>
<p>There&rsquo;s an interactive mode for tokens and keys, so you don&rsquo;t have to clean up your history afterwards. You can also pipe a token into <code>jwtd</code> if you like. We&rsquo;re also accepting keys via environment variable and even support raw HMAC secrets.</p>
<h2 id="where"><a href="#where" class="heading-anchor">Where?</a></h2>
<p>All major operating systems are supported, but to be honest, my main focus is macOS and Linux. You can get <code>jwtd</code> via Homebrew, the AUR, Fedora COPR, Nix and Scoop. WinGET is coming soon. There are also pre-built deb and rpm packages available on GitHub.</p>
<h2 id="how"><a href="#how" class="heading-anchor">How?</a></h2>
<p>To decode a token just supply it as argument:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">$ jwtd eyJhbGciOiJSUzI1NiIs...
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Header:
</span></span><span class="line"><span class="cl"><span class="o">{</span>
</span></span><span class="line"><span class="cl">  <span class="s2">&#34;alg&#34;</span>: <span class="s2">&#34;RS256&#34;</span>,
</span></span><span class="line"><span class="cl">  <span class="s2">&#34;typ&#34;</span>: <span class="s2">&#34;JWT&#34;</span>
</span></span><span class="line"><span class="cl"><span class="o">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Payload:
</span></span><span class="line"><span class="cl"><span class="o">{</span>
</span></span><span class="line"><span class="cl">  <span class="s2">&#34;sub&#34;</span>: <span class="s2">&#34;user_2048&#34;</span>,
</span></span><span class="line"><span class="cl">  <span class="s2">&#34;admin&#34;</span>: true,
</span></span><span class="line"><span class="cl">  <span class="s2">&#34;iat&#34;</span>: <span class="s2">&#34;2026-07-22T03:00:00Z (1784689200)&#34;</span>,
</span></span><span class="line"><span class="cl">  <span class="s2">&#34;exp&#34;</span>: <span class="s2">&#34;2026-07-22T04:00:00Z (1784692800)&#34;</span>,
</span></span><span class="line"><span class="cl">  <span class="s2">&#34;note&#34;</span>: null
</span></span><span class="line"><span class="cl"><span class="o">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Signature: eyJfX2p3dGRfXyI...
</span></span></code></pre></div><p>Need to verify a JWS signature?</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">jwtd --key /path/to/public-key.pem eyJhbGciOiJSUzI1NiIs...
</span></span></code></pre></div><p>For decryption just use the private key instead of the public key.</p>
<p>Don&rsquo;t want to pass the key path as parameter? No problem, just use the environment variable <code>JWTD_KEY</code>.</p>
<p>To use the interactive mode just omit the token or the value of the key parameter.</p>
<p>That&rsquo;s just a small overview, you can find a full usage guide, every installation option and more on the official website <a href="https://jwtd.sh/">jwtd.sh</a> or on <a href="https://github.com/webcodr/jwtd">GitHub</a>.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Find things even faster with srchr</title>
      <link>https://webcodr.io/2026/07/find-things-even-faster-with-srchr/</link>
      <pubDate>Sun, 05 Jul 2026 20:28:50 +0000</pubDate>
      <guid>https://webcodr.io/2026/07/find-things-even-faster-with-srchr/</guid>
      <description>Inspired by my last post about rgp and fdp I got the idea to combine both into a more powerful and easier tool called srchr.
It’s a TUI written in Rust and uses similar or the same libraries as rg, fd, fzf and bat, but in one package. There are no external dependencies and it comes for macOS, Linux and Windows in aarch64 and x86-64.
Currently srchr is not available via package managers, but there’s an installation script:
</description>
      <content:encoded><![CDATA[<p>Inspired by my last post about <code>rgp</code> and <code>fdp</code> I got the idea to combine both into a more powerful and easier tool called <code>srchr</code>.</p>
<p>It&rsquo;s a TUI written in Rust and uses similar or the same libraries as <code>rg</code>, <code>fd</code>, <code>fzf</code> and <code>bat</code>, but in one package. There are no external dependencies and it comes for macOS, Linux and Windows in aarch64 and x86-64.</p>
<p>Currently <code>srchr</code> is not available via package managers, but there&rsquo;s an installation script:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">curl -fsSL https://raw.githubusercontent.com/webcodr/srchr/main/install.sh <span class="p">|</span> sh
</span></span></code></pre></div><p>I will also publish <code>srchr</code> on Homebrew, the AUR and perhaps some other package managers.</p>
<p>Beware, it&rsquo;s still under development and the UI is functional, but not finished yet. At the moment there is just a hardcoded Tokyo Night inspired color theme, but this will also change in the near future.</p>
<p><a href="https://github.com/webcodr/srchr">srchr on GitHub</a></p>
<h3 id="update"><a href="#update" class="heading-anchor">Update</a></h3>
<p>It&rsquo;s now available on Homebrew for macOS and Linux!</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">brew install webcodr/tap/srchr
</span></span></code></pre></div>]]></content:encoded>
    </item>
    
    <item>
      <title>Using fd, rg, fzf and bat to find things fast</title>
      <link>https://webcodr.io/2026/07/using-fd-rg-fzf-and-bat-to-find-things-fast/</link>
      <pubDate>Sun, 05 Jul 2026 17:05:03 +0000</pubDate>
      <guid>https://webcodr.io/2026/07/using-fd-rg-fzf-and-bat-to-find-things-fast/</guid>
      <description>Modern terminal programs like fd or rg make it really easy to find stuff, but there’s still room for improvement. In this post I will show you how to use fish to write two small functions with fd, rg, fzf and bat to search for file names and file content with an interactive list and even a preview in the terminal.
I don’t know that stuff? First things first. If you already know fd or the other tools from above, feel free to skip this section.
</description>
      <content:encoded><![CDATA[<p>Modern terminal programs like <code>fd</code> or <code>rg</code> make it really easy to find stuff, but there&rsquo;s still room for improvement. In this post I will show you how to use fish to write two small functions with <code>fd</code>, <code>rg</code>, <code>fzf</code> and <code>bat</code> to search for file names and file content with an interactive list and even a preview in the terminal.</p>
<h2 id="i-dont-know-that-stuff"><a href="#i-dont-know-that-stuff" class="heading-anchor">I don&rsquo;t know that stuff?</a></h2>
<p>First things first. If you already know <code>fd</code> or the other tools from above, feel free to skip this section.</p>
<ul>
<li><code>fd</code> is a more user-friendly replacement for <code>find</code></li>
<li><code>rg</code> or ripgrep is <code>grep</code> on steroids, respecting git ignore files and skipping binaries or hidden files</li>
<li><code>fzf</code> is a command-line fuzzy finder. You basically can pipe everything into <code>fzf</code> and just type to filter the output</li>
<li><code>bat</code> is a modern version of <code>cat</code> with syntax highlighting and git integration</li>
</ul>
<h2 id="say-hi-to-rgp-and-fdp"><a href="#say-hi-to-rgp-and-fdp" class="heading-anchor">Say hi to rgp and fdp</a></h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fish" data-lang="fish"><span class="line"><span class="cl"><span class="k">function</span> <span class="nf">rgp</span>
</span></span><span class="line"><span class="cl">    <span class="k">set</span> <span class="na">-l</span> <span class="nv">search_term</span> <span class="nv">$argv</span><span class="o">[</span><span class="m">1</span><span class="o">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="k">test</span> <span class="na">-z</span> <span class="s2">&#34;</span><span class="nv">$search_term</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="k">echo</span> <span class="s2">&#34;Usage: rgp &lt;search_term&gt;&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="m">1</span>
</span></span><span class="line"><span class="cl">    <span class="k">end</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nf">rg</span> <span class="na">-l</span> <span class="nv">$search_term</span> <span class="o">|</span> <span class="nf">fzf</span> <span class="na">--preview</span> <span class="s1">&#39;bat --color always {}&#39;</span> <span class="na">--bind</span> <span class="s1">&#39;enter:become(&#34;$EDITOR&#34; {+})&#39;</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">function</span> <span class="nf">fdp</span>
</span></span><span class="line"><span class="cl">    <span class="k">set</span> <span class="na">-l</span> <span class="nv">search_term</span> <span class="nv">$argv</span><span class="o">[</span><span class="m">1</span><span class="o">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="k">test</span> <span class="na">-z</span> <span class="s2">&#34;</span><span class="nv">$search_term</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="k">echo</span> <span class="s2">&#34;Usage: fdp &lt;search_term&gt;&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="m">1</span>
</span></span><span class="line"><span class="cl">    <span class="k">end</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nf">fd</span> <span class="na">-tf</span> <span class="nv">$search_term</span> <span class="o">|</span> <span class="nf">fzf</span> <span class="na">--preview</span> <span class="s1">&#39;bat --color always {}&#39;</span> <span class="na">--bind</span> <span class="s1">&#39;enter:become(&#34;$EDITOR&#34; {+})&#39;</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span>
</span></span></code></pre></div><p>That&rsquo;s all you need. Put them into your fish config file or the fish functions folder.</p>
<h2 id="usage"><a href="#usage" class="heading-anchor">Usage</a></h2>
<p><code>rgp something</code> &ndash; this will use <code>rg</code> to recursively search the current directory for files with <code>something</code> inside. The result is piped into <code>fzf</code>. You can now filter the result further with <code>fzf</code> or select a file with the arrow keys and <code>bat</code> will give you a live preview of the file with syntax highlighting. Pressing <code>enter</code> will open the selected file with your default editor (environment variable <code>EDITOR</code>).</p>
<p><code>fdp</code> works similarly, but looks for file names instead of the file content and also pipes the result to <code>fzf</code> for further filtering, preview or opening the selected file.</p>
<p>Don&rsquo;t like fish? Here&rsquo;s a version that works with bash or zsh.</p>
<p><strong>Note</strong>: the <code>local</code> keyword is not POSIX-compliant. If you need that, just remove it, but this makes <code>search_term</code> global, so use with care.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">rgp<span class="o">()</span> <span class="o">{</span>
</span></span><span class="line"><span class="cl">    <span class="nb">local</span> <span class="nv">search_term</span><span class="o">=</span><span class="nv">$1</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="o">[</span> -z <span class="s2">&#34;</span><span class="nv">$search_term</span><span class="s2">&#34;</span> <span class="o">]</span><span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl">        <span class="nb">echo</span> <span class="s2">&#34;Usage: rgp &lt;search_term&gt;&#34;</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="m">1</span>
</span></span><span class="line"><span class="cl">    <span class="k">fi</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    rg -l <span class="s2">&#34;</span><span class="nv">$search_term</span><span class="s2">&#34;</span> <span class="p">|</span> fzf --preview <span class="s1">&#39;bat --color always {}&#39;</span> --bind <span class="s1">&#39;enter:become(&#34;$EDITOR&#34; {+})&#39;</span>
</span></span><span class="line"><span class="cl"><span class="o">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">fdp<span class="o">()</span> <span class="o">{</span>
</span></span><span class="line"><span class="cl">    <span class="nb">local</span> <span class="nv">search_term</span><span class="o">=</span><span class="nv">$1</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="o">[</span> -z <span class="s2">&#34;</span><span class="nv">$search_term</span><span class="s2">&#34;</span> <span class="o">]</span><span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl">        <span class="nb">echo</span> <span class="s2">&#34;Usage: fdp &lt;search_term&gt;&#34;</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="m">1</span>
</span></span><span class="line"><span class="cl">    <span class="k">fi</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    fd -tf <span class="s2">&#34;</span><span class="nv">$search_term</span><span class="s2">&#34;</span> <span class="p">|</span> fzf --preview <span class="s1">&#39;bat --color always {}&#39;</span> --bind <span class="s1">&#39;enter:become(&#34;$EDITOR&#34; {+})&#39;</span>
</span></span><span class="line"><span class="cl"><span class="o">}</span>
</span></span></code></pre></div>]]></content:encoded>
    </item>
    
    <item>
      <title>More awesome CLI tools</title>
      <link>https://webcodr.io/2025/08/more-awesome-cli-tools/</link>
      <pubDate>Fri, 29 Aug 2025 21:34:15 +0000</pubDate>
      <guid>https://webcodr.io/2025/08/more-awesome-cli-tools/</guid>
      <description>This is a follow-up article to Awesome CLI tools with even more useful CLI tools.
btop It’s top on steroids with a beautiful terminal UI. Way more information at a glance and just a joy to use.
delta Do you often look at git diffs? Are you missing syntax highlighting? delta is here to help. Just install it, configure delta as pager for git and voila, diffs with syntax highlighting.
dog Dog is a modern DNS lookup tool with colored output and a simple interface.
</description>
      <content:encoded><![CDATA[<p>This is a follow-up article to <a href="/2024/03/awesome-cli-tools/">Awesome CLI tools</a> with even more useful CLI tools.</p>
<h2 id="btop"><a href="#btop" class="heading-anchor">btop</a></h2>
<p>It&rsquo;s <code>top</code> on steroids with a beautiful terminal UI. Way more information at a glance and just a joy to use.</p>
<h2 id="delta"><a href="#delta" class="heading-anchor">delta</a></h2>
<p>Do you often look at git diffs? Are you missing syntax highlighting? <code>delta</code> is here to help. Just install it, configure delta as pager for git and voila, diffs with syntax highlighting.</p>
<h2 id="dog"><a href="#dog" class="heading-anchor">dog</a></h2>
<p>Dog is a modern DNS lookup tool with colored output and a simple interface.</p>
<h2 id="tokei"><a href="#tokei" class="heading-anchor">tokei</a></h2>
<p>Are you a fan of statistics? Tokei can summarize file types, lines of code, comments or blank spaces of your project.</p>
<p>I&rsquo;m currently converting a large Java project to Kotlin and tokei makes it easy to see the progress.</p>
<h2 id="procs"><a href="#procs" class="heading-anchor">procs</a></h2>
<p>A modern replacement for <code>ps</code> with colored output, keyword search, tree view and some useful helpers for networking (ports) and Docker.</p>
<h2 id="lazygit"><a href="#lazygit" class="heading-anchor">lazygit</a></h2>
<p>One of my favorites. Lazygit is a dead simple, yet powerful and elegant to use terminal UI for git. I&rsquo;m not a fan of the git CLI and always preferred a GUI tool like Tower, but nowadays lazygit is my git client of choice. I don&rsquo;t think there is a better git client out there. Even many NeoVim distributions support it out-of-the-box (LazyVim with <code>LEADER</code> + <code>gg</code>).</p>
<h2 id="sd"><a href="#sd" class="heading-anchor">sd</a></h2>
<p>Do you use <code>sed</code>? Do you like it? I don&rsquo;t. <code>sd</code> is better, much better.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Awesome CLI Tools</title>
      <link>https://webcodr.io/2024/03/awesome-cli-tools/</link>
      <pubDate>Wed, 06 Mar 2024 20:21:06 +0000</pubDate>
      <guid>https://webcodr.io/2024/03/awesome-cli-tools/</guid>
      <description>There are some incredibly useful CLI tools out there. Here’s a list with some awesome tools I’m using for my daily work.
atuin Atuin is a history replacement with a fuzzy finding search and sync/backup options (self-hosted if you need). It’s written in Rust (blazingly fast!) and stores the history entries in a SQLite db. You can even import your current history from your shell. Atuin supports bash, zsh, fish and NuShell.
</description>
      <content:encoded><![CDATA[<p>There are some incredibly useful CLI tools out there. Here&rsquo;s a list with some awesome tools I&rsquo;m using for my daily work.</p>
<h2 id="atuin"><a href="#atuin" class="heading-anchor">atuin</a></h2>
<p><a href="https://atuin.sh/">Atuin</a> is a history replacement with a fuzzy finding search and sync/backup options (self-hosted if you need). It&rsquo;s written in Rust (blazingly fast!) and stores the history entries in a SQLite db. You can even import your current history from your shell. Atuin supports bash, zsh, fish and NuShell.</p>
<h2 id="bat"><a href="#bat" class="heading-anchor">bat</a></h2>
<p>Need <code>cat</code> a lot? <a href="https://github.com/sharkdp/bat">Bat</a> is a cat clone on steroids with syntax highlighting, themes, git integration and much more.</p>
<h2 id="eza"><a href="#eza" class="heading-anchor">eza</a></h2>
<p>Everyone needs <code>ls</code> ? Nope, <a href="https://eza.rocks/">eza</a> is much better. Colored output, icons via nerd fonts, git status tracking per file, tons of display options &hellip;</p>
<h2 id="tldr"><a href="#tldr" class="heading-anchor">tldr</a></h2>
<p>Reading a man page can be frustrating, why can&rsquo;t I just have the TL;DR version? Well, <a href="https://tldr.sh/">tldr</a> does exactly that. Just use it like <code>man</code> and enjoy the TL;DR version of a man page.</p>
<h2 id="zoxide"><a href="#zoxide" class="heading-anchor">zoxide</a></h2>
<p>Like its siblings, <code>cd</code> is a little dated and clunky. With <a href="https://github.com/ajeetdsouza/zoxide">zoxide</a> you can easily jump to directories without typing the full path. It stores a history of your visited paths and you can jump via keywords to your directories.</p>
<h2 id="chezmoi"><a href="#chezmoi" class="heading-anchor">chezmoi</a></h2>
<p>You&rsquo;re using multiple computers or just want a simple and reliable way to store your dot files? <a href="https://www.chezmoi.io/">Chezmoi</a> is your friend and stores your dot files in a git repo with syncing capabilities to other devices. It&rsquo;s even possible to encrypt your files. If you have secrets in your dot files, chezmoi comes with integrations for many password managers to safely store your passwords, tokens etc.</p>
<h2 id="starship"><a href="#starship" class="heading-anchor">starship</a></h2>
<p>Your shell looks boring? Just theme it with <a href="https://starship.rs/">starship</a>! It&rsquo;s pretty easy to build your own and if you don&rsquo;t want to, there are many themes available. Starship also has integrations for many dev tools to show the current git status or currently active versions of your runtime environments like NodeJS, Rust, Go, Java etc.</p>
<h2 id="fzf"><a href="#fzf" class="heading-anchor">fzf</a></h2>
<p>Finding files with the usual suspects works fine, but <a href="https://github.com/junegunn/fzf">fzf</a> can do this faster and much more intuitive. It&rsquo;s a fuzzy finding search within your current directory, processes, git commits, history (if you don&rsquo;t like Atuin) and much more.</p>
<h2 id="ripgrep"><a href="#ripgrep" class="heading-anchor">ripgrep</a></h2>
<p>Ripgrep is a really fast regex-based search tool and can do much more than <code>grep</code> alone.</p>
<h2 id="btop"><a href="#btop" class="heading-anchor">btop</a></h2>
<p>Another <code>top</code> variant? Yup, but <a href="https://github.com/aristocratos/btop">btop</a> is way more like its modern GUI-based colleagues on macOS or Windows with CPU and GPU usage, process trees, I/O and disk activities, battery status &hellip;</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Introducing Server Runner</title>
      <link>https://webcodr.io/2023/05/introducing-server-runner/</link>
      <pubDate>Fri, 26 May 2023 23:53:33 +0000</pubDate>
      <guid>https://webcodr.io/2023/05/introducing-server-runner/</guid>
      <description>In my recent adventures with Rust, I planned to write a REST API with the help of the excellent book “Zero To Production In Rust” from Luca Palmieri. That’s still happening, but as a small side project, I wanted to write some kind of CLI tool.
A few weeks ago I wrote a bash script to run some web servers and check their status until they’re up and running. When all servers are ready, a command would be executed and all servers would be closed after this command is finished. Since I hate bash with a passion, I asked a friend to help me: ChatGPT.
</description>
      <content:encoded><![CDATA[<p>In my recent adventures with Rust, I planned to write a REST API with the help of the excellent book &ldquo;Zero To Production In Rust&rdquo; from Luca Palmieri. That&rsquo;s still happening, but as a small side project, I wanted to write some kind of CLI tool.</p>
<p>A few weeks ago I wrote a bash script to run some web servers and check their status until they&rsquo;re up and running. When all servers are ready, a command would be executed and all servers would be closed after this command is finished. Since I hate bash with a passion, I asked a friend to help me: ChatGPT.</p>
<p>I would never trust an AI in this day and age to write a code base for me, but for small scripts? Why not. As long as the scope is small and I can understand the code, ChatGPT is a really good tool. That script does exactly what I want and it&rsquo;s easy enough to understand, even for me as a bash hater.</p>
<p>But I wanted to do this properly and so I decided to rewrite this script as a small CLI tool program in Rust: Server Runner. Well, not a very creative name, but it does what it says.</p>
<h2 id="configuration"><a href="#configuration" class="heading-anchor">Configuration</a></h2>
<p>Server Runner is quite simple and just needs a small YAML file as configuration. Here&rsquo;s a small example.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">servers</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;Hello World&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">url</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;http://localhost:3000&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">command</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;node index.js&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">command</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;node sleep.js&#34;</span><span class="w">
</span></span></span></code></pre></div><p>To start server runner, just run:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">server-runner -c servers.yaml
</span></span></code></pre></div><p>Server Runner will execute all server commands defined in the config section <code>servers</code> and waits until the URLs return HTTP 200. When all servers are up and running, the primary command will be started. After the command finished, all server processes will be killed off.</p>
<h2 id="how-do-i-get-it"><a href="#how-do-i-get-it" class="heading-anchor">How do I get it?</a></h2>
<p>Server Runner is available as a <a href="https://crates.io/crates/server-runner">Cargo Crate</a> and will be published soon on NPM with executables for macOS (aarch64, x86_64), Linux (aarch64, x86_64) and Windows (x86_64).</p>
<h3 id="installation-via-cargo"><a href="#installation-via-cargo" class="heading-anchor">Installation via Cargo</a></h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">cargo add server-runner
</span></span></code></pre></div><p>The source code is available on <a href="https://github.com/webcodr/server-runner">GitHub</a>.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Terminal evolved</title>
      <link>https://webcodr.io/2023/05/terminal-evolved/</link>
      <pubDate>Mon, 15 May 2023 19:22:14 +0000</pubDate>
      <guid>https://webcodr.io/2023/05/terminal-evolved/</guid>
      <description>I always saw myself as a casual user of the terminal. I preferred zsh with the Prezto framework within iTerm 2 with tabs and that’s about it. No more! A colleague of mine introduced me to kitty as terminal emulator, together with tmux and Neovim. That’s a lot to swallow. I was never a fan of the vi/vim user experience and more of a mouse guy. Well, what should I say? It’s awesome if you’re getting used to it. Let me explain …
</description>
      <content:encoded><![CDATA[<p>I always saw myself as a casual user of the terminal. I preferred zsh with the Prezto framework within iTerm 2 with tabs and that&rsquo;s about it. No more! A colleague of mine introduced me to kitty as terminal emulator, together with tmux and Neovim. That&rsquo;s a lot to swallow. I was never a fan of the vi/vim user experience and more of a mouse guy. Well, what should I say? It&rsquo;s awesome if you&rsquo;re getting used to it. Let me explain &hellip;</p>
<h2 id="jfyi"><a href="#jfyi" class="heading-anchor">JFYI</a></h2>
<p>kitty, tmux and nvim are available in Homebrew on macOS and should be also available in your favorite package manager on Linux.</p>
<p>Be aware, that most examples contain some macOS-specific settings marked with corresponding comments, as I am a Mac user.</p>
<h2 id="kitty"><a href="#kitty" class="heading-anchor">kitty</a></h2>
<p>iTerm 2 is a pretty good terminal emulator with many features and way better than Apple&rsquo;s sorry excuse of a terminal. To be fair, the macOS terminal app has gotten better over the years, but it still lacks essential features like true color support. As good as iTerm 2 is, there&rsquo;s one catch: iTerm 2 is slow. GPU-accelerated alternatives like kitty render much faster. Don&rsquo;t get me wrong, iTerm 2 is no slouch and works well, but if you&rsquo;re on the way to a terminal power-user, you will notice it. Switching between tmux windows is much faster in kitty or other terminal emulators like Alacritty. The latter is a really nice app, but unfortunately has some trouble with macOS key bindings within tmux and I found no easy solution to that. Kitty works out of the box.</p>
<h3 id="taming-the-kitten"><a href="#taming-the-kitten" class="heading-anchor">Taming the kitten</a></h3>
<p>Kitty&rsquo;s configuration is very well documented, but can be overwhelming. There are hundreds of options to explore. One of the most important is the font. Grab yourself a <a href="https://www.nerdfonts.com/">nerd-font</a>, add it to your OS and specify the font family. I&rsquo;m using &ldquo;Hack Nerd Font Mono&rdquo; for this example. Just open your kitty config in <code>~/.config/kitty/kitty.conf</code> and add the following:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-toml" data-lang="toml"><span class="line"><span class="cl"><span class="c"># Replace with your preferred font</span>
</span></span><span class="line"><span class="cl"><span class="nx">font_family</span>			<span class="nx">Hack</span> <span class="nx">Nerd</span> <span class="nx">Font</span> <span class="nx">Mono</span> 
</span></span><span class="line"><span class="cl"><span class="nx">bold_font</span>			<span class="nx">auto</span>
</span></span><span class="line"><span class="cl"><span class="nx">italic_font</span>			<span class="nx">auto</span>
</span></span><span class="line"><span class="cl"><span class="nx">bold_italic_font</span>	<span class="nx">auto</span>
</span></span><span class="line"><span class="cl"><span class="c"># Replace with your preferred font size in points</span>
</span></span><span class="line"><span class="cl"><span class="nx">font_size</span>			<span class="mf">17.0</span> 
</span></span></code></pre></div><p>Save and reload the config via menu bar. Enjoy!</p>
<p>Now that&rsquo;s out of the way, how about some comfort features?</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-toml" data-lang="toml"><span class="line"><span class="cl"><span class="c"># Set how many lines the buffer can scroll back</span>
</span></span><span class="line"><span class="cl"><span class="nx">scrollback_lines</span> <span class="mi">10000</span> 
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># Auto-detect URLs</span>
</span></span><span class="line"><span class="cl"><span class="nx">detect_url</span> <span class="nx">yes</span>
</span></span><span class="line"><span class="cl"><span class="c"># Open URLs with ctrl + click</span>
</span></span><span class="line"><span class="cl"><span class="nx">mouse_map</span> <span class="nx">ctrl</span><span class="err">+</span><span class="nx">left</span> <span class="nx">press</span> <span class="nx">ungrabbed</span><span class="p">,</span><span class="nx">grabbed</span> <span class="nx">mouse_click_url</span> 
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># Copy the mouse selection directly to the clipboard</span>
</span></span><span class="line"><span class="cl"><span class="nx">copy_on_select</span> <span class="nx">yes</span> 
</span></span><span class="line"><span class="cl"><span class="c"># Paste on right click</span>
</span></span><span class="line"><span class="cl"><span class="nx">mouse_map</span> <span class="nx">right</span> <span class="nx">press</span> <span class="nx">grabbed</span><span class="p">,</span><span class="nx">ungrabbed</span> <span class="nx">no-op</span>
</span></span><span class="line"><span class="cl"><span class="nx">mouse_map</span> <span class="nx">right</span> <span class="nx">click</span> <span class="nx">grabbed</span><span class="p">,</span><span class="nx">ungrabbed</span> <span class="nx">paste_from_clipboard</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># Enable macOS copy &amp; paste via CMD + c/v</span>
</span></span><span class="line"><span class="cl"><span class="nx">map</span> <span class="nx">cmd</span><span class="err">+</span><span class="nx">c</span> <span class="nx">copy_to_clipboard</span>
</span></span><span class="line"><span class="cl"><span class="nx">map</span> <span class="nx">cmd</span><span class="err">+</span><span class="nx">v</span> <span class="nx">paste_from_clipboard</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># Jump to beginning and end of a word with alt and arrow keys (macOS)</span>
</span></span><span class="line"><span class="cl"><span class="nx">map</span> <span class="nx">alt</span><span class="err">+</span><span class="nx">left</span> <span class="nx">send_text</span> <span class="nx">all</span> <span class="err">\</span><span class="nx">x1b</span><span class="err">\</span><span class="nx">x62</span>
</span></span><span class="line"><span class="cl"><span class="nx">map</span> <span class="nx">alt</span><span class="err">+</span><span class="nx">right</span> <span class="nx">send_text</span> <span class="nx">all</span> <span class="err">\</span><span class="nx">x1b</span><span class="err">\</span><span class="nx">x66</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># Jump to beginning and end of a line with cmd and arrow keys (macOS)</span>
</span></span><span class="line"><span class="cl"><span class="nx">map</span> <span class="nx">cmd</span><span class="err">+</span><span class="nx">left</span> <span class="nx">send_text</span> <span class="nx">all</span> <span class="err">\</span><span class="nx">x01</span>
</span></span><span class="line"><span class="cl"><span class="nx">map</span> <span class="nx">cmd</span><span class="err">+</span><span class="nx">right</span> <span class="nx">send_text</span> <span class="nx">all</span> <span class="err">\</span><span class="nx">x05</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># Nicer titlebar on macOS</span>
</span></span><span class="line"><span class="cl"><span class="nx">macos_titlebar_color</span> <span class="nx">background</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># Make vim the default editor for the kitty config</span>
</span></span><span class="line"><span class="cl"><span class="nx">editor</span> <span class="nx">vim</span>
</span></span></code></pre></div><p>Want some color? No problem, there are hundreds of themes available just a Google search away. I prefer <a href="https://github.com/catppuccin/catppuccin">Catppuccin Macchiato</a>, but choose what ever you want. kitty config files support includes, so it&rsquo;s easy to add a theme:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-toml" data-lang="toml"><span class="line"><span class="cl"><span class="nx">include</span> <span class="p">.</span><span class="err">/</span><span class="nx">theme</span><span class="p">.</span><span class="nx">conf</span>
</span></span></code></pre></div><p>And put the file <code>theme.conf</code> in the same directory as the kitty config and paste your theme of choice into the file.</p>
<h2 id="tmux"><a href="#tmux" class="heading-anchor">tmux</a></h2>
<p>So, what the hell is tmux? If you need a terminal, tmux will be one of your best friends. Did you ever run something complex on the shell and accidentally closed the terminal window or something similar happened during an SSH session? It sucks.</p>
<p>tmux sessions to the rescue! A session will be open until you close it, so even if your internet connection breaks down during an SSH session, nothing will vanish. Just connect to the server again and re-join the tmux session. Everything will be as you left it.</p>
<p>Just type <code>tmux new</code> or if you want to give the session a name <code>tmux new -s my_new_session</code> . Of course tmux can handle multiple sessions. To list all open sessions use <code>tmux ls</code> and to join a session type <code>tmux a -t session_name</code> .</p>
<p>After opening a new session, tmux will display window 0. Need more windows? No problem. Need a window inside a window? No problem, they are called panes. Windows can be split in horizontal or vertical panes, as many and wild as you like.</p>
<p>Inside a tmux session you can trigger commands via a so-called prefix key following one or more keys to tell tmux what you want to do. The default prefix key is <code>ctrl + b</code> . To split your current window into two horizontal panes press <code>ctrl + b</code> followed by <code>%</code> , for a vertical split use <code>ctrl + b</code> and <code>&quot;</code>.</p>
<p>To close a pane, just exit the shell of the pane with <code>exit</code>. You can switch panes with <code>ctrl + b</code> followed by an arrow key in the corresponding direction.</p>
<p>Our new best friend <code>ctrl + b</code> is not the most intuitive key combination. I recommend using <code>ctrl + a</code> and map the caps lock key to ctrl (pro-tip: macOS can do this for you without tools or customizable keyboard firmware). It&rsquo;s way faster and easier to press. Of course, you can map whatever key combination you want, just beware of conflicts with other combinations like <code>cmd + space</code>.</p>
<p>To change the command key, go to your tmux config in <code>~/.tmux.conf</code> and add the following lines:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-toml" data-lang="toml"><span class="line"><span class="cl"><span class="nx">unbind</span> <span class="nx">C-b</span>
</span></span><span class="line"><span class="cl"><span class="nx">set</span> <span class="nx">-g</span> <span class="nx">prefix</span> <span class="nx">C-a</span>
</span></span><span class="line"><span class="cl"><span class="nx">bind-key</span> <span class="nx">C-a</span> <span class="nx">send-prefix</span>
</span></span></code></pre></div><p>This unbinds <code>ctrl + b</code> and sets the prefix key to <code>ctrl + a</code>. To reload the tmux config inside a session use <code>tmux source-file ~/.tmux.conf</code>.</p>
<h3 id="more-more"><a href="#more-more" class="heading-anchor">More? More!</a></h3>
<p>There is much more you can do. Here are some recommendations.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-toml" data-lang="toml"><span class="line"><span class="cl"><span class="c"># Enable mouse support</span>
</span></span><span class="line"><span class="cl"><span class="nx">set</span> <span class="nx">-g</span> <span class="nx">mouse</span> <span class="nx">on</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># Set history limit to 100,000 lines</span>
</span></span><span class="line"><span class="cl"><span class="nx">set-option</span> <span class="nx">-g</span> <span class="nx">history-limit</span> <span class="mi">100000</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># Enable true color support</span>
</span></span><span class="line"><span class="cl"><span class="nx">set-option</span> <span class="nx">-sa</span> <span class="nx">terminal-overrides</span> <span class="s2">&#34;,xterm*:Tc&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># Start windows and panes at 1, not 0</span>
</span></span><span class="line"><span class="cl"><span class="nx">set</span> <span class="nx">-g</span> <span class="nx">base-index</span> <span class="mi">1</span>
</span></span><span class="line"><span class="cl"><span class="nx">set</span> <span class="nx">-g</span> <span class="nx">pane-base-index</span> <span class="mi">1</span>
</span></span><span class="line"><span class="cl"><span class="nx">set-window-option</span> <span class="nx">-g</span> <span class="nx">pane-base-index</span> <span class="mi">1</span>
</span></span><span class="line"><span class="cl"><span class="nx">set-option</span> <span class="nx">-g</span> <span class="nx">renumber-windows</span> <span class="nx">on</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># Open new panes in the same directory as their parent pane</span>
</span></span><span class="line"><span class="cl"><span class="nx">bind</span> <span class="s1">&#39;&#34;&#39;</span> <span class="nx">split-window</span> <span class="nx">-v</span> <span class="nx">-c</span> <span class="s2">&#34;#{pane_current_path}&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nx">bind</span> <span class="err">%</span> <span class="nx">split-window</span> <span class="nx">-h</span> <span class="nx">-c</span> <span class="s2">&#34;#{pane_current_path}&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># Vim style pane selection</span>
</span></span><span class="line"><span class="cl"><span class="nx">bind</span> <span class="nx">h</span> <span class="nx">select-pane</span> <span class="nx">-L</span>
</span></span><span class="line"><span class="cl"><span class="nx">bind</span> <span class="nx">j</span> <span class="nx">select-pane</span> <span class="nx">-D</span> 
</span></span><span class="line"><span class="cl"><span class="nx">bind</span> <span class="nx">k</span> <span class="nx">select-pane</span> <span class="nx">-U</span>
</span></span><span class="line"><span class="cl"><span class="nx">bind</span> <span class="nx">l</span> <span class="nx">select-pane</span> <span class="nx">-R</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># Shift arrow to switch windows</span>
</span></span><span class="line"><span class="cl"><span class="nx">bind</span> <span class="nx">-n</span> <span class="nx">S-Left</span>  <span class="nx">previous-window</span>
</span></span><span class="line"><span class="cl"><span class="nx">bind</span> <span class="nx">-n</span> <span class="nx">S-Right</span> <span class="nx">next-window</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># Don&#39;t scroll down on copy via mouse</span>
</span></span><span class="line"><span class="cl"><span class="nx">unbind</span> <span class="nx">-T</span> <span class="nx">copy-mode-vi</span> <span class="nx">MouseDragEnd1Pane</span>
</span></span></code></pre></div><p>With mouse support you can resize panes with drag &amp; drop and even get a context menu with a right click. By default tmux assigns numbers to windows for fast switching via <code>ctrl + b</code> and <code>number key</code>. Unfortunately the developers decided to begin with 0. This is technically correct, but on the keyboard it&rsquo;s quite unintuitive, so we can tell tmux to begin with 1. The rest is pretty much self-explanatory.</p>
<h2 id="neovim"><a href="#neovim" class="heading-anchor">Neovim</a></h2>
<p>Why neo? Good old vim is extensible via vimscript. It works, but it&rsquo;s like bash: ugly as fuck. Neovim is a fork of vim and replaces vimscript with support for lua-based extensions. So it&rsquo;s still blazingly fast(tm) and much nicer to write extensions.</p>
<p>You could setup Neovim and the necessary extensions yourself, but I won&rsquo;t recommend it in the beginning. Pre-built configs like <a href="https://astronvim.com/">AstroNvim</a> or <a href="https://github.com/NvChad/NvChad">NvChad</a> will massively speed up the process and have great defaults. It can be very overwhelming to get used to vim/nvim, so I would recommend to wait with your own config until you get more familiar with a keyboard-based editor.</p>
<h3 id="help-i-cant-quit-vim"><a href="#help-i-cant-quit-vim" class="heading-anchor">HELP! I can&rsquo;t quit vim!</a></h3>
<p>Don&rsquo;t worry, you are not the first and will certainly not be the last. vim is a so-called modal-based editor. It has different modes like command, insert, visual etc. As you may have noticed, typing will not add text to the buffer. You need to press certain keys like <code>i</code>  to enter insert mode to edit text. There are other keys to go in insert mode and every one of them has a slightly different, but pretty useful function, like <code>o</code> which creates a new line below the cursor and starts insert mode.</p>
<p>To exit vim you have to leave the insert mode by pressing <code>esc</code>. Now you are in command mode and can quit by typing <code>:</code> to enter the command line mode and hit <code>q</code> for quit, followed by enter to execute the command.</p>
<p>If you want to save a file, enter command line mode and use <code>w</code> for write. It&rsquo;s possible to chain certain commands. <code>wq</code> will save the file and quit vim.</p>
<p>Congratulations, you now know how to exit vim!</p>
<h3 id="navigation"><a href="#navigation" class="heading-anchor">Navigation</a></h3>
<p>To move the cursor you would just use the arrow keys in most other editors. But there is a more efficient key mapping in command mode: <code>h</code> (left), <code>j</code> (down), <code>k</code> (up) and <code>l</code> (right). No need to move your hand to the arrow keys anymore. To be honest, I&rsquo;m still not comfortable with this way of navigation, but it&rsquo;s objectively more efficient than moving the right hand to the arrow keys.</p>
<p>Of course vim has way more navigation possibilities. For example, the cursor can jump forward by one word with <code>w</code> and backwards with <code>b</code>.  Press <code>$</code> to jump to the end of the current line or <code>0</code> to the beginning. <code>G</code> navigates you to the last line and <code>gg</code> jumps to the first line. And there is so much more to explore. I recommend a decent <a href="https://vim.rtorr.com/">vim cheat sheet</a> to learn. But do yourself a favor and try not to learn all keys at once. You will only become frustrated and give up more easily, it&rsquo;s just too much to learn everything in the beginning.</p>
<p>Netflix developer and Twitch Streamer <a href="https://twitter.com/ThePrimeagen">ThePrimeagen</a> designed a Neovim plug-in to learn the navigation commands as a game. It&rsquo;s pretty good and fun: <a href="https://github.com/ThePrimeagen/vim-be-good">https://github.com/ThePrimeagen/vim-be-good</a></p>
<p>AstroNvim has many plug-ins out of the box. Syntax highlighting, linting, auto-formatting etc. are all there, but you need to install the corresponding servers, parsers etc.</p>
<p>To do this, enter command line mode and use <code>LspInstall</code> followed by the language name for installing a language server protocol. A language server for <a href="https://github.com/tree-sitter/tree-sitter">Tree-Sitter</a> can be installed with <code>TSInstall</code> followed by the language name. If there&rsquo;s nothing available, both commands will recommend plug-ins according to your input, if available.</p>
<p>Be aware, that LSPs and Tree-Sitter will not bring the necessary tools with them. If you install tooling for Rust, rust-analyzer has to be installed on the system. Same goes for ESLint, Prettier, Kotlin, Java etc.</p>
<h2 id="the-end"><a href="#the-end" class="heading-anchor">The End</a></h2>
<h2 id="-for-now"><a href="#-for-now" class="heading-anchor">&hellip; for now</a></h2>
<p>That was a lot to unpack, but there is so much more to show you. I will be back with more productivity tools and tips in the near future. Stay tuned!</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>webcodr goes Netlify CMS</title>
      <link>https://webcodr.io/2020/10/webcodr-goes-netlify-cms/</link>
      <pubDate>Sat, 31 Oct 2020 22:54:24 +0000</pubDate>
      <guid>https://webcodr.io/2020/10/webcodr-goes-netlify-cms/</guid>
      <description>Until today posts on webcodr were published via a simple git-based workflow. If I wanted to create a new post, I had to open the repository in Visual Studio Code and create a markdown file. After pushing the commit with the new file, a GitHub hook notified Netlify to pull the repo and build and publish the site.
It was quite simple and effective, but lacks comfort and does not work on iOS/iPadOS devices. After buying a new iPad Air and Magic Keyboard, I wanted a pragmatic way to write posts without my MacBook or PC.
</description>
      <content:encoded><![CDATA[<p>Until today posts on webcodr were published via a simple git-based workflow. If I wanted to create a new post, I had to open the repository in Visual Studio Code and create a markdown file. After pushing the commit with the new file, a GitHub hook notified Netlify to pull the repo and build and publish the site.</p>
<p>It was quite simple and effective, but lacks comfort and does not work on iOS/iPadOS devices. After buying a new iPad Air and Magic Keyboard, I wanted a pragmatic way to write posts without my MacBook or PC.</p>
<p>I always wanted to try Netlify CMS, so this was my chance. The transition was really simple. I followed the guide for Hugo-based sites and adjusted the config to work with Hugo. That’s it. Netlify CMS works just fine with the already existing markdown files. Even custom frontmatter fields within the markdown files are no problem, just set them up in the config file.</p>
<p>A little more configuration in the Netlify admin panel is necessary, but the guide explains everything very well. It was just a matter of 15 minutes to get everything going.</p>
<p>If you use a static site generator and want to have a little more comfort, Netlify CMS makes it really simple. They provide guides for every major player like Gatsby, Jekyll or Nuxt and of course Hugo. You don’t even have to use GitHub. GitLab and BitBucket are supported as well. As are more complex workflows for more than one editor, custom authentication with OAuth or custom media libraries.</p>
<h2 id="editor"><a href="#editor" class="heading-anchor">Editor</a></h2>
<p>Netlify CMS supports markdown and has a basic, but decent editor with rich-text mode. But I wanted a little bit more, so I decided to write my posts in Ulysses — a specialized writing app with support of GitHub-flavored markdown, including syntax highlighting preview. It’s available for macOS and iOS/iPadOS. All files and settings are synched via iCloud. So, once you have setup everything, you’re good to go on any of your Apple devices.</p>
<p>Since Ulysses requires a subscription, I will use this to „force“ me writing more posts. 😁</p>
<p>I wrote this post entirely on my iPad Air and so far, I’m quite happy with the new workflow. Of course I will not write every post this way. New posts with code examples will be easier to handle on a Mac or PC. (Hey Apple, how about IntelliJ on an iPad?)</p>
<p>btw: even as an enthusiast of mechanical keyboards I have to say, it’s quite nice to type on a Magic Keyboard. I just have to get used to the smaller size. The Magic Keyboard for the 10.9“ iPad Air or 11“ iPad Pro is a compromise in size and some keys like tab, shift, backspace, enter and the umlaut keys (bracket keys on English keyboard layouts) are way smaller compared to normal-sized keyboards. Its bigger brother for the 13“ iPad Pro has a normal layout, but that monster of an iPad seems a bit excessive for my use case.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Kotest and JUnit with IntelliJ or: don’t frak up your toolchain upgrades</title>
      <link>https://webcodr.io/2020/08/kotest-and-junit-with-intellij-or-dont-frak-up-your-toolchain-upgrades/</link>
      <pubDate>Sat, 29 Aug 2020 22:26:07 +0200</pubDate>
      <guid>https://webcodr.io/2020/08/kotest-and-junit-with-intellij-or-dont-frak-up-your-toolchain-upgrades/</guid>
      <description>My team and I recently decided to use Kotlin for new features in our existing project. It was a great choice to implement a new authentication process and we’re now rewriting some older parts of the application from Java to Kotlin.
Actually I wanted to use Kotlin for a while now, but there were only minor tasks within the Java part of the project. That finally changed and we can focus to improve the Java backend drastically.
</description>
      <content:encoded><![CDATA[<p>My team and I recently decided to use Kotlin for new features in our existing project. It was a great choice to implement a new authentication process and we’re now rewriting some older parts of the application from Java to Kotlin.</p>
<p>Actually I wanted to use Kotlin for a while now, but there were only minor tasks within the Java part of the project. That finally changed and we can focus to improve the Java backend drastically.</p>
<p>Part of this process was a library update. We decided to upgrade JUnit from 4 to 5. A big pain in the ass. I don’t think, I would do it again. JUnit 5 was also part of a bigger problem, even if it was actually PEBKAC.</p>
<h2 id="kotest-and-mockk-features"><a href="#kotest-and-mockk-features" class="heading-anchor">Kotest and MockK features</a></h2>
<p>If you already know about Kotest or want to know more about the problem I had, just skip to the next headline. The Kotest introduction is a little bit longer.</p>
<p>As I dived more and more into Kotlin, I stumbled over Kotest. A really neat testing framework for Kotlin. There’s nothing wrong with JUnit, but Kotest gives you way more awesome ways to structure your tests.</p>
<p>A little example:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-kt" data-lang="kt"><span class="line"><span class="cl"><span class="k">package</span> <span class="nn">io.webcodr.demo</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">import</span> <span class="nn">io.webcodr.demo</span>
</span></span><span class="line"><span class="cl"><span class="k">import</span> <span class="nn">io.kotest.assertions.throwables.shouldThrow</span>
</span></span><span class="line"><span class="cl"><span class="k">import</span> <span class="nn">io.kotest.core.spec.style.FunSpec</span>
</span></span><span class="line"><span class="cl"><span class="k">import</span> <span class="nn">io.mockk.*</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">UserServiceTest</span> <span class="p">:</span> <span class="n">FunSpec</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">private</span> <span class="k">val</span> <span class="py">userRepository</span> <span class="p">=</span> <span class="n">mockk</span><span class="p">&lt;</span><span class="n">UserRepository</span><span class="p">&gt;()</span>
</span></span><span class="line"><span class="cl">    <span class="k">private</span> <span class="k">val</span> <span class="py">service</span> <span class="p">=</span> <span class="n">UserService</span><span class="p">(</span><span class="n">userRepository</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">private</span> <span class="k">lateinit</span> <span class="k">var</span> <span class="py">user</span><span class="p">:</span> <span class="n">User</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">init</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">beforeTest</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="n">user</span> <span class="p">=</span> <span class="n">User</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="s2">&#34;Jane&#34;</span><span class="p">,</span> <span class="s2">&#34;Doe&#34;</span><span class="p">,</span> <span class="s2">&#34;jane@doe.com&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="n">afterTest</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="n">clearAllMocks</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="n">context</span><span class="p">(</span><span class="s2">&#34;getUser()&#34;</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="k">fun</span> <span class="nf">verifyRepoCalls</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="n">verify</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                    <span class="n">userRepository</span><span class="p">.</span><span class="n">findById</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">                <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">                <span class="n">confirmVerified</span><span class="p">(</span><span class="n">userRepository</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">            <span class="n">test</span><span class="p">(</span><span class="s2">&#34;should succeed&#34;</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="n">every</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                    <span class="n">userRepository</span><span class="p">.</span><span class="n">findById</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">                <span class="p">}</span> <span class="n">returns</span> <span class="n">user</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">                <span class="n">service</span><span class="p">.</span><span class="n">getUser</span><span class="p">(</span><span class="mi">1</span><span class="p">).</span><span class="n">shouldBe</span><span class="p">(</span><span class="n">user</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">                <span class="n">verifyRepoCalls</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">            <span class="n">test</span><span class="p">(</span><span class="s2">&#34;should fail&#34;</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="n">every</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                    <span class="n">userRepository</span><span class="p">.</span><span class="n">findById</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">                <span class="p">}</span> <span class="n">throws</span> <span class="n">UserNotFoundException</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">                <span class="n">shouldThrow</span><span class="p">&lt;</span><span class="n">UserNotFoundException</span><span class="p">&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                    <span class="n">service</span><span class="p">.</span><span class="n">getUser</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">                <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">                <span class="n">verifyRepoCalls</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>Kotest offers several different styles to write tests. I chose the <code>FunSpec</code> style for this example. You could also use a BDD-like or Jasmine-like style, if you want to.</p>
<p>It’s much more intuitive to nest tests with Kotest. To be fair, JUnit 5 allows you to use <code>@Nested</code> with an inner class to accomplish nesting as well, but it’s not as intuitive and harder to read than trailing lambdas.</p>
<p>Assertions are also a little easier to write. Kotest has over 100 different matchers. You can use them as extension functions, like in the example above or alternatively as infix functions, for example <code>service.getUser(1) shouldBe user</code>. It’s also quite simple to write custom matchers.</p>
<p>There are many more features like soft assertions, tagging, easy temporary file creation or handling for non-deterministic test cases.</p>
<p>For mocking we decided to use MockK, since it’s way more intuitive to use than Mockito with Kotlin. Don’t get me wrong, Mockito is a great library, but it has one flaw: the <code>when</code> method. <code>when</code> is a keyword in Kotlin and to use it with Mockito, you need to write it in backticks. That’s quite ugly and not intuitive at all.</p>
<p>So, in summary, Kotest offers a bunch of pretty neat features and is very intuitive to use. Of course, JUnit can achieve much of this as well, it’s just not that shiny and little harder to read.</p>
<h2 id="the-actual-problem-or-why-the-frak-is-there-intellij-in-the-title"><a href="#the-actual-problem-or-why-the-frak-is-there-intellij-in-the-title" class="heading-anchor">The actual problem or: why the frak is there IntelliJ in the title?</a></h2>
<p>If you migrate an old codebase to Kotlin and want to use Kotest, you will have no choice and have to use JUnit and Kotest in coexistence.</p>
<p>That shouldn’t be a problem, since Kotest uses the JUnit 5 Jupiter engine under the hood. But …</p>
<p>As I wrote a new service in Kotlin and some tests with Kotest, I could not start the JUnit tests anymore. As soon as the maven dependency of Kotest was present, IntelliJ didn’t recognize JUnit tests and used the Kotest files only. With <code>mvn test</code> (Maven Surefire) everything worked fine.</p>
<p>I tried several things and was ready to give up. Search engines didn’t find anything about this problem. Nothing on GitHub, nothing on Stack Overflow.</p>
<p>I hate to give up, so I decided to create a small demo project to open a GitHub issue. Well, that didn’t work out as intended, since the discovery of JUnit tests in the demo project worked fine. The IntelliJ JUnit runner did what it was supposed to: run JUnit and Kotest.</p>
<p>Well, frak. There must be some kind of configuration problem with my real project. I already looked at the IntelliJ runner config, Maven files etc. — nothing worked.</p>
<p>I compared the Maven files from both codebases and there was one difference: my real project did not include the JUnit Jupiter Engine dependency. Bingo. I added it to the Maven file and guess what? It worked like a charm.</p>
<p>What an embarrassment. As we upgraded from JUnit 4 to 5, we forgot to add the new dependency for the engine. I don’t know why the tests worked at all, but it seems the engine is not really necessary for all cases. But it can screw up test discovery quite well, if you forget it.</p>
<p>The dependency configuration in the POM file should look like this:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-xml" data-lang="xml"><span class="line"><span class="cl"><span class="nt">&lt;dependency&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&lt;groupId&gt;</span>org.junit.jupiter<span class="nt">&lt;/groupId&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&lt;artifactId&gt;</span>junit-jupiter-api<span class="nt">&lt;/artifactId&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&lt;version&gt;</span>${junit.version}<span class="nt">&lt;/version&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&lt;scope&gt;</span>test<span class="nt">&lt;/scope&gt;</span>
</span></span><span class="line"><span class="cl"><span class="nt">&lt;/dependency&gt;</span>
</span></span><span class="line"><span class="cl"><span class="nt">&lt;dependency&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&lt;groupId&gt;</span>org.junit.jupiter<span class="nt">&lt;/groupId&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&lt;artifactId&gt;</span>junit-jupiter-engine<span class="nt">&lt;/artifactId&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&lt;version&gt;</span>${junit.version}<span class="nt">&lt;/version&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&lt;scope&gt;</span>test<span class="nt">&lt;/scope&gt;</span>
</span></span><span class="line"><span class="cl"><span class="nt">&lt;/dependency&gt;</span>
</span></span></code></pre></div><p>Well, that was a long post, but IMO it was necessary to show how this problem came to be and even if you have no trouble at all, perhaps you’ll consider using Kotest. It’s awesome!</p>
<h2 id="gradle"><a href="#gradle" class="heading-anchor">Gradle</a></h2>
<p>I’m not sure, but this issue could happen with Gradle as well, when you are migrating to JUnit 5.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Pimp Your Visual Studio Code</title>
      <link>https://webcodr.io/2018/04/pimp-your-visual-studio-code/</link>
      <pubDate>Sat, 21 Apr 2018 15:30:10 +0200</pubDate>
      <guid>https://webcodr.io/2018/04/pimp-your-visual-studio-code/</guid>
      <description>Like VS Code? Yeah, me too. Here are some very useful extensions and optical enhancements to get an even better experience with VS Code.
Extensions Settings Sync I love my Mac, but sometimes I have to do stuff (besides gaming) on my Windows PC as well. So, if I want to use the same config on both devices, I have to install my extensions and copy my config back and forth. That sucks. Settings Sync to the rescue! It syncs your settings, extensions etc. through the power of Gists on GitHub.
</description>
      <content:encoded><![CDATA[<p>Like VS Code? Yeah, me too. Here are some very useful extensions and optical enhancements to get an even better experience with VS Code.</p>
<h2 id="extensions"><a href="#extensions" class="heading-anchor">Extensions</a></h2>
<h3 id="settings-sync"><a href="#settings-sync" class="heading-anchor">Settings Sync</a></h3>
<p>I love my Mac, but sometimes I have to do stuff (besides gaming) on my Windows PC as well. So, if I want to use the same config on both devices, I have to install my extensions and copy my config back and forth. That sucks. Settings Sync to the rescue! It syncs your settings, extensions etc. through the power of Gists on GitHub.</p>
<p><a href="https://marketplace.visualstudio.com/items?itemName=Shan.code-settings-sync">Download</a></p>
<h3 id="bookmarks"><a href="#bookmarks" class="heading-anchor">Bookmarks</a></h3>
<p>It&rsquo;s quite simple: just bookmark certain lines of code you need often.</p>
<p><a href="https://marketplace.visualstudio.com/items?itemName=alefragnani.Bookmarks">Download</a></p>
<h3 id="editorconfig-for-vs-code"><a href="#editorconfig-for-vs-code" class="heading-anchor">EditorConfig for VS Code</a></h3>
<p>Share your coding styles between editors, IDEs etc. on a per project basis. It&rsquo;s really nice for teams as well.</p>
<p><a href="https://marketplace.visualstudio.com/items?itemName=EditorConfig.EditorConfig">Download</a></p>
<h3 id="bracket-pair-colorizer"><a href="#bracket-pair-colorizer" class="heading-anchor">Bracket Pair Colorizer</a></h3>
<p>Bracket madness? No more!</p>
<p><em>Update: The extension has been delisted, since VS Code now ships native bracket pair colorization — see the <code>editor.bracketPairColorization.enabled</code> setting.</em></p>
<h3 id="markdown-all-in-one"><a href="#markdown-all-in-one" class="heading-anchor">Markdown All in One</a></h3>
<p>Do you write a lot of Markdown? Here are some really useful helpers.</p>
<p><a href="https://marketplace.visualstudio.com/items?itemName=yzhang.markdown-all-in-one">Download</a></p>
<h2 id="themesicons"><a href="#themesicons" class="heading-anchor">Themes/Icons</a></h2>
<h3 id="cobalt2"><a href="#cobalt2" class="heading-anchor">Cobalt2</a></h3>
<p>If you like darker and bluish color themes, give Cobalt2 a try. The color choices with a contrast between yellow and blue can reduce strain on your eyes.</p>
<p><a href="https://marketplace.visualstudio.com/items?itemName=wesbos.theme-cobalt2">Download</a></p>
<h3 id="material-icon-theme"><a href="#material-icon-theme" class="heading-anchor">Material Icon Theme</a></h3>
<p>Matches nicely with Cobalt2 or other darker themes. There are a ton of icons for almost any file type and even for many special folders like <code>node_modules</code> etc.</p>
<p><a href="https://marketplace.visualstudio.com/items?itemName=PKief.material-icon-theme">Download</a></p>
<p>But that&rsquo;s not the end. VS Code can do much more, you can find some other very useful tips and tricks on <a href="https://web.archive.org/web/2018/https://vscodecandothat.com/">vscodecandothat.com</a> (now offline, linked via the Wayback Machine).</p>
<h2 id="dear-github"><a href="#dear-github" class="heading-anchor">Dear GitHub</a></h2>
<p>Look, I want to like Atom, but there are too many caveats. Atom is slow and resource hungry as hell, which is especially bad on a mobile device. It literally eats my MacBook&rsquo;s battery away. VS Code is not perfect either, but the general experience is much better. So, please, get your shit together and improve Atom. We need more awesome editors on the market!</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Tastaturen</title>
      <link>https://webcodr.io/2014/06/tastaturen/</link>
      <pubDate>Fri, 06 Jun 2014 22:31:23 +0100</pubDate>
      <guid>https://webcodr.io/2014/06/tastaturen/</guid>
      <description>Für uns Entwickler ist die Tastatur ohne Zweifel das wichtigste Werkzeug. Ohne sie könnten wir keine Zeile Code schreiben und dennoch wird ihr selten Beachtung geschenkt. Sie ist da und funktioniert – bis man eine Tasse Kaffee darüber schüttet oder sie nach Jahren in Krümeln, anderen Essensresten bzw. Staub ersoffen ist.
Wenn sie kaputt ist, wird für ein paar Euro eine neue gekauft und gut ist. Manchmal gibt man auch etwas mehr aus, z.B. für ein Apple Keyboard oder ein besseres Modell von Logitech.
</description>
      <content:encoded><![CDATA[<p>Für uns Entwickler ist die Tastatur ohne Zweifel das wichtigste Werkzeug. Ohne sie könnten wir keine Zeile Code schreiben und dennoch wird ihr selten Beachtung geschenkt. Sie ist da und funktioniert &ndash; bis man eine Tasse Kaffee darüber schüttet oder sie nach Jahren in Krümeln, anderen Essensresten bzw. Staub ersoffen ist.</p>
<p>Wenn sie kaputt ist, wird für ein paar Euro eine neue gekauft und gut ist. Manchmal gibt man auch etwas mehr aus, z.B. für ein Apple Keyboard oder ein besseres Modell von Logitech.</p>
<p>Dabei macht sich aber niemand Gedanken darüber, wie sie eigentlich funktioniert und ob da nicht gerade für uns Vieltipper Verbesserungspotenzial ist.</p>
<p>Die meisten Tastaturen haben eines gemeinsam: sie nutzen die sog. Rubberdome-Technik. Dabei wird beim Tastendruck eine Gumminoppe mit Kontaktpad nach unten auf die Platine gedrückt und so der Anschlag durch den Kontakt ausgelöst. Alle Noppen befinden sich auf einer Gummifolie, die einfach über die Platine gelegt wird. Kabel ans PCB, Tasten drauf, Gehäuse drumrum und fertig ist die Tastatur.</p>
<p>Das ist günstig, aber auch gut? Leider nein. Es gibt zwar durchaus ganz gute Vertreter dieser Gattung, aber die Schwachstellen haben sie alle gemein:</p>
<ol>
<li>Um den Anschlag auszulösen, muss man die Taste vollständig durchdrücken.</li>
<li>Der Anschlag ist nicht über alle Tasten konsistent und verändert sich mit der Zeit.</li>
<li>Gerade bei den billigen Vertretern, mitunter aber auch bei den teuren ist das Gehäuse nicht verwindungssteif.</li>
<li>Geringe Haltbarkeit von max. 5 Millionen Anschlägen.</li>
</ol>
<p>Die ersten drei Punkte fallen insbesondere für Vieltipper deutlich stärker ins Gewicht, als man meinen möchte. Vollständiges Durchdrücken der Tasten lässt die Hände bzw. Finger schnell ermüden &ndash; gleiches gilt, wenn sich die Tastatur beim Tippen verwindet bzw. nach unten verbiegt. Da sich der Anschlag ungleichmäßig über die Zeit und je nach Nutzung der Tasten verändert, kann sich kein Muskelgedächtnis bilden, um schneller tippen zu können.</p>
<h2 id="und-jetzt"><a href="#und-jetzt" class="heading-anchor">Und jetzt?</a></h2>
<p>Wie wär&rsquo;s mit einer Alternative? Mechanische Tastaturen!</p>
<p>Huch? Sind die nicht sauteuer, laut und sperrig? So wie früher diese Totschläger von IBM &hellip;</p>
<p>Hach ja, das IBM Model M. Wenn man wollte, könnte man damit wohl wirklich Einbrecher niederschlagen. Zur Selbstverteidigung empfehle ich aber doch eher andere Gerätschaften.</p>
<p>Ein billiges Vergnügen sind mechanische Tastaturen wirklich nicht, aber sie sind es definitiv wert. Hier geht es schließlich um ein Werkzeug. Handwerker geben sich schließlich auch nicht mit einem Consumer-Akkuschrauber für 20 Euro zufrieden. Warum also sollten wir das bei unseren alltäglichen Helfern tun? Ob sie laut und groß sind, hängt dagegen ganz vom jeweiligen Geschmack ab.</p>
<h2 id="aha-und-warum-können-die-dinger-das-nun-besser"><a href="#aha-und-warum-k%c3%b6nnen-die-dinger-das-nun-besser" class="heading-anchor">Aha, und warum können die Dinger das nun besser?</a></h2>
<p>Um die Kritikpunkte von oben direkt aufzugreifen:</p>
<ol>
<li>Mechanische Schalter müssen nicht vollständig durchgedrückt werden, um einen Anschlag auszulösen &ndash; die Hälfte genügt. Die verbreitetsten Schalter (Cherry MX) haben einen Hub von insgesamt 4 mm und lösen darum nach 2 mm aus.</li>
<li>Der Anschlag verändert sich weder mit der Zeit noch nutzen sich verschiedene Tasten je nach Gebrauch unterschiedlich ab. So bildet sich mit der Zeit ein Muskelgedächtnis, das schnelleres und komfortableres Schreiben ermöglicht.</li>
<li>Bei guten mechanischen Tastaturen sind die Schalter auf einer Stahlplatte angebracht, darunter befindet sich die Platine mit der sie verlötet sind. Da verwindet und verbiegt sich nichts.</li>
<li>Mechanische Tastaturen halten Jahrzehnte durch. Die durchschnittliche Lebensdauer von Cherry-Schaltern liegt bei ca. 50 Mio. Anschlägen. Unzerstörbar sind sie aber natürlich nicht.</li>
</ol>
<p>Je nach Schalter-Typ gibt es auch noch zusätzliche Vor- und Nachteile, so dass man sie ganz nach seinen Präferenzen aussuchen kann.</p>
<h2 id="schalter-typen"><a href="#schalter-typen" class="heading-anchor">Schalter-Typen</a></h2>
<p>Ich beschränke mich hierbei auf die gängen Varianten von Cherry, da sie am häufigsten verbaut werden.</p>
<ul>
<li>MX blue: löst mit einem Klick-Geräusch aus und hat dazu beim Anschlag einen spürbaren Widerstand. Betätigungskraft: 60 cN</li>
<li>MX brown: löst ohne Klick aus, besitzt aber den gleichen spürbaren Widerstand beim Anschlag wie der MX blue. Betätigungskraft: 55 cN</li>
<li>MX black: linearer Schalter, löst beim Anschlag weder einen Klick noch einen Widerstand aus. Betätigungskraft: 60 cN</li>
<li>MX red: wie MX black, nur mit geringerer Betätigungskraft: 45 cN</li>
</ul>
<p>Darüber hinaus gibt es noch verschiedene Varianten der MX blue und MX brown mit höherer Betätigungskraft. Man trifft sie allerdings eher selten an, manche davon sind sogar regelrecht rar.</p>
<p>Grundsätzlich gilt es beim Kauf einer Tastatur zuerst den Schalter-Typ zu wählen. Zum Entwickeln oder Schreiben sind die MX blue definitiv die beste Wahl, da sie ein hör- und spürbares Feedback bieten und daher nach der Eingewöhnung, sehr schnelles und flüssiges Tippen ohne Ermüdungserscheinungen ermöglichen.</p>
<p>Nun mag natürlich so manchen das Klicken auf die Palme bringen, andere wiederum können nicht mehr ohne. Wer sich daran stört oder die Kollegen im Büro nicht zum Amoklauf treiben will, aber dennoch spüren möchte, wenn der Anschlag ausgelöst wird, sollte zum MX brown greifen. Er tippt sich ein klein wenig leichter und ist ohne den Klick erheblich leiser.</p>
<p>Findet man dagegen Widerstand zwecklos, sollte man einen Blick auf die MX black oder MX red werfen. Letzterer ist besonders bei Spielern sehr beliebt, da man sehr schnell mehrere Anschläge hintereinander auslösen kann, ohne wie ein Bekloppter auf die Tastatur hämmern zu müssen. Dafür neigt man u.U. eher zu Vertippern.</p>
<p>Grundsätzlich kann man die Schalter in drei Kategorien aufteilen: Profi-Tipper ohne Klick-Allergie, die eher wenig bis gar nicht spielen, werden mit MX blue am glücklichsten. Möchte man dagegen einen guten Allrounder zum Schreiben und Spielen, ist der MX brown das Mittel der Wahl. Wer mehr spielt als Texte tippt, dürfte mit einem MX black oder MX red am besten klarkommen.</p>
<p>Ich empfehle aber jedem, verschiedene Schaltertypen auszuprobieren. Es gibt genug Spieler, die sich nicht am Klicken des MX blue stören und den MX red hassen wie die Pest &ndash; und umgekehrt genauso.</p>
<p>Noch etwas zur Lautstärke: man kann auch mit einem nicht klickenden Schalter schön Krach machen, wenn man auf der Tastatur rumhackt wie ein Irrer. Dazu hängt der Geräuschpegel auch von der Konstruktion bzw. dem Gehäuse ab. Dazu später etwas mehr (dasKeyboard Model S vs. dasKeyboard 4 vs. Corsair K70).</p>
<h2 id="was-kostet-der-spaß-und-wo-bekomme-ich-so-ein-teil-her"><a href="#was-kostet-der-spa%c3%9f-und-wo-bekomme-ich-so-ein-teil-her" class="heading-anchor">Was kostet der Spaß und wo bekomme ich so ein Teil her?</a></h2>
<p>Der Preis der gängigen Modelle liegt zwischen 60 und 200 Euro.</p>
<p>Die definitiv günstigste Wahl gibt&rsquo;s von Cherry selbst mit dem MX Keyboard 3.0. Zu bekommen bei Amazon oder den gängigen Hardware-Händlern.</p>
<p>Ansonsten ist die Auswahl an Shops eher eingeschränkt. Die EU und insbesondere Deutschland gehören bei mechanischen Tastaturen eher zur dritten Welt.</p>
<p>Die bisher besten Quellen, die ich neben Amazon ausmachen konnte: <a href="http://www.getdigital.de/">GetDigital</a> (dasKeyboard, Ducky, Filco, Leopold), <a href="https://www.caseking.de/">CaseKing</a> (Cherry und Ducky), <a href="http://www.keyboardco.com/">The Keyboard Company UK</a> (primär Filco und deren Zubehör).</p>
<p>Ansonsten stellen diverse bekannte Marken aus dem Spiele-Sektor wie Corsair, Razer, CMstorm, Func und auch Logitech mechanische Tastaturen her, die man auch in gängigen Läden und Shops bekommt.</p>
<p>Für professionelle Anwender rate ich zu Filco, Ducky oder dasKeyboard, da sie qualitativ etwas mehr bieten. Besonders Ducky und Filco bauen regelrechte Panzer. Grundsätzlich kann man mit den anderen aber nicht viel falsch machen. Man sollte aber inzwischen aufpassen, von welchem Hersteller die Switches sind. Da gibt es leider nicht nur Unterschiede in der Schaltcharakteristik, weil inzwischen wegen abgelaufener Patente auch billigere Kopien der MX-Schalter auf dem Markt sind, zu deren Haltbarkeit es noch keine Erfahrungswerte gibt. Die einschlägigen Foren sehen die Sache allerdings weniger gelassen &hellip;</p>
<h2 id="meine-erfahrung"><a href="#meine-erfahrung" class="heading-anchor">Meine Erfahrung</a></h2>
<p>Ich hatte mich im November vergangenen Jahres dazu entschlossen eine mechanische Tastatur auszuprobieren und entschied mich für eine Corsair K70 mit MX brown und blauer Hintergrundbeleuchtung. Die Tastatur hing nur an meinem Windows-Rechner, an dem ich eher wenig schreibe und mehr spiele.</p>
<p>Abgesehen von der Lautstärke durch die offene Konstruktion ohne einen Rahmen, der die Tasten umgibt, war ich mit der K70 sehr zufrieden. Nach einem Tipp im Computerbase-Forum, habe ich Gummi-O-Ringe zwischen die Tasten und Schalter montiert, was die Lautstärke deutlich dämpfte. Allerdings verändern solche Maßnahmen den Anschlag &ndash; einfach ausprobieren, die Ringe kann man sehr günstig kaufen.</p>
<p>Für meine Arbeit als Entwickler, die ich ausschließlich am Mac verrichte, habe ich längere Zeit eine geeignete mechanische Tastatur gesucht. Zum Testen entschied ich mich für ein dasKeyboard Model S Professional for Mac mit MX blue. Leider gibt es dieses Modell nur mit ANSI-Layout, was mich anfangs vom Kauf abgehalten hat und mit dem ich schließlich auch nicht zurechtkam. Der ständige Wechsel bringt einen nur durcheinander und das deutsche Tasten-Mapping (ISO-Layout) mit einem ANSI-Layout zu nutzen klappt auch nicht &ndash; da fehlt schließlich eine Taste.</p>
<p>Die MX blue dagegen haben mich auf Anhieb begeistert. Kurzum: ich habe die Tastatur gegen ein dasKeyboard 4 mit MX blue umgetauscht. Die hat zwar kein Mac-Layout, aber das lässt sich durch den Tausch der Tastenkappen und ein paar Einstellungen in OS X problemlos anpassen. Außerdem funktionieren die Media-Tasten und selbst der Lautstärkeregler ohne jegliche Anpassung mit OS X. Wozu da also noch ein spezielles Mac-Modell?</p>
<p>Parallel ließ mich leider die K70 im Stich. Innerhalb eines halben Jahres gingen drei LEDs der Hintergrundbeleuchtung kaputt. Nach einer Recherche in den Corsair-Foren scheint das ein verbreitetes Problem mit den blauen LEDs (gibt auch rote) bei der K70 zu sein. Corsair hat das Modell zwischenzeitlich vom Markt genommen und wird wohl demnächst eine überarbeitete Version liefern.</p>
<p>Amazon nahm die K70 anstandslos zurück und als Ersatz habe ich mich für ein dasKeyboard 4 mit MX brown entschieden und es bisher nicht bereut.</p>
<p>Zum Abrunden des Portfolios der MX-Schalter, habe ich mir noch als Abwechslung zu den beiden dasKeyboard eine Ducky Shine 3 mit MX black gegönnt. Sie wirkt noch einen Tick solider, hat ein abnehmbares Kabel und zig Beleuchtungsoptionen. Der lineare Gang und höhere Widerstand der Switches ist etwas gewöhnungsbedürftig, aber angenehm, besonders beim Spielen.</p>
<p>Eine weitere Anmerkung zur Lautstärke: die dasKeyboard 4 haben zwischen ihrer Deckplatte aus Aluminium und der Stahlplatte einen sehr festen Schaumstoff, der die Geräuschkulisse dämpft. Der Unterschied zum Vorgängermodell oder auch der Corsair K70 ist ziemlich gewaltig. Sogar die MX blue-Version ist leiser als die K70 samt Gummi-O-Ringen. Die Ducky liegt durch ihre sehr stabile Konstruktion auch recht gut im Vergleich. Dazu tragen aber auch die MX black sicherlich ihren Teil bei.</p>
<p>Generell habe ich mit keiner der Tastaturen eine schlechte Tipp-Erfahrung gemacht. Nur das ANSI-Layout und die defekten LEDs haben mich zu einem Umtausch veranlasst.</p>
<h2 id="fazit"><a href="#fazit" class="heading-anchor">Fazit</a></h2>
<p>Nachdem ich nun in einem halben Jahr drei Hersteller und drei unterschiedliche Schalter-Typen durch habe, kann ich nur sagen, dass mich mechanische Tastaturen begeistern, wenn sie nicht sogar eine Sammlerwut entfacht haben (ich hoffe nicht, das wäre ein teures Hobby).</p>
<p>Der Tipp-Komfort und die Zuverlässigkeit sind es mir aber wert. Schließlich sind die Tastaturen auch maßgeblich daran beteiligt, dass ich überhaupt Geld verdiene. Wenn man die Unterschiede erstmal kennt, möchte man nur ungern zu Rubberdome-Tastaturen zurückkehren. Selbst mein früher geliebtes Apple Keyboard lasse ich für eine mechanische Tastatur links liegen.</p>
<p>Dazu gibt es eine unglaubliche Vielfalt an Individualisierungsmöglichkeiten. Seien es nun Tastenkappen, modifizierte Federn in den Schaltern oder gar leicht verrückte Dinge wie Tastatur-Bausätze, mit denen man wirklich alles bis ins letzte Detail für sich anpassen und austüfteln kann. Interessenten zu diesen Themen sowie Kaufberatung etc. kann ich das Forum <a href="http://geekhack.org/">geekhack</a> ans Herz legen.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Sublime Text 2</title>
      <link>https://webcodr.io/2012/04/sublime-text-2/</link>
      <pubDate>Thu, 05 Apr 2012 00:00:00 +0100</pubDate>
      <guid>https://webcodr.io/2012/04/sublime-text-2/</guid>
      <description>Als Entwickler ist man ja immer auf der Suche nach noch besseren Werkzeugen, um seine Arbeit schneller, besser und schöner zu erledigen. Das wichtigste Tool dafür ist ein guter Editor. Unter OS X setzte ich immer auf TextMate und falls kein Mac zur Verfügung stand, war Notepad++ unter Windows das Mittel der Wahl.
Leider wird TextMate kaum noch weiterentwickelt. Der letzte Release ist Monate her und TextMate 2 grenzt schon fast an Vaporware. Im Büro (sowohl früher als auch jetzt bei Chip) habe ich nun seit über einem halben Jahr auch einen Mac, daher kommt Notepad++ nicht als Alternative in Frage. Diverse Versuche mit Wine bzw. WineBottler haben sich als Schuss in den Ofen erwiesen.
</description>
      <content:encoded><![CDATA[<p>Als Entwickler ist man ja immer auf der Suche nach noch besseren Werkzeugen, um seine Arbeit schneller, besser und schöner zu erledigen. Das wichtigste Tool dafür ist ein guter Editor. Unter OS X setzte ich immer auf <a href="http://macromates.com/">TextMate</a> und falls kein Mac zur Verfügung stand, war <a href="http://notepad-plus-plus.org/">Notepad++</a> unter Windows das Mittel der Wahl.</p>
<p>Leider wird TextMate kaum noch weiterentwickelt. Der letzte Release ist Monate her und TextMate 2 grenzt schon fast an Vaporware. Im Büro (sowohl früher als auch jetzt bei <a href="http://www.chip.de/">Chip</a>) habe ich nun seit über einem halben Jahr auch einen Mac, daher kommt Notepad++ nicht als Alternative in Frage. Diverse Versuche mit Wine bzw. WineBottler haben sich als Schuss in den Ofen erwiesen.</p>
<p>Zu meinem großen Glück bin ich dann zufällig über <a href="http://www.sublimetext.com/2">Sublime Text 2</a> gestolpert. Zuerst dachte ich, es wäre nur ein billiger TextMate-Klon, aber weit gefehlt. Das Ding ist richtig toll.</p>
<h3 id="warum-darum"><a href="#warum-darum" class="heading-anchor">Warum? Darum</a></h3>
<ul>
<li>Läuft unter OS X, Windows und sogar Linux.</li>
<li>Kann von Haus aus eine Menge, ohne überladen zu sein (gutes Syntax-Highlighting, umfangreiche Suchfunktionen, Code-Folding, Code Completion etc.)</li>
<li>Bis ins letzte Detail konfigurierbar (nur über JSON-Files, keine GUI bisher).</li>
<li>Erweiterbar über sog. Packages, die es für so ziemlich alles gibt, von ActionScript über Git bis Zen Coding (ein Großteil der TextMate Bundles ist kompatibel!)</li>
<li>Sehr schnell und keine Probleme mit extrem langen Zeilen (TextMate gerät da teilweise unglaublich ins Stocken bishin zum Absturz).</li>
<li>Tabs (ja, die kann TextMate auch, aber nur innerhalb von Projekten).</li>
<li>Regelmäßige Updates.</li>
</ul>
<p>Wie effizient man mit Sublime Text und ein paar kleinen Tools entwickeln kann, zeigt Andrey Tarantsov in einem sehr schönen <a href="http://tarantsov.com/blog/2012/02/sublime-text-workflow-that-beats-coda-and-espresso/">Video</a>. Da zeigt sich auch mal wieder, dass für Web-Entwickler OS X immer noch die beste Plattform ist — viele Tools gibt es für Windows schlichtweg nicht. Mal davon abgesehen, dass Arbeiten mit einem Terminal immer noch eine Qual ist. <a href="http://www.cygwin.com/">Cygwin</a> ist hier zwar ein Segen, aber auch nicht allmächtig, da es nicht für alles Wichtige kompatible Versionen gibt (Stichwort Ruby Gems …).</p>
<p>Da Sublime Text 2 Shareware ist und beliebig lange getestet werden kann, rate ich jedem Entwickler ihn zumindest auszuprobieren — es lohnt sich. Und wer schon immer einen TextMate-ähnlichen Editor für Windows oder Linux gesucht hat: hier ist er!</p>
]]></content:encoded>
    </item>
    
  </channel>
</rss>
