<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: John Oerter</title>
    <description>The latest articles on Forem by John Oerter (@joerter).</description>
    <link>https://forem.com/joerter</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F290334%2Fb32bff11-634b-448b-ae8f-40712584525b.jpeg</url>
      <title>Forem: John Oerter</title>
      <link>https://forem.com/joerter</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/joerter"/>
    <language>en</language>
    <item>
      <title>2021 Development Environment Review</title>
      <dc:creator>John Oerter</dc:creator>
      <pubDate>Sun, 27 Feb 2022 17:49:35 +0000</pubDate>
      <link>https://forem.com/joerter/2021-development-environment-review-34nl</link>
      <guid>https://forem.com/joerter/2021-development-environment-review-34nl</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;I recently had this idea to write about my current dev environment every year. I thought it would be fun to keep track of how the tools I'm using every day change and evolve over time. And since it's still February 2022, I figure it's not too late for a 2021 recap post.&lt;/p&gt;

&lt;h2&gt;
  
  
  My Tech Stack
&lt;/h2&gt;

&lt;p&gt;This year, I transitioned to full-stack JavaScript / TypeScript development. I spend the majority of my time in Node.js and React projects deployed on serverless AWS. Prior to 2021, I spent more time in the C# / Microsoft ecosystem. C# is an amazing language and Visual Studio is a powerful IDE, but I am very happy with my new JavaScript based tech stack.&lt;/p&gt;

&lt;h2&gt;
  
  
  Desktop - macOS and elementary OS
&lt;/h2&gt;

&lt;p&gt;I currently split time between Linux and macOS. I've been a Linux user for years and have primarily used Ubuntu and other Ubuntu-based distros. I switched to &lt;a href="https://elementary.io/"&gt;elementary OS&lt;/a&gt; earlier this year and have really enjoyed it. Even though I have used Linux for a long time, I don't really enjoy fighting with updates or spending lots of time configuring my desktop environment. Elementary gives me the best out of the box experience I've found on Linux so far. All that being said, my Linux laptop is getting old, and I'm planning on buying a MacBook to replace it. I've been eyeing the M1 for awhile, and I think it's the best choice for me right now. If &lt;a href="https://system76.com/"&gt;System 76&lt;/a&gt; ever releases a laptop made in house like the &lt;a href="https://system76.com/desktops/thelio-major"&gt;Thelio&lt;/a&gt; or &lt;a href="https://system76.com/accessories/launch"&gt;Launch Keyboard&lt;/a&gt;, I will definitely check it out. &lt;/p&gt;

&lt;h2&gt;
  
  
  Editor - NeoVim
&lt;/h2&gt;

&lt;p&gt;My VIM setup with &lt;a href="https://neovim.io/"&gt;Neovim&lt;/a&gt; has never been better. I've gone back and forth on using VsCode, Emacs, and JetBrains IDEs instead of VIM in the past, but I keep coming back. Almost every editor these days has VIM emulation, but at the end of the day &lt;strong&gt;only VIM is VIM&lt;/strong&gt;. What I mean by that is even the best VIM emulator running in another editor falls short of the real thing in some way. I made a real effort to switch to Emacs at the end of 2021 by following &lt;a href="https://www.youtube.com/c/SystemCrafters"&gt;System Crafters&lt;/a&gt; Emacs from Scratch series. The videos were really excellent and I learned a lot, but in the end, I couldn't quite get over the performance issues with Emacs and switched back to Neovim. I fully expect to maybe flop back and forth on this position in the future, so I'm very curious to see where I'm at a year from now.&lt;/p&gt;

&lt;p&gt;Luckily, there is a lot of development going on in the Neovim ecosystem and many great plugins are taking advantage of the new Lua integration. I can now easily have an LSP configuration that gives great autocomplete similar to VsCode. Here are a few of my favorite plugins:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/glepnir/lspsaga.nvim"&gt;lspsaga&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/nvim-telescope/telescope.nvim"&gt;nvim-telescope&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/kyazdani42/nvim-tree.lua"&gt;nvim-tree&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/folke/trouble.nvim"&gt;trouble.nvim&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/tpope/vim-fugitive"&gt;vim-fugitive&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/nvim-lualine/lualine.nvim"&gt;lualine.nvim&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/akinsho/bufferline.nvim"&gt;bufferline.nvim&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here's a screenshot of my current Neovim session:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--X9GIc7SD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dgkqt9x4c0rvpix1t6e1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--X9GIc7SD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dgkqt9x4c0rvpix1t6e1.png" alt="nvim.png" width="880" height="469"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I'm using the &lt;a href="https://draculatheme.com/"&gt;Dracula&lt;/a&gt; colorscheme everywhere I can.&lt;/p&gt;

&lt;h2&gt;
  
  
  Terminal - Alacritty, tmux, and zsh
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/alacritty/alacritty"&gt;Alacritty&lt;/a&gt; has been my terminal emulator of choice this year. It's easy to configure using yml files so I can share my configuration between machines. Tmux is a vital piece of my workflow for organizing my sessions and windows. &lt;/p&gt;

&lt;p&gt;Zsh along with &lt;a href="https://ohmyz.sh/"&gt;Oh My Zsh&lt;/a&gt; has been my shell for years now. I make heavy use of the &lt;a href="https://github.com/evanthegrayt/cdc"&gt;cdc&lt;/a&gt; and &lt;a href="https://github.com/zsh-users/zsh-autosuggestions"&gt;zsh-autosuggestions&lt;/a&gt; for moving between repos.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/joerter/dotfiles"&gt;Link to my dotfiles repo on GitHub&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
    </item>
    <item>
      <title>Message in a Bottle - A Simple Clojure App</title>
      <dc:creator>John Oerter</dc:creator>
      <pubDate>Thu, 10 Dec 2020 03:16:14 +0000</pubDate>
      <link>https://forem.com/joerter/message-in-a-bottle-a-simple-clojure-app-54ei</link>
      <guid>https://forem.com/joerter/message-in-a-bottle-a-simple-clojure-app-54ei</guid>
      <description>&lt;h2&gt;
  
  
  The Social Network for Deserted Islanders
&lt;/h2&gt;

&lt;p&gt;I've been spending time learning Clojure lately, and I wanted to build a super simple web application to put my learning to use. Message in a Bottle is a fake social network for people stranded on deserted islands. It allows them to read and send messages to other stranded people. Messages are at the mercy of the wind and waves so you'll never know who will get your message or what you will receive. But that's part of the fun!&lt;/p&gt;

&lt;p&gt;People stranded on deserted islands aren't lucky enough to have access to the social networks you and I use and enjoy every day. How can they waste hours of their day scrolling through timelines or experience extreme jealousy at that new rainwater collector their friend built? Message in a Bottle is the answer.&lt;/p&gt;

&lt;p&gt;In this post, I'll dive into how I built the app and what I learned. If you'd like to check out the app, visit &lt;a href="https://message-in-a-bottle-1.herokuapp.com/"&gt;https://message-in-a-bottle-1.herokuapp.com/&lt;/a&gt;. My apologies if the performance is slow or the app takes a minute to respond. I'm using the Free level of Heroku which sleeps after 30 minutes of inactivity. Feel free to read and write a few messages! I need to find a way to increase the daily active users of Message in a Bottle before the IPO... 😆&lt;/p&gt;

&lt;p&gt;You can find the source code &lt;a href="https://github.com/joerter/message-in-a-bottle"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Overview
&lt;/h2&gt;

&lt;p&gt;In order to keep Message in a Bottle simple, I decided to use an MVC-style approach with no client-side code. That way, I could just focus on a simple request-response cycle with a simple form and data store for persisting the messages. Since the messages aren't relational in any way, I decided to persist them using Redis. I've used Redis in the past with JavaScript and C# and generally find it to be a joy to use.&lt;/p&gt;

&lt;p&gt;Here's a quick list of the main tools I used:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://leiningen.org/"&gt;Leiningen&lt;/a&gt; - Leiningen is the main build and dependency manager in Clojure. Think of it as a bit like NPM if you're coming from JavaScript land.&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://github.com/ring-clojure/ring"&gt;Ring&lt;/a&gt; - HTTP web stack&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://github.com/weavejester/compojure"&gt;Compojure&lt;/a&gt; - Routing library for Ring.&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://github.com/weavejester/hiccup"&gt;Hiccup&lt;/a&gt; - Write HTML in Clojure!&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://github.com/weavejester/environ"&gt;Environ&lt;/a&gt; - For managing environment variables.&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://github.com/ptaoussanis/carmine"&gt;Carmine&lt;/a&gt; - Clojure Redis client&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://redis.io/"&gt;Redis&lt;/a&gt; - Message persisitance&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://www.docker.com/"&gt;Docker and Docker Compose&lt;/a&gt; - Local development&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://heroku.com"&gt;Heroku&lt;/a&gt; - Deployment and hosting&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Routing and Handling Requests
&lt;/h2&gt;

&lt;p&gt;I used the Compojure Leiningen template to scaffold the app with &lt;code&gt;lein new compojure&lt;/code&gt;. That template starts you off with a &lt;code&gt;handler.clj&lt;/code&gt; file that contains a sample route and app setup with the default settings. Here's how my routes ended up at the end:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;defroutes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;app-routes&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;GET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;handlers/home&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;GET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"/read-message"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;handlers/read-message&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;GET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"/send-message"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;handlers/send-message&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;POST&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"/send-message"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;handlers/sent-message&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;route/resources&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;route/not-found&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"Not Found"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each HTTP method function from Compojure takes a string for the route url along with a function to run for the response. I chose to set up these functions in a &lt;code&gt;handlers.clj&lt;/code&gt; file. I'm not sure if that's idiomatic Clojure or not since they are essentially controllers, but that's how I did it. I would love to hear any stylistic improvements or suggestions anyone has here.&lt;/p&gt;

&lt;p&gt;Take a closer look at the &lt;code&gt;(POST "/send-message" [message] (handlers/sent-message message))&lt;/code&gt; form. The &lt;code&gt;[message]&lt;/code&gt; argument is the value of the message textbox POSTed to the server from the web browser. It is passed on as an argument to the &lt;code&gt;handlers/sent-message&lt;/code&gt; function.&lt;/p&gt;

&lt;p&gt;This is one of the reasons I really enjoy writing Clojure. This code is highly readable and low-ceremony. If I compare this to C# and ASP.NET Core, which is where I spend most of my time writing web applications, I notice the lack of syntax, keywords (public, class, namespace, etc.), and type declarations. We can debate the merits of statically vs. dynamically typed languages, but there's no denying that Clojure is a simple and beautiful language to read.&lt;/p&gt;

&lt;h2&gt;
  
  
  Writing HTML with Hiccup
&lt;/h2&gt;

&lt;p&gt;Using Hiccup to write HTML in Clojure is a joy as well. The idea is to use vectors for elements, and maps for attributes. Here's an example of the form to send a message:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;defn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;send-message&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;validation-message&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;layouts/default&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"Send Message"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;:p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"Write your message below. Unfortunately, the paper can only hold 250 characters."&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;nil?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;validation-message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;:span&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;:p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;validation-message&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;hf/form-to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;:post&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"/send-message"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;:textarea&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"message"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:autofocus&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:rows&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"10"&lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;:input&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"Send"&lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;rf/anti-forgery-field&lt;/span&gt;&lt;span class="p"&gt;))))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this function, I'm using a &lt;code&gt;layouts/default&lt;/code&gt; function I created as well. This function adds in some default HTML I wanted to have on every page like CSS, a page title, and simple app header.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;hf/form-to&lt;/code&gt; is a hiccup defined function that creates a form with an action on submission. Inside the form, I've added a simple &lt;code&gt;textarea&lt;/code&gt; element along with a submit button.&lt;/p&gt;

&lt;h2&gt;
  
  
  Storing Messages with Redis and Carmine
&lt;/h2&gt;

&lt;p&gt;Let's get to the good stuff!&lt;/p&gt;

&lt;p&gt;My basic idea for storing and reading the messages using Redis was to store each message using a random UUID as the key. Then, I could use Redis' &lt;code&gt;RANDOMKEY&lt;/code&gt; command to easily get a random message every time a user wants to read a new message.&lt;/p&gt;

&lt;p&gt;Carmine, the Clojure Redis client I used, gives an example of a &lt;code&gt;wcar*&lt;/code&gt; macro to use when issuing commands to Redis. I'm still learning about Clojure macros, but this one seems pretty simple. Here's the definition:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;defmacro&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;wcar*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;car/wcar&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;server1-conn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;~@&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This saves me from having to reference the &lt;code&gt;server1-conn&lt;/code&gt; definition every time I use a command. Therefore, saving a message is as easy as calling &lt;code&gt;SET&lt;/code&gt; with a UUID:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;defn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;save-message&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;wcar*&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;car/set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Where &lt;code&gt;uuid&lt;/code&gt; is a function that returns the unique string.&lt;/p&gt;

&lt;p&gt;Then, to read out a message I just need to get a random key from Redis:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;defn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;random-key&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;wcar*&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;car/randomkey&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And use that random key with the &lt;code&gt;GET&lt;/code&gt; command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;defn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;get-message&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;wcar*&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;car/get&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;random-key&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Easy peasy!&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrap Up
&lt;/h2&gt;

&lt;p&gt;I learned quite a bit with this project. It was a challenge to get started, but I'm glad I picked something simple enough to finish quickly. Next, I'm going to focus on some front-end ClojureScript development by working through the &lt;a href="https://eugenkiss.github.io/7guis/"&gt;https://eugenkiss.github.io/7guis/&lt;/a&gt; project.&lt;/p&gt;

</description>
      <category>clojure</category>
    </item>
    <item>
      <title>Vim and Vim Emulators</title>
      <dc:creator>John Oerter</dc:creator>
      <pubDate>Thu, 19 Nov 2020 03:13:00 +0000</pubDate>
      <link>https://forem.com/joerter/vim-and-vim-emulators-bb9</link>
      <guid>https://forem.com/joerter/vim-and-vim-emulators-bb9</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;I recently scored a license to the &lt;a href="https://www.jetbrains.com/rider/"&gt;Rider IDE&lt;/a&gt; from JetBrains through work. I've been a Resharper user for years, but this is the first time I've used a full JetBrains IDE. I have to say that I'm really enjoying it. This is also my first experience with JetBrains' Vim emulator, &lt;a href="https://plugins.jetbrains.com/plugin/164-ideavim"&gt;IdeaVim&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I've been a Vim user since being required to use it in my intro to programming course in college. Like many Vim users, I've gone back and forth between using and believing in a pure Vim setup, and using the Vim emulators that are available for pretty much every IDE and editor.&lt;/p&gt;

&lt;p&gt;Today, I believe I have settled on using Vim emulators. Here's why:&lt;/p&gt;

&lt;h2&gt;
  
  
  IDE-like Vim Configuration Is Hard
&lt;/h2&gt;

&lt;p&gt;I've spent a good chunk of time fine-tuning my &lt;a href="https://github.com/joerter/vim"&gt;.vimrc&lt;/a&gt;, but there have always been a few features that seem just out of my reach to get working perfectly. Auto-completion is a perfect example. I've tried &lt;a href="https://github.com/neoclide/coc.nvim"&gt;coc.nvim&lt;/a&gt; and others, but I still can't seem to achieve the level of auto completion that comes out of the box in VSCode, Visual Studio, or the JetBrains products.&lt;/p&gt;

&lt;p&gt;This isn't because these Vim plugins are buggy or low quality, it's just that the amount of work it takes to install the plugins, learn how to use them effectively, and maintain them across updates is really hard to stomach when I can download any of the IDEs I mentioned earlier and get this functionality working almost perfectly without any extra work.&lt;/p&gt;

&lt;p&gt;It's the struggle between taking the time build a setup that is made specifically for my needs and tastes versus accepting an environment that may not check all the boxes, but allows me to be productive from day one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Vim Emulators Are Good and Getting Better
&lt;/h2&gt;

&lt;p&gt;The three main Vim emulators I've used are &lt;a href="https://github.com/VsVim/VsVim"&gt;VsVim for Visual Studio&lt;/a&gt;, &lt;a href="https://marketplace.visualstudio.com/items?itemName=vscodevim.vim"&gt;VSCodeVim&lt;/a&gt;, and &lt;a href="https://plugins.jetbrains.com/plugin/164-ideavim"&gt;IdeaVim&lt;/a&gt;. I've had generally good experiences with all of them, and they can all effectively emulate the main features of Vim that I find useful. As long as I can use the standard motions and keybindings and create some simple &lt;code&gt;imap&lt;/code&gt; and &lt;code&gt;nmap&lt;/code&gt; rules, I'm happy. If the emulator supports macros and relative line numbers that's even better.&lt;/p&gt;

&lt;p&gt;One of the most important features to me is the ability to switch from INSERT mode to NORMAL mode easily by typing "jk". I made the switch to this a long time ago to save myself the time of reaching for the ESCAPE key or using the CTRL-[ shortcut. I would suspect this is a difficult effect to achieve in an editor that doesn't support modal editing natively, but all the emulators above are able to mimic this flawlessly.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--40clYbSz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://redgreenrefactor.dev/vim-and-vim-emulators/vim.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--40clYbSz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://redgreenrefactor.dev/vim-and-vim-emulators/vim.gif" alt="vim.gif" width="813" height="551"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;I still see myself dropping into Vim if I need to quickly edit a file, but I believe the days of making constant tweaks to my .vimrc are over. Vim (including emulators) continues to be highly relevant to today's developers, and offers a substantial productivity boost to those that take the time to learn to use it effectively. If you're interested in taking the plunge to learn Vim, I would recommend checking out &lt;a href="https://learnvimscriptthehardway.stevelosh.com/"&gt;Learn Vimscript the Hard Way&lt;/a&gt; and &lt;a href="http://vimcasts.org/"&gt;Vimcasts&lt;/a&gt;. However, I think the best way is the old fashioned one of starting up &lt;a href="https://linux.die.net/man/1/vimtutor"&gt;Vim Tutor&lt;/a&gt; and practicing regularly with code katas until the keybindings become second nature.&lt;/p&gt;

</description>
      <category>vim</category>
    </item>
    <item>
      <title>10 Tips for Awesome Angular Apps</title>
      <dc:creator>John Oerter</dc:creator>
      <pubDate>Sun, 08 Nov 2020 23:32:56 +0000</pubDate>
      <link>https://forem.com/joerter/10-tips-for-awesome-angular-apps-a2b</link>
      <guid>https://forem.com/joerter/10-tips-for-awesome-angular-apps-a2b</guid>
      <description>&lt;p&gt;This article started out as an explanation of my approach to handling state management in Angular apps. Instead, it's turned into a list of lessons I've learned while using Angular for around 3 years. I hope you find a point or two useful or at least find one of the articles I've linked to informative and a good jumping off point for your own exploration and learning. Enjoy!&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;When it comes to state management in Angular apps, there are plenty libraries to choose from. A few examples are &lt;a href="https://ngrx.io/"&gt;NGRX&lt;/a&gt;,&lt;br&gt;
&lt;a href="https://datorama.github.io/akita/"&gt;Akita&lt;/a&gt;, and &lt;a href="https://www.ngxs.io/"&gt;NGXS&lt;/a&gt;.&lt;br&gt;
You can even use libraries more popular in the React ecosystem like &lt;a href="https://redux.js.org/"&gt;Redux&lt;/a&gt; and &lt;a href="https://mobx.js.org/README.html"&gt;Mobx&lt;/a&gt;. In my experience, these libraries add boilerplate and knowledge overhead and you're usually better off using vanilla Angular with @Input and @Output properties and services. &lt;a href="https://medium.com/@dan_abramov/you-might-not-need-redux-be46360cf367"&gt;You Might Not Need Redux&lt;/a&gt; is a great article about this topic from the React perspective, but I think the same principles apply to Angular.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;"Prop drilling" is the problem where you need to pass @Input or @Output properties through multiple layers in the component tree. I recommend utilizing a service to manage state when passing data through 3 or more layers of components. You can even use &lt;a href="https://angular.io/guide/hierarchical-dependency-injection"&gt;hierarchical dependency injection&lt;/a&gt; to make services visible only to a certain component tree instead of global to the entire application.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Composition_over_inheritance"&gt;Favor composition over inheritance&lt;/a&gt;. Since Angular components use TypeScript classes, it can be tempting to reach for inheritance to share common functionality. In my experience, this leads to a rigid architecture that is difficult to debug and follow. Compose components, refactor shared functionality into services, or use shared directives instead.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://angular.io/guide/dynamic-component-loader"&gt;Dynamic component loading&lt;/a&gt; is possible in Angular, but almost never useful at the application level. I can see its uses in libraries, but for applications, I've never seen a problem solved with dynamic components that couldn't have been solved more easily with a simple &lt;code&gt;*ngFor&lt;/code&gt; or &lt;code&gt;*ngIf&lt;/code&gt; directive.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use the OnPush Change Detection Strategy. This results in increased performance, but that's not the main reason I recommend it. OnPush gives you more control over when change detection runs and forces good practices when it comes to immutability and changing @Input properties. Netanel Basal has a fantastic article about OnPush &lt;a href="https://netbasal.com/a-comprehensive-guide-to-angular-onpush-change-detection-strategy-5bac493074a4"&gt;here&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use the &lt;a href="https://angular.io/api/common/AsyncPipe"&gt;async pipe&lt;/a&gt;. Subscribing to streams in components can cause memory leaks if not unsubscribed during the &lt;code&gt;OnDestroy&lt;/code&gt; lifecycle method. Instead, let the async pipe handle this for you. It runs change detection when using OnPush Change Detection too!&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;For DTOs and communicating with your backend, favor interfaces over classes. The simple reason is that TypeScript interfaces only exist at compile time and are not present at runtime. Classes, on the other hand, are bundled with the application and can cause unnecessary weight if you're only using them as a data structure.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Strive for immutability in your applications. You may find success using a library like &lt;a href="https://immutable-js.github.io/immutable-js/docs/#/"&gt;Immutable.js&lt;/a&gt; to force immutability, but I've found that using OnPush change detection and having a good code review process can be just as good without the 3rd party library overhead. This can really be as simple as using &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax"&gt;spread syntax&lt;/a&gt; and reassigning to array and object fields in components.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use &lt;a href="https://github.com/ngneat/spectator"&gt;Spectator&lt;/a&gt; for your unit tests. This library is awesome. When I first started using Angular, I found the TestBed and built in testing tools so cumbersome I favored writing &lt;a href="https://angular.io/guide/testing-components-basics#component-class-testing"&gt;class based tests for every component&lt;/a&gt;. With Spectator, tests are a breeze to setup and it helps you write better tests. It does this by emulating the same selectors used by the &lt;a href="https://testing-library.com/"&gt;Testing Library&lt;/a&gt; family.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Don't test implementation details of your components. Another way of saying this is that you shouldn't have a test file for every single one of your components, directives, or services. Instead, test the &lt;strong&gt;behavior&lt;/strong&gt; of your application like a user would at a higher level in the component tree. In the OOP world, Uncle Bob calls this &lt;a href="https://blog.cleancoder.com/uncle-bob/2017/10/03/TestContravariance.html"&gt;Test Contra-variance&lt;/a&gt;. By following this, you will end up with tests that may exercise the functionality of multiple components at once. This leads to tests that are far more valuable and less prone to breaking due to minor refactors in component structure.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Thanks for reading! Let me know if you've found this article helpful or disagree with any of these points.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally posted at &lt;a href="https://redgreenrefactor.dev/posts/ten-tips-for-awesome-angular-apps"&gt;https://redgreenrefactor.dev/posts/ten-tips-for-awesome-angular-apps&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>angular</category>
    </item>
    <item>
      <title>Gear for a quick and effective standing desk</title>
      <dc:creator>John Oerter</dc:creator>
      <pubDate>Tue, 17 Mar 2020 15:39:41 +0000</pubDate>
      <link>https://forem.com/joerter/gear-for-a-quick-and-effective-standing-desk-114b</link>
      <guid>https://forem.com/joerter/gear-for-a-quick-and-effective-standing-desk-114b</guid>
      <description>&lt;p&gt;Today, I'd like to spread the word about two products that have significantly improved my work from home situation during this COVID-19 outbreak. If you're like me and don't have a furnished home office already, I hope you check these out and find them useful. The two products are the &lt;a href="https://amzn.to/33oj7tT"&gt;Roost Stand&lt;/a&gt; and the &lt;a href="https://amzn.to/3d7vvTC"&gt;GhostStand desk&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://amzn.to/33oj7tT"&gt;Roost Stand&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;I am seriously impressed with this stand. When I was in the market for a laptop stand, I was looking for 3 things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Wide compatibility with different laptop sizes and models&lt;/li&gt;
&lt;li&gt;Portability&lt;/li&gt;
&lt;li&gt;Overall quality&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For me, the Roost Stand hits all three marks. It's light yet sturdy. I can easily carry it with me to coffee shops, and my laptop feels extremely secure when it's resting on the stand. &lt;/p&gt;

&lt;p&gt;If you don't already have a laptop stand to put your laptop at an ergonomic height, I highly recommend the Roost Stand.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://amzn.to/3d7vvTC"&gt;Ghost Desk&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;You might be wondering why I'm recommending what essentially looks like a cardboard box. While it might seem silly, this desk does a pretty good job of making a workable standing desk if you don't have an alternative. You could cobble together some surfaces from around your house and accomplish the same thing, but it's harder than you'd think to get the right stair step height for keyboard and mouse placement lower than the monitor placement. For me, I've also found the portability aspect of this product to be a huge advantage over alternatives. It's also surprisingly sturdy for cardboard. I've been resting my laptop with the Rooststand on top and don't have any worries about the whole stand collapsing.&lt;/p&gt;

&lt;p&gt;That's it! I hope you find these products helpful. I'd love to hear and see other improved work from home desk areas in the comments.&lt;/p&gt;

</description>
      <category>productivity</category>
    </item>
    <item>
      <title>Integration Test Entropy</title>
      <dc:creator>John Oerter</dc:creator>
      <pubDate>Wed, 19 Feb 2020 04:23:40 +0000</pubDate>
      <link>https://forem.com/joerter/integration-test-entropy-534b</link>
      <guid>https://forem.com/joerter/integration-test-entropy-534b</guid>
      <description>&lt;h2&gt;
  
  
  What is Entropy?
&lt;/h2&gt;

&lt;p&gt;According to the Oxford Dictionary, entropy can be defined as:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;gradual decline into disorder&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;When I think about integration or end-to-end tests I've encountered in my&lt;br&gt;
career, entropy definitely comes to mind. I have written and encountered&lt;br&gt;
integration tests that were written when the project was under active&lt;br&gt;
development, but became more and more brittle and lost value as time went on. As a result, developers begin skipping them in CI builds and soon neglect them altogether. In this article, I want to talk about the two main reasons I believe this entropy occurs and what can be done to make sure integration tests thrive and provide value throughout the lifespan of a project.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: Integration tests could have many different meanings to different&lt;br&gt;
developers. For the purposes of this article I'm referring specifically to end to end tests that either test a UI (Selenium, Cypress, etc.) or test the data returned by a REST API.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Data Reliance
&lt;/h2&gt;

&lt;p&gt;The most common reason for brittle integration tests I've seen is a reliance on data. I do believe that end-to-end tests should manipulate data all the way to the data store in order to assure stakeholders that the application is working properly. However, these tests shouldn't assume that the data will always and forever be in the correct state for an accurate run of the test. Data change is inevitable and no one wants to waste hours trying to diagnose a failing test because of a change in data.&lt;/p&gt;

&lt;p&gt;There are several ways to mitigate this risk. The easiest would be to write setup and tear down code for integration tests that ensure that data is in the right state before and after the run. Of course, if integration tests can be written in a way that they are not reliant on any specific data this is even better. A more complicated solution could be to utilize a Docker container that contains known data specifically for integration tests.&lt;/p&gt;

&lt;h2&gt;
  
  
  Business Requirements
&lt;/h2&gt;

&lt;p&gt;In my opinion, every integration test should be tied to a business requirement and this link should be immediately obvious to anyone who encounters the test. Unfortunately, this doesn't always happen. Tests that make an HTTP request to an API endpoint and assert against data or tests that look for a specific element to appear on a UI don't necessarily meet this need. When the test inevitably breaks for a developer unfamiliar with the original requirements, the test should make its value clear. Otherwise, it's all to easy to decide the test isn't valuable anymore and delete it.&lt;/p&gt;

&lt;p&gt;My favorite method for linking tests to actual business requirements is to use Behavior Driven Development. You may be familiar with this concept as BDD, &lt;a href="https://cucumber.io/"&gt;Cucumber&lt;/a&gt;, or Gherkin, but the idea is the same. If integration tests can be written in a &lt;em&gt;behavior&lt;/em&gt; oriented fashion that business owners can easily understand and verify, the result is a huge win for the project.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally posted on &lt;a href="https://redgreenrefactor.dev/integration-test-entropy/"&gt;redgreenrefactor.dev&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>testing</category>
    </item>
    <item>
      <title>Learning to Love Testing Library</title>
      <dc:creator>John Oerter</dc:creator>
      <pubDate>Wed, 12 Feb 2020 04:00:49 +0000</pubDate>
      <link>https://forem.com/joerter/learning-to-love-testing-library-3fhd</link>
      <guid>https://forem.com/joerter/learning-to-love-testing-library-3fhd</guid>
      <description>&lt;p&gt;When I first started using Angular, I found the built in testing tools awkward to use and slow to run. In order to write unit tests and get into a TDD flow, I turned to &lt;a href="https://angular.io/guide/testing#component-class-testing"&gt;isolated class tests&lt;/a&gt;. I really enjoyed this technique&lt;br&gt;
because it let me write tests for Angular components in the same fashion that I would write tests for C# classes. I even made a &lt;a href="https://medium.com/@john_oerter/simple-typescript-stubs-5bc9fdf0b808"&gt;simple function&lt;/a&gt; to create typed stubs of dependencies to inject into tested classes.&lt;/p&gt;

&lt;p&gt;This method worked, but I've now learned that there's a better way. I've been playing with &lt;a href="https://testing-library.com/docs/react-testing-library/intro"&gt;angular-testing-library&lt;/a&gt; and &lt;a href="https://testing-library.com/docs/angular-testing-library/intro"&gt;react-testing-library&lt;/a&gt; recently, and they've completely changed the way I think about UI tests. If you're not familiar, these libraries are a part of a family of libraries built for writing maintainable tests in several different JavaScript libraries. This can be explained by one of the guiding principles&lt;br&gt;
of Testing Library:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The more your tests resemble the way your software is used, the more confidence they can give you.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This means that all the implementations of Testing Library only expose ways to assert against the DOM. In &lt;code&gt;angular-testing-library&lt;/code&gt; for example, there is no way to assert against properties or methods on the component itself. You must query the DOM in the way a user would interact with your application.&lt;/p&gt;

&lt;p&gt;My first reaction to this philosophy was a negative one. I thought that this was too limiting, and would make writing unit tests very difficult.&lt;br&gt;
But I was very wrong! I've been using Testing Library more and more and I've found that the guiding principle is 100% correct. But it also has me&lt;br&gt;
wondering, are tests writtien with Testing Library Unit tests or Integration tests?&lt;/p&gt;

&lt;p&gt;At first, I thought of them as integration tests because of two reasons:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Tests written with Testing Library interact with apps in the way a user would - through the DOM. This style is often associated with other
end-to-end test frameworks like Cypress or Selenium.&lt;/li&gt;
&lt;li&gt;I find myself testing features of an app that may involve a parent and many child components instead of writing 1 to 1 tests for each component.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The more I think about it, however, I'm not sure this distinction really matters and I'm comfortable with either classification.&lt;/p&gt;

&lt;p&gt;Going back to #1 above, the DOM really is the public API of my UI components just like the public properties and methods are the public API of classes and interfaces in C#. Therefore, it makes sense to test UI components only through the DOM and not through the "implementation details" of their component properties, even if these properties are accessible "in code".&lt;/p&gt;

&lt;p&gt;For #2, this is a pattern that I'm adopting more and more for C# as well. Unit tests don't have to be - and probably shouldn't be - written&lt;br&gt;
1 to 1 for classes. Instead, I've begun writing tests for a top level class that may depend on other helper classes whose functionality is tested through the public API of the top level class. This leads to far less mocking and more maintainable tests.&lt;/p&gt;

&lt;p&gt;This is how Testing Library has changed the way I think about testing for the better. If you haven't tried it out yet, you should check it out in&lt;br&gt;
your framework of choice! There are flavors for React, Angular, Svelte, and more.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally posted on &lt;a href="https://redgreenrefactor.dev/learning-to-love-testing-library/"&gt;redgreenrefactor.dev&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>testing</category>
      <category>javascript</category>
      <category>react</category>
      <category>angular</category>
    </item>
    <item>
      <title>Bowling Game Kata in JavaScript</title>
      <dc:creator>John Oerter</dc:creator>
      <pubDate>Tue, 24 Dec 2019 14:27:23 +0000</pubDate>
      <link>https://forem.com/joerter/bowling-game-kata-in-javascript-gi6</link>
      <guid>https://forem.com/joerter/bowling-game-kata-in-javascript-gi6</guid>
      <description>&lt;p&gt;I created a video showing the Bowling Game Kata in JavaScript. This is a kata originally created by Uncle Bob Martin. I wanted to show the kata in JavaScript. This is a great kata to do when learning TDD, a new language, or practicing using your editor more efficiently. Thanks for watching!&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/brahHchaegc"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>tdd</category>
      <category>kata</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Do you use Bootstrap?</title>
      <dc:creator>John Oerter</dc:creator>
      <pubDate>Thu, 12 Dec 2019 19:06:38 +0000</pubDate>
      <link>https://forem.com/joerter/do-you-use-bootstrap-1goi</link>
      <guid>https://forem.com/joerter/do-you-use-bootstrap-1goi</guid>
      <description>&lt;p&gt;Not long ago, it felt like every site and app in the world was built on top of &lt;a href="https://getbootstrap.com/"&gt;Bootstrap&lt;/a&gt;. Now, it feels like there are a lot of other great options and even though Bootstrap is still very popular, I feel like new projects aren't using it as much. I'm curious if you're still using the framework - especially in a newer project and your reasons for or against Bootstrap usage.&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>css</category>
      <category>html</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Correctness vs. Behavior</title>
      <dc:creator>John Oerter</dc:creator>
      <pubDate>Wed, 11 Dec 2019 16:38:20 +0000</pubDate>
      <link>https://forem.com/joerter/correctness-vs-behavior-ai9</link>
      <guid>https://forem.com/joerter/correctness-vs-behavior-ai9</guid>
      <description>&lt;p&gt;I recently read &lt;a href="https://blog.cleancoder.com/uncle-bob/2019/06/08/TestsAndTypes.html"&gt;this excellent blog post&lt;/a&gt; by Bob Martin about an interesting&lt;br&gt;
debate he had on Twitter with Mark Seeman. The debate centered around&lt;br&gt;
testing in static vs. dynamically typed languages. Uncle Bob made the assertion&lt;br&gt;
that using a statically typed language does not reduce the number of tests&lt;br&gt;
one needs to write because one must still execute the tests to prove that&lt;br&gt;
the system has the correct &lt;strong&gt;behavior&lt;/strong&gt;. Mark Seeman made the point via one of&lt;br&gt;
his past blog posts that languages like Haskell that don't have nulls eliminate a&lt;br&gt;
whole class of tests one would need to write in a dynamically typed language or one that allows nulls.&lt;/p&gt;

&lt;p&gt;In his article, Martin runs through the same problem that Seeman solves in his blog using&lt;br&gt;
Clojure, a LISP-style dynamic functional language.&lt;/p&gt;

&lt;p&gt;Near the end of the article, Uncle Bob makes the following statement:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This is the crux of the argument between Mark and I. I claim that the number&lt;br&gt;
of tests required are only those tests that are necessary to describe the correct&lt;br&gt;
behavior of the system. If the behavior of each element of the system is correct,&lt;br&gt;
then no element of the system will pass invalid arguments to any other.&lt;br&gt;
Invalid states will be unrepresented.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I was so happy when I read this because it made an idea clear in my head that&lt;br&gt;
I've been feeling for years, but didn't have the words to express. I now call it&lt;br&gt;
&lt;strong&gt;Correctness vs. Behavior&lt;/strong&gt;. I've felt that some developers approach tests in a&lt;br&gt;
similar fashion as Mark Seeman, and feel they need to prove the "correctness" of&lt;br&gt;
their systems by testing that it correctly handles every possible input.&lt;br&gt;
This is why they often prefer statically typed languages. To varying degrees,&lt;br&gt;
these languages are able to guarantee some kind of safety and eliminate&lt;br&gt;
the need for some kinds of tests.&lt;/p&gt;

&lt;p&gt;I agree more with Bob Martin's line of thinking. If the whole system is well tested,&lt;br&gt;
why should I feel the need to write tests for states that are never going to happen?&lt;br&gt;
I prefer to focus on the &lt;strong&gt;behavior&lt;/strong&gt; of the area of code I'm testing.&lt;br&gt;
In this way, the difference between statically and dynamically typed languages doesn't matter much&lt;br&gt;
at all to me.&lt;/p&gt;

&lt;p&gt;I wonder if this different way of thinking is something that turns developers off from TDD.&lt;br&gt;
I wonder if developers that feel they need to cover every invalid argument or state in&lt;br&gt;
their system don't see the benefits of driving the correct behavior of a system with tests.&lt;br&gt;
This mentality could be why many developers prefer to write their production code first and&lt;br&gt;
then use tests to prove &lt;strong&gt;correctness&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This article is not meant to spark debate about which way of thinking is better or more effective.&lt;br&gt;
I have simply found joy in being able to finally express this dichotomy and expand on it here.&lt;/p&gt;

</description>
      <category>tdd</category>
      <category>testing</category>
    </item>
    <item>
      <title>Introduction to Code Katas</title>
      <dc:creator>John Oerter</dc:creator>
      <pubDate>Wed, 11 Dec 2019 16:37:18 +0000</pubDate>
      <link>https://forem.com/joerter/introduction-to-code-katas-200e</link>
      <guid>https://forem.com/joerter/introduction-to-code-katas-200e</guid>
      <description>&lt;h2&gt;
  
  
  What Are Code Katas?
&lt;/h2&gt;

&lt;p&gt;In the software development world, code katas are commonly used by developers&lt;br&gt;
to hone their skill. They are meant to create a safe environment to experiment&lt;br&gt;
and learn new techniques. The word "kata" is borrowed from the world of martial&lt;br&gt;
arts.&lt;/p&gt;

&lt;p&gt;In that world, katas are a series of choreographed movements meant to&lt;br&gt;
be memorized and practiced over and over again until they are perfect. Similarly,&lt;br&gt;
code katas are meant to be practiced regularly, making small improvements each&lt;br&gt;
time. Code katas are usually performed using Test Driven Development.&lt;/p&gt;

&lt;p&gt;When a martial arts practitioner masters the movements of a kata, the idea&lt;br&gt;
is that he or she will be able to perform the same movements perfectly&lt;br&gt;
in the real world without hesitation. The same idea holds for code katas.&lt;br&gt;
The TDD flow of a kata along with its refactorings are memorized so that a&lt;br&gt;
developer can perform similar refactorings and patterns in production code.&lt;/p&gt;

&lt;p&gt;The point of a code kata is not to figure out a solution to a problem as quickly as&lt;br&gt;
possible. Rather, the point is to intentionally practice the fundamentals of&lt;br&gt;
writing code with TDD and using your chosen editor efficiently. Each time&lt;br&gt;
a code kata is performed, small improvements should be made. These&lt;br&gt;
improvements and gained efficiencies will be transferred into production code.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Do You Do a Code Kata?
&lt;/h2&gt;

&lt;p&gt;Getting started is easy!&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;First, choose a problem or create your own.&lt;br&gt;
There are numerous katas out there that other developers have created. Some&lt;br&gt;
of the most popular are the &lt;a href="http://butunclebob.com/ArticleS.UncleBob.TheBowlingGameKata"&gt;Bowling Game&lt;/a&gt;,&lt;br&gt;
&lt;a href="http://codingdojo.org/kata/StringCalculator/"&gt;String Calculator&lt;/a&gt;,&lt;br&gt;
&lt;a href="http://butunclebob.com/ArticleS.UncleBob.ThePrimeFactorsKata"&gt;Prime Factors&lt;/a&gt;,&lt;br&gt;
and &lt;a href="http://codingdojo.org/kata/RomanNumerals/"&gt;Roman Numerals&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Next, choose a language. Depending on your goals, you can choose a&lt;br&gt;
familiar language or learn something entirely new. When doing a new kata&lt;br&gt;
for the first time, I would recommend using a familiar language. You can&lt;br&gt;
try new languages later after you're understanding of the kata is solid.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Start coding! Remember to follow the TDD cycle:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Write a failing test&lt;/li&gt;
&lt;li&gt;Write just enough code to make the test pass&lt;/li&gt;
&lt;li&gt;Refactor&lt;/li&gt;
&lt;li&gt;Repeat&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Remember, this is a safe environment where you're free to make mistakes.&lt;br&gt;
If you can't figure out a kata, don't feel bad about looking up solutions.&lt;br&gt;
The point is to learn the movements of TDD or to practice the keyboard&lt;br&gt;
shortcuts of your editor.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Are the Benefits of Practicing Code Katas?
&lt;/h2&gt;

&lt;p&gt;The three main benefits of practicing code katas are:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Practicing the TDD flow.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I hear that many developers want to learn TDD, but learning TDD on the job is&lt;br&gt;
not always a good option. We need a safe environment to fail and learn without the&lt;br&gt;
pressure of deadlines or preventing bugs. Code katas can offer that environment to&lt;br&gt;
any developer that cares to improve or learn their TDD skills. Regular code kata&lt;br&gt;
practice should make doing TDD in the workplace almost second nature.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Increased Editor Efficiency&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Have you always wanted to learn Vim, but never felt you had the time? What about&lt;br&gt;
all those ReSharper shortcuts? When you practice a code kata, you can take the time&lt;br&gt;
to learn the most efficient key strokes and really get to know your editor. This can&lt;br&gt;
really pay off when writing production code. It's a great way to increase your&lt;br&gt;
confidence as a developer. Whatever editor you use, you owe it to yourself&lt;br&gt;
to be as proficient as possible with your tool set.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Learn a new language or language features&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;After you understand a kata well and have practiced it a couple of times, feel free&lt;br&gt;
to experiment. What would the code look like in a completely different language from&lt;br&gt;
the one you use everyday? Are there some brand new features in your favorite&lt;br&gt;
language you have yet to try out? Code katas are a perfect way to both learn&lt;br&gt;
new languages and gain a deeper understanding of familiar languages.&lt;/p&gt;

&lt;h2&gt;
  
  
  Closing Thoughts
&lt;/h2&gt;

&lt;p&gt;In life, fundamentals often separate the successful from the unsuccessful. What do&lt;br&gt;
many coaches say after a tough loss? "We have get back to the fundamentals".&lt;/p&gt;

&lt;p&gt;As developers, how do we practice the fundamentals of developing software?&lt;br&gt;
I think this is something that our industry often forgets. We are so eager to dive in&lt;br&gt;
and start slinging code that we rarely take the time to slow down and deliberately&lt;br&gt;
practice to improve our skills. I believe doing regular code katas is a fantastic way&lt;br&gt;
to practice the fundamentals developing software and will make a noticeable difference&lt;br&gt;
in your productivity.&lt;/p&gt;

&lt;p&gt;Originally posted on &lt;a href="https://redgreenrefactor.dev"&gt;RedGreenRefactor&lt;/a&gt;&lt;/p&gt;

</description>
      <category>tdd</category>
      <category>testing</category>
    </item>
    <item>
      <title>A Short Introduction to TDD</title>
      <dc:creator>John Oerter</dc:creator>
      <pubDate>Wed, 11 Dec 2019 16:33:30 +0000</pubDate>
      <link>https://forem.com/joerter/a-short-introduction-to-tdd-504j</link>
      <guid>https://forem.com/joerter/a-short-introduction-to-tdd-504j</guid>
      <description>&lt;h2&gt;
  
  
  What is TDD?
&lt;/h2&gt;

&lt;p&gt;Whether you're new to software development or have been around for awhile,&lt;br&gt;
you may have heard of TDD, but have never really gotten a full explanation&lt;br&gt;
of the process and benefits of adoption. The purpose of this post is to give&lt;br&gt;
you a quick introduction to TDD and hopefully pique your interest if you don't&lt;br&gt;
already have TDD in your arsenal of tools.&lt;/p&gt;

&lt;p&gt;So what is TDD? To put it simply,&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TDD (Test Driven Development) is a methodology of developing software&lt;br&gt;
that relies on very short feedback loops using unit tests.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To practice TDD, start with a failing unit test.&lt;br&gt;
Then write only enough code to make that test pass. Finally, refactor the&lt;br&gt;
production and unit test code you've written. Repeat.&lt;br&gt;
This cycle is often called Red Green Refactor and is the inspiration for the name of this blog.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Robert_C._Martin"&gt;Uncle Bob Martin&lt;/a&gt; summarized this&lt;br&gt;
process into what he calls the &lt;a href="http://butunclebob.com/ArticleS.UncleBob.TheThreeRulesOfTdd"&gt;"Three Rules of TDD"&lt;/a&gt;,&lt;br&gt;
which are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You are not allowed to write any production code unless it is to make a failing unit test pass.&lt;/li&gt;
&lt;li&gt;You are not allowed to write any more of a unit test than is sufficient to fail; and compilation failures are failures.&lt;/li&gt;
&lt;li&gt;You are not allowed to write any more production code than is sufficient to pass the one failing unit test.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Why Should I Learn TDD?
&lt;/h2&gt;

&lt;p&gt;Learning and practicing TDD has numerous benefits while developing software.&lt;br&gt;
I'll expand on the most important ones to me here.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Code is Always Running
&lt;/h3&gt;

&lt;p&gt;When you're in a TDD flow, the time between unit tests runs is usually no more than a few minutes.&lt;br&gt;
This means that at any given point, the whole program worked at most a few minutes ago.&lt;br&gt;
If you somehow make a change that breaks some part of the code, it's much easier to undo&lt;br&gt;
that change and get back to a working system. This makes it much harder to have an&lt;br&gt;
hours long coding session of many changes that leaves a whole program in disrepair.&lt;br&gt;
And if you're being proactive during the Refactor phase of a TDD cycle,&lt;br&gt;
your code is always in a clean state which makes the possibility&lt;br&gt;
of creating bugs smaller.&lt;/p&gt;

&lt;h3&gt;
  
  
  Saving Debugging Time
&lt;/h3&gt;

&lt;p&gt;Another benefit of tighter feedback loops from unit tests is a drastically smaller&lt;br&gt;
need to use the debugger. You may still need to use the debugger if a test unexpectedly fails,&lt;br&gt;
but the issue should be much more apparent when there is only a small unit of code to debug.&lt;/p&gt;

&lt;h3&gt;
  
  
  Easier Refactoring
&lt;/h3&gt;

&lt;p&gt;After following TDD for a bit in a large system, you may have hundreds of unit tests.&lt;br&gt;
These tests are your best defense against breaking the system.&lt;br&gt;
If you find that the architecture is flawed in some way,&lt;br&gt;
you can always rely on these tests during refactoring.&lt;br&gt;
You could fearlessly delete all of your production code and start completely&lt;br&gt;
from scratch while being guided buy a suite of comprehensive tests.&lt;/p&gt;

&lt;h3&gt;
  
  
  Unit Tests as Documentation
&lt;/h3&gt;

&lt;p&gt;Having a large suite of passing unit tests can act as living and&lt;br&gt;
breathing documentation of your system. This is like a detailed specification&lt;br&gt;
that is forced to stay up to date with the production code. When other developers read your code,&lt;br&gt;
they can use these tests to understand the requirements of the system and the constraints.&lt;/p&gt;

&lt;h3&gt;
  
  
  Gets Requirements Out of Your Head
&lt;/h3&gt;

&lt;p&gt;Last, but certainly not least, is my personal favorite.&lt;br&gt;
If someone asked me why I use TDD and why I am more effective as a&lt;br&gt;
developer when following a TDD flow, this is the first reason I would give.&lt;br&gt;
As developers, we are usually juggling so many thoughts and concerns while creating software.&lt;br&gt;
Requirements, edge cases, and possible performance issues are just a few examples.&lt;br&gt;
By practicing TDD, I can get those out of my head piece by piece and&lt;br&gt;
build upon them bit by bit. I can solve the simplest problems first and then&lt;br&gt;
move on to the more complex. TDD allows me to get out of my own way when&lt;br&gt;
writing code and solve problems faster.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrap Up
&lt;/h2&gt;

&lt;p&gt;I hope you enjoyed this article. If you've never heard of TDD,&lt;br&gt;
I hope I've inspired you to check it out. If you've tried it&lt;br&gt;
and decided it's not for you, then I hope I've inspired you to give it another shot.&lt;/p&gt;

&lt;p&gt;Originally published on &lt;a href="https://redgreenrefactor.dev"&gt;RedGreenRefactor&lt;/a&gt;&lt;/p&gt;

</description>
      <category>tdd</category>
      <category>testing</category>
    </item>
  </channel>
</rss>
