<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[Biodigital Jazz]]></title><description><![CDATA[Lessons learned in software engineering.]]></description><link>https://www.biodigitaljazz.tech</link><image><url>https://www.biodigitaljazz.tech/img/substack.png</url><title>Biodigital Jazz</title><link>https://www.biodigitaljazz.tech</link></image><generator>Substack</generator><lastBuildDate>Mon, 18 May 2026 04:25:47 GMT</lastBuildDate><atom:link href="https://www.biodigitaljazz.tech/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Tim Reynolds]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[biodigitaljazz@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[biodigitaljazz@substack.com]]></itunes:email><itunes:name><![CDATA[Tim Reynolds]]></itunes:name></itunes:owner><itunes:author><![CDATA[Tim Reynolds]]></itunes:author><googleplay:owner><![CDATA[biodigitaljazz@substack.com]]></googleplay:owner><googleplay:email><![CDATA[biodigitaljazz@substack.com]]></googleplay:email><googleplay:author><![CDATA[Tim Reynolds]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[Bootstrapping a Python Project]]></title><description><![CDATA[Setting up a Python project manually can be tedious, but it&#8217;s a valuable way to learn the ecosystem. I created a simple bash script to automate the process: setting up a virtual environment, installing handy tools, and building a basic structure. Today, I&#8217;m excited to share it with you!]]></description><link>https://www.biodigitaljazz.tech/p/bootstrapping-a-python-project</link><guid isPermaLink="false">https://www.biodigitaljazz.tech/p/bootstrapping-a-python-project</guid><dc:creator><![CDATA[Tim Reynolds]]></dc:creator><pubDate>Thu, 19 Dec 2024 13:31:00 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/d971d86c-e7c4-45d0-a355-c927554cfd30_300x300.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Lately, I&#8217;ve been working more with the Python programming language. I&#8217;ve used Python some in the past, but this time I really want to get a deeper understanding of the language and its ecosystem. To get up to speed, I&#8217;ve been reading <em><a href="https://nostarch.com/dead-simple-python">Dead Simple Python</a></em> by Jason McDonald. It&#8217;s an excellent book for developers who already know how to program but want to learn Python, along with its ecosystem and common best practices.</p><p>One topic that can be convoluted is <strong>project setup</strong>. I expected to find a simple command-line utility like <code>python init</code>, something I could quickly use to spin up a project structure. There are some utilities that do this job for you, such as <a href="https://python-poetry.org/">Poetry</a> and <a href="https://docs.astral.sh/uv/">UV</a>.</p><p>However, for the sake of understanding, I really wanted to work with the basic tooling available: more hands-on work with <code>pip</code> and <code>virtual environments</code>, and craft my setup from there. Setting up a basic project with these tools, however, can involve a lot of tedious steps.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!XG6J!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1b870eb5-ca65-4d12-9c52-71b405f8eb8a_1024x1024.webp" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!XG6J!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1b870eb5-ca65-4d12-9c52-71b405f8eb8a_1024x1024.webp 424w, https://substackcdn.com/image/fetch/$s_!XG6J!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1b870eb5-ca65-4d12-9c52-71b405f8eb8a_1024x1024.webp 848w, https://substackcdn.com/image/fetch/$s_!XG6J!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1b870eb5-ca65-4d12-9c52-71b405f8eb8a_1024x1024.webp 1272w, https://substackcdn.com/image/fetch/$s_!XG6J!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1b870eb5-ca65-4d12-9c52-71b405f8eb8a_1024x1024.webp 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!XG6J!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1b870eb5-ca65-4d12-9c52-71b405f8eb8a_1024x1024.webp" width="728" height="728" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1b870eb5-ca65-4d12-9c52-71b405f8eb8a_1024x1024.webp&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:false,&quot;imageSize&quot;:&quot;normal&quot;,&quot;height&quot;:1024,&quot;width&quot;:1024,&quot;resizeWidth&quot;:728,&quot;bytes&quot;:230944,&quot;alt&quot;:&quot;A cyberpunk-style illustration of a futuristic python coiling tightly around a glowing command-line terminal window displaying Python setup commands.&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/webp&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="A cyberpunk-style illustration of a futuristic python coiling tightly around a glowing command-line terminal window displaying Python setup commands." title="A cyberpunk-style illustration of a futuristic python coiling tightly around a glowing command-line terminal window displaying Python setup commands." srcset="https://substackcdn.com/image/fetch/$s_!XG6J!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1b870eb5-ca65-4d12-9c52-71b405f8eb8a_1024x1024.webp 424w, https://substackcdn.com/image/fetch/$s_!XG6J!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1b870eb5-ca65-4d12-9c52-71b405f8eb8a_1024x1024.webp 848w, https://substackcdn.com/image/fetch/$s_!XG6J!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1b870eb5-ca65-4d12-9c52-71b405f8eb8a_1024x1024.webp 1272w, https://substackcdn.com/image/fetch/$s_!XG6J!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1b870eb5-ca65-4d12-9c52-71b405f8eb8a_1024x1024.webp 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Even the python is having issues&#8230;</figcaption></figure></div><p>The aforementioned book does a great job of detailing how and what to set up as you create basic to sophisticated projects. There&#8217;s also plenty of material on the internet that describes different project setups and approaches.</p><p>So, I decided to automate the process and share what I have so far&#8230;</p><div><hr></div><h2><strong>The Python Project Initializer Script</strong></h2><p>Here&#8217;s the link to a repo that contains the script I created:<br><strong><a href="https://github.com/reynoldstim/python-project-initializer/blob/main/init_python_project.sh">init_python_project.sh</a></strong>.</p><p>This script automates the creation of a very simple Python project with a <strong>virtual environment</strong>, a few tools for <strong>linting</strong>, <strong>formatting</strong>, and <strong>testing</strong>, and a <strong>program entry point</strong>.</p><div><hr></div><h2><strong>Script Breakdown:</strong></h2><p>This script automates the setup of a basic Python project, providing everything you need to get started quickly and efficiently. Here&#8217;s a breakdown of what it&#8217;s doing:</p><div><hr></div><h3><strong>1. Create the Project Directory</strong></h3><p>The script begins by asking for a project name and creating a directory with that name. This directory serves as the root of your new project.</p><pre><code>if ! mkdir "$PROJECT_NAME"; then
    echo "Error: Failed to create project directory."
    exit 1
fi
cd "$PROJECT_NAME" || exit</code></pre><p>This ensures that the project directory is created successfully, and the script exits gracefully if an error occurs.</p><div><hr></div><h3><strong>2. Set Up a Virtual Environment</strong></h3><p>A virtual environment isolates dependencies for your project, preventing conflicts with system-wide Python packages or other projects.</p><pre><code>"$PYTHON_VERSION" -m venv .venv

source .venv/bin/activate</code></pre><ul><li><p><strong>Virtual Environment Creation</strong>: <code>python3 -m venv .venv</code> sets up an isolated environment within a .<code>venv/</code> directory. When using vscode with python tools, opening the project directory will automatically pickup the virtual environment.</p></li><li><p><strong>Activation</strong>: Activating the environment ensures all dependencies installed via <code>pip</code> are scoped to this project.</p></li></ul><div><hr></div><h3><strong>3. Initialize Dependencies</strong></h3><p>The script installs a few handy tools for development:</p><ul><li><p><strong>Black</strong>: A code formatter that enforces a consistent style.</p></li><li><p><strong>Flake8</strong>: A linting tool for catching style and syntax issues.</p></li><li><p><strong>pytest</strong>: The most common Python testing framework.</p></li></ul><pre><code>pip install --upgrade pip
pip install black flake8 pytest</code></pre><p>This ensures that your project starts with tools for formatting, linting, and testing.</p><div><hr></div><h3><strong>4. Create a </strong><code>pyproject.toml</code><strong> File</strong></h3><p>The script generates a <code>pyproject.toml</code> file, a standardized way to configure Python tools and projects. This file simplifies configuration and avoids cluttering the project with multiple tool-specific files.</p><p>Example contents for <code>pyproject.toml</code>:</p><pre><code>[tool.black]
line-length = 88
target-version = ['py38']

[tool.flake8]
max-line-length = 88
exclude = [".venv", "venv", "tests/"]</code></pre><ul><li><p><code>[tool.black]</code>: Configures Black to format code with a line length of 88 characters, targeting Python 3.8.</p></li><li><p><code>[tool.flake8]</code>: Configures Flake8 to match the same line length and exclude directories like <code>venv</code> and <code>tests</code>.</p></li></ul><p>By centralizing configurations in <code>pyproject.toml</code>, you maintain a clean and modern setup.</p><div><hr></div><h3><strong>5. Generate a </strong><code>requirements.txt</code><strong> File</strong></h3><p>To help with reproducibility, the script uses <code>pip freeze</code> to list installed dependencies and lock them into a <code>requirements.txt</code> file.</p><pre><code>pip freeze &gt; requirements.txt</code></pre><p>This makes it easy for others (or future you) to recreate the same environment using:</p><pre><code>pip install -r requirements.txt</code></pre><div><hr></div><h3><strong>6. Create Basic Project Files and Structure</strong></h3><p>The script scaffolds a simple, functional Python project structure. The resulting directory looks like this:</p><pre><code>&lt;project-name&gt;/
&#9500;&#9472;&#9472; .git/
&#9500;&#9472;&#9472; .gitignore
&#9500;&#9472;&#9472; .venv/
&#9500;&#9472;&#9472; LICENSE.md
&#9500;&#9472;&#9472; pyproject.toml
&#9500;&#9472;&#9472; README.md
&#9500;&#9472;&#9472; requirements.txt
&#9500;&#9472;&#9472; &lt;project-name&gt;.py           # root level entry point
&#9500;&#9472;&#9472; &lt;project-name&gt;/
&#9474;   &#9500;&#9472;&#9472; __init__.py
&#9474;   &#9492;&#9472;&#9472; __main__.py             # Entry point for the application
&#9492;&#9472;&#9472; tests/                      # Tests directory
    &#9500;&#9472;&#9472; __init__.py
    &#9492;&#9472;&#9472; test_placeholder.py     # Placeholder test file
</code></pre><p>This structure provides a clean starting point for a simple project.</p><div><hr></div><h3><strong>7. Set Up Git</strong></h3><p>The script also initializes a Git repository and sets up a <code>.gitignore</code> file for version control.</p><div><hr></div><h2><strong>How to Use the Script</strong></h2><p>You can clone or simply download the script file. Then make it executable and run it with the filename like so:</p><pre><code>chmod +x ./init_python_project.sh 

./init_python_project.sh</code></pre><p>This will create a project in the same directory as the script.</p><h3><strong>Make the Script Available Anywhere</strong></h3><p>What I do is add the script in a location where my <code>PATH</code> variable will pick it up. I&#8217;m running a Mac with Zsh as my shell. Here&#8217;s how you can do it:</p><ol><li><p><strong>Move the Script to a Directory in Your </strong><code>PATH</code><br>A common location for user scripts is <code>~/bin</code> or <code>/usr/local/bin</code>. you can move the script into that directory.</p></li></ol><pre><code>mv init_python_project.sh ~/bin/</code></pre><ol start="2"><li><p><strong>Add the Directory to Your </strong><code>PATH</code><br>If <code>~/bin</code> isn&#8217;t already in your <code>PATH</code>, add it in your ZSH configuration file (<code>~/.zshrc</code>):</p></li></ol><pre><code># look for a line like this, it may be commented-out
export PATH="$HOME/bin:$PATH"</code></pre><p>     Then reload your ZSH configuration:</p><pre><code>source ~/.zshrc</code></pre><ol start="3"><li><p><strong>Call the Script from Anywhere</strong><br>Now you can use the script from any directory:</p></li></ol><pre><code>init_python_project.sh</code></pre><p>This makes it convenient to spin up a new Python project in any directory.</p><h2><strong>Why Automate?</strong></h2><p>By automating all of these steps, this script allowed me to learn a lot about Python&#8217;s tooling and ecosystem while saving the time and hassle of manually setting up each new project.</p><p>It&#8217;s a great foundation for small projects and can easily be extended as my needs grow.</p><p>Grab the script <a href="https://github.com/reynoldstim/python-project-initializer/tree/main">here</a> and let me know how it works for you! Feel free to add issues, submit pull requests for improvements, or fork the repo for your own needs.</p><p></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.biodigitaljazz.tech/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Biodigital Jazz! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[waitFor Me!]]></title><description><![CDATA[Async/Await with Testing Library's waitFor]]></description><link>https://www.biodigitaljazz.tech/p/waitfor-me</link><guid isPermaLink="false">https://www.biodigitaljazz.tech/p/waitfor-me</guid><dc:creator><![CDATA[Tim Reynolds]]></dc:creator><pubDate>Fri, 10 May 2024 23:07:57 GMT</pubDate><enclosure url="https://images.unsplash.com/photo-1620405959457-b2411a30cd78?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwyfHx3YWl0aW5nfGVufDB8fHx8MTcxNTM3ODg0NXww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://images.unsplash.com/photo-1620405959457-b2411a30cd78?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwyfHx3YWl0aW5nfGVufDB8fHx8MTcxNTM3ODg0NXww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://images.unsplash.com/photo-1620405959457-b2411a30cd78?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwyfHx3YWl0aW5nfGVufDB8fHx8MTcxNTM3ODg0NXww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 424w, https://images.unsplash.com/photo-1620405959457-b2411a30cd78?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwyfHx3YWl0aW5nfGVufDB8fHx8MTcxNTM3ODg0NXww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 848w, https://images.unsplash.com/photo-1620405959457-b2411a30cd78?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwyfHx3YWl0aW5nfGVufDB8fHx8MTcxNTM3ODg0NXww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 1272w, https://images.unsplash.com/photo-1620405959457-b2411a30cd78?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwyfHx3YWl0aW5nfGVufDB8fHx8MTcxNTM3ODg0NXww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 1456w" sizes="100vw"><img src="https://images.unsplash.com/photo-1620405959457-b2411a30cd78?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwyfHx3YWl0aW5nfGVufDB8fHx8MTcxNTM3ODg0NXww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080" width="6060" height="4040" data-attrs="{&quot;src&quot;:&quot;https://images.unsplash.com/photo-1620405959457-b2411a30cd78?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwyfHx3YWl0aW5nfGVufDB8fHx8MTcxNTM3ODg0NXww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:4040,&quot;width&quot;:6060,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;happy new year neon light signage&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="happy new year neon light signage" title="happy new year neon light signage" srcset="https://images.unsplash.com/photo-1620405959457-b2411a30cd78?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwyfHx3YWl0aW5nfGVufDB8fHx8MTcxNTM3ODg0NXww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 424w, https://images.unsplash.com/photo-1620405959457-b2411a30cd78?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwyfHx3YWl0aW5nfGVufDB8fHx8MTcxNTM3ODg0NXww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 848w, https://images.unsplash.com/photo-1620405959457-b2411a30cd78?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwyfHx3YWl0aW5nfGVufDB8fHx8MTcxNTM3ODg0NXww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 1272w, https://images.unsplash.com/photo-1620405959457-b2411a30cd78?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwyfHx3YWl0aW5nfGVufDB8fHx8MTcxNTM3ODg0NXww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Photo by <a href="true">Levi Meir Clancy</a> on <a href="https://unsplash.com">Unsplash</a></figcaption></figure></div><p>Automated tests are wonderful. They can give you confidence that the code you write works. They can document the behavior of your application. And they can also help prevent regressions introduced when you update your applications.</p><p>However, sometimes a bug can slip into your tests and cause them to <em>lie</em> to you! You see a test pass, and without carefully checking, you can get a false sense of confidence, making you think that your code works when really, you&#8217;ve allowed a bug through.</p><p>A coworker and I discovered  this recently while reviewing one of their tests. Let&#8217;s explore an example&#8230;</p><p><strong>TL;DR</strong></p><p>When using Testing Library&#8217;s<em><a href="https://testing-library.com/docs/dom-testing-library/api-async/#waitfor"> waitFor</a></em><a href="https://testing-library.com/docs/dom-testing-library/api-async/#waitfor"> function </a>to test asynchronous code, remember that it returns a <code>Promise</code>. So make sure to <code>use await </code>or<code> .then</code>.</p><p>Do this:</p><pre><code>it('tests some asynchronous code', <em><strong>async</strong></em> () =&gt; {
  // arrange
  // act

  <em><strong>await</strong></em> waitFor(() =&gt; {
    //assert
  });
});</code></pre><p>Or this:</p><pre><code><code>it('tests some asynchronous code', () =&gt; {
  // arrange

  waitFor(() =&gt; {
    // act
  })</code><em><strong>.then</strong></em><code>(() =&gt; {
    // assert
  });
});</code></code></pre><p>But NOT this:</p><pre><code>it('tests some asynchronous code', () =&gt; {
  // arrange
  // act

  waitFor(() =&gt; {
    // You'll think that you asserted, but you probably didn't.
  });
});</code></pre><p>They mention this in the <a href="https://testing-library.com/docs/dom-testing-library/api-async">docs</a> too&#8230;</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!E6B7!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1d477d0a-2b82-4211-9692-561ea09cdf11_1756x1462.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!E6B7!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1d477d0a-2b82-4211-9692-561ea09cdf11_1756x1462.png 424w, https://substackcdn.com/image/fetch/$s_!E6B7!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1d477d0a-2b82-4211-9692-561ea09cdf11_1756x1462.png 848w, https://substackcdn.com/image/fetch/$s_!E6B7!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1d477d0a-2b82-4211-9692-561ea09cdf11_1756x1462.png 1272w, https://substackcdn.com/image/fetch/$s_!E6B7!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1d477d0a-2b82-4211-9692-561ea09cdf11_1756x1462.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!E6B7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1d477d0a-2b82-4211-9692-561ea09cdf11_1756x1462.png" width="1456" height="1212" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1d477d0a-2b82-4211-9692-561ea09cdf11_1756x1462.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1212,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:337570,&quot;alt&quot;:&quot;The async methods return Promises, so be sure to use await or .then when calling them.&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="The async methods return Promises, so be sure to use await or .then when calling them." title="The async methods return Promises, so be sure to use await or .then when calling them." srcset="https://substackcdn.com/image/fetch/$s_!E6B7!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1d477d0a-2b82-4211-9692-561ea09cdf11_1756x1462.png 424w, https://substackcdn.com/image/fetch/$s_!E6B7!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1d477d0a-2b82-4211-9692-561ea09cdf11_1756x1462.png 848w, https://substackcdn.com/image/fetch/$s_!E6B7!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1d477d0a-2b82-4211-9692-561ea09cdf11_1756x1462.png 1272w, https://substackcdn.com/image/fetch/$s_!E6B7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1d477d0a-2b82-4211-9692-561ea09cdf11_1756x1462.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Testing Library&#8217;s docs tell you what I&#8217;m telling you. I&#8217;m not that original.</figcaption></figure></div><h2>The Example</h2><p>I created a small demo application for illustration. <a href="https://github.com/reynoldstim/async-await-waitfor-example">Here&#8217;s the link to the repo</a>.</p><p>This little React application takes some input text, reverses it, and then displays the reversed text to the user.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!n-km!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f266b95-4bb0-4736-89be-1ef047feea13_3024x1894.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!n-km!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f266b95-4bb0-4736-89be-1ef047feea13_3024x1894.png 424w, https://substackcdn.com/image/fetch/$s_!n-km!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f266b95-4bb0-4736-89be-1ef047feea13_3024x1894.png 848w, https://substackcdn.com/image/fetch/$s_!n-km!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f266b95-4bb0-4736-89be-1ef047feea13_3024x1894.png 1272w, https://substackcdn.com/image/fetch/$s_!n-km!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f266b95-4bb0-4736-89be-1ef047feea13_3024x1894.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!n-km!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f266b95-4bb0-4736-89be-1ef047feea13_3024x1894.png" width="1456" height="912" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4f266b95-4bb0-4736-89be-1ef047feea13_3024x1894.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:912,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:243763,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!n-km!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f266b95-4bb0-4736-89be-1ef047feea13_3024x1894.png 424w, https://substackcdn.com/image/fetch/$s_!n-km!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f266b95-4bb0-4736-89be-1ef047feea13_3024x1894.png 848w, https://substackcdn.com/image/fetch/$s_!n-km!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f266b95-4bb0-4736-89be-1ef047feea13_3024x1894.png 1272w, https://substackcdn.com/image/fetch/$s_!n-km!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f266b95-4bb0-4736-89be-1ef047feea13_3024x1894.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>The reversal of the text is delayed by 200 ms. In the real application where we encountered this type of bug, the action that my coworker implemented invoked an API call. The application had to wait for this API call to finish to display the results. This example is contrived to mimic that behavior.</p><pre><code>// This reversed result is delayed and returns a promise. This is to 
// mimic the behavior we might encounter in an API call, such as with
//.fetch.
function delayedReverseString(theString: string): Promise&lt;string&gt; {
  return new Promise((resolve) =&gt; {
    setTimeout(() =&gt; {
      const reversedString = reverseString(theString);
      resolve(reversedString);
    }, 250);
  });
}</code></pre><p>Before we try it out, let&#8217;s examine the test&#8230;</p><pre><code>  it('reverses entered text and displays reversed text to user', () =&gt; {
    // arrange
    render(&lt;App /&gt;);
    const input = screen.getByPlaceholderText('Enter text...');
    const reverseButton = screen.getByText('Reverse!');

    // act
    fireEvent.change(input, { target: { value: 'hello' } });
    fireEvent.click(reverseButton);

    // assert
    expect(screen.getByText('olleh')).toBeInTheDocument();
  });</code></pre><p>As you can see, our test:</p><ol><li><p>Renders the application.</p></li><li><p>Gets the input element and the reverse button.</p></li><li><p>Enters the text &#8220;hello&#8221;, and clicks the button, just like a user would.</p></li><li><p>Asserts that the reversed text is displayed in the document.</p></li></ol><p>When we run the test, we can see it fails&#8230;</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!xExQ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F114516c6-aaa9-4a09-87a0-d0d6c8abbcd0_3024x1892.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!xExQ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F114516c6-aaa9-4a09-87a0-d0d6c8abbcd0_3024x1892.png 424w, https://substackcdn.com/image/fetch/$s_!xExQ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F114516c6-aaa9-4a09-87a0-d0d6c8abbcd0_3024x1892.png 848w, https://substackcdn.com/image/fetch/$s_!xExQ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F114516c6-aaa9-4a09-87a0-d0d6c8abbcd0_3024x1892.png 1272w, https://substackcdn.com/image/fetch/$s_!xExQ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F114516c6-aaa9-4a09-87a0-d0d6c8abbcd0_3024x1892.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!xExQ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F114516c6-aaa9-4a09-87a0-d0d6c8abbcd0_3024x1892.png" width="1456" height="911" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/114516c6-aaa9-4a09-87a0-d0d6c8abbcd0_3024x1892.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:911,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:616236,&quot;alt&quot;:&quot;The test fails.&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="The test fails." title="The test fails." srcset="https://substackcdn.com/image/fetch/$s_!xExQ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F114516c6-aaa9-4a09-87a0-d0d6c8abbcd0_3024x1892.png 424w, https://substackcdn.com/image/fetch/$s_!xExQ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F114516c6-aaa9-4a09-87a0-d0d6c8abbcd0_3024x1892.png 848w, https://substackcdn.com/image/fetch/$s_!xExQ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F114516c6-aaa9-4a09-87a0-d0d6c8abbcd0_3024x1892.png 1272w, https://substackcdn.com/image/fetch/$s_!xExQ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F114516c6-aaa9-4a09-87a0-d0d6c8abbcd0_3024x1892.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">The test fails</figcaption></figure></div><p>Since we know the result is delayed, we&#8217;ll need to modify our test to wait for that result to display. So let&#8217;s use <a href="https://testing-library.com/docs/dom-testing-library/api-async/#waitfor">Testing Library&#8217;s waitFor</a> function to do that!<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a></p><pre><code>...

// assert
waitFor(() =&gt; {
  expect(screen.getByText('olleh')).toBeInTheDocument();
});

...</code></pre><p>After that modification, the test passes!</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!GXSz!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad8e8964-0a36-4fc4-a96d-f1d9f4e42e49_3022x1890.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!GXSz!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad8e8964-0a36-4fc4-a96d-f1d9f4e42e49_3022x1890.png 424w, https://substackcdn.com/image/fetch/$s_!GXSz!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad8e8964-0a36-4fc4-a96d-f1d9f4e42e49_3022x1890.png 848w, https://substackcdn.com/image/fetch/$s_!GXSz!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad8e8964-0a36-4fc4-a96d-f1d9f4e42e49_3022x1890.png 1272w, https://substackcdn.com/image/fetch/$s_!GXSz!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad8e8964-0a36-4fc4-a96d-f1d9f4e42e49_3022x1890.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!GXSz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad8e8964-0a36-4fc4-a96d-f1d9f4e42e49_3022x1890.png" width="1456" height="911" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ad8e8964-0a36-4fc4-a96d-f1d9f4e42e49_3022x1890.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:911,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:575389,&quot;alt&quot;:&quot;Image of passing test results.&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Image of passing test results." title="Image of passing test results." srcset="https://substackcdn.com/image/fetch/$s_!GXSz!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad8e8964-0a36-4fc4-a96d-f1d9f4e42e49_3022x1890.png 424w, https://substackcdn.com/image/fetch/$s_!GXSz!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad8e8964-0a36-4fc4-a96d-f1d9f4e42e49_3022x1890.png 848w, https://substackcdn.com/image/fetch/$s_!GXSz!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad8e8964-0a36-4fc4-a96d-f1d9f4e42e49_3022x1890.png 1272w, https://substackcdn.com/image/fetch/$s_!GXSz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad8e8964-0a36-4fc4-a96d-f1d9f4e42e49_3022x1890.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">The tests pass! Or so it appears&#8230;</figcaption></figure></div><p>Awesome. Our test is passing. However, when we try out the application, something seems off&#8230;</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!trk1!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8539ab9a-031a-4311-897b-323453e9b25a_3024x1896.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!trk1!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8539ab9a-031a-4311-897b-323453e9b25a_3024x1896.png 424w, https://substackcdn.com/image/fetch/$s_!trk1!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8539ab9a-031a-4311-897b-323453e9b25a_3024x1896.png 848w, https://substackcdn.com/image/fetch/$s_!trk1!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8539ab9a-031a-4311-897b-323453e9b25a_3024x1896.png 1272w, https://substackcdn.com/image/fetch/$s_!trk1!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8539ab9a-031a-4311-897b-323453e9b25a_3024x1896.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!trk1!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8539ab9a-031a-4311-897b-323453e9b25a_3024x1896.png" width="1456" height="913" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8539ab9a-031a-4311-897b-323453e9b25a_3024x1896.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:913,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:237230,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!trk1!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8539ab9a-031a-4311-897b-323453e9b25a_3024x1896.png 424w, https://substackcdn.com/image/fetch/$s_!trk1!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8539ab9a-031a-4311-897b-323453e9b25a_3024x1896.png 848w, https://substackcdn.com/image/fetch/$s_!trk1!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8539ab9a-031a-4311-897b-323453e9b25a_3024x1896.png 1272w, https://substackcdn.com/image/fetch/$s_!trk1!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8539ab9a-031a-4311-897b-323453e9b25a_3024x1896.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Our text just gets repeated back to us. That&#8217;s not right.</figcaption></figure></div><p>After entering some text and clicking &#8220;Reverse!&#8221; It just shows the text we entered! It&#8217;s not magically reversed!</p><p>So what mistake did we make in our test?</p><p>Let&#8217;s add some logging statements to follow along with the execution of our test.</p><pre><code>// assert
console.log("before waitFor");
waitFor(() =&gt; {
  console.log("before assertion");
  expect(screen.getByText('olleh')).toBeInTheDocument();
  console.log("after assertion");
});
console.log("after waitFor");</code></pre><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Accz!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e8a6a39-7d08-4b1d-876b-c635bb9a0e61_2212x1692.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Accz!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e8a6a39-7d08-4b1d-876b-c635bb9a0e61_2212x1692.png 424w, https://substackcdn.com/image/fetch/$s_!Accz!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e8a6a39-7d08-4b1d-876b-c635bb9a0e61_2212x1692.png 848w, https://substackcdn.com/image/fetch/$s_!Accz!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e8a6a39-7d08-4b1d-876b-c635bb9a0e61_2212x1692.png 1272w, https://substackcdn.com/image/fetch/$s_!Accz!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e8a6a39-7d08-4b1d-876b-c635bb9a0e61_2212x1692.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Accz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e8a6a39-7d08-4b1d-876b-c635bb9a0e61_2212x1692.png" width="1456" height="1114" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9e8a6a39-7d08-4b1d-876b-c635bb9a0e61_2212x1692.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1114,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:354880,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Accz!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e8a6a39-7d08-4b1d-876b-c635bb9a0e61_2212x1692.png 424w, https://substackcdn.com/image/fetch/$s_!Accz!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e8a6a39-7d08-4b1d-876b-c635bb9a0e61_2212x1692.png 848w, https://substackcdn.com/image/fetch/$s_!Accz!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e8a6a39-7d08-4b1d-876b-c635bb9a0e61_2212x1692.png 1272w, https://substackcdn.com/image/fetch/$s_!Accz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e8a6a39-7d08-4b1d-876b-c635bb9a0e61_2212x1692.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Notice that we never see &#8220;<code>after assertion</code>&#8220;. This is because our <code>expect</code> statement is failing and throwing an error. It will never hit the line after our assertion.</p><p>We can prove this by adding a try-catch block.</p><pre><code>// assert
console.log("before waitFor");
waitFor(() =&gt; {
  console.log("before assertion");
  try {
    expect(screen.getByText('olleh')).toBeInTheDocument();
  } catch (e) {
    console.log("EXPECT FAILURE:", e);
  }
  console.log("after assertion");
});
console.log("after waitFor");</code></pre><p>We can see that an error is thrown, but our test continues on its merry way, reporting success.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!QZ8G!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffaea8276-499a-4f6a-934a-f9e66b26784c_2242x1708.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!QZ8G!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffaea8276-499a-4f6a-934a-f9e66b26784c_2242x1708.png 424w, https://substackcdn.com/image/fetch/$s_!QZ8G!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffaea8276-499a-4f6a-934a-f9e66b26784c_2242x1708.png 848w, https://substackcdn.com/image/fetch/$s_!QZ8G!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffaea8276-499a-4f6a-934a-f9e66b26784c_2242x1708.png 1272w, https://substackcdn.com/image/fetch/$s_!QZ8G!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffaea8276-499a-4f6a-934a-f9e66b26784c_2242x1708.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!QZ8G!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffaea8276-499a-4f6a-934a-f9e66b26784c_2242x1708.png" width="1456" height="1109" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/faea8276-499a-4f6a-934a-f9e66b26784c_2242x1708.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1109,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:415161,&quot;alt&quot;:&quot;The expect statement is failing, but not our test.&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="The expect statement is failing, but not our test." title="The expect statement is failing, but not our test." srcset="https://substackcdn.com/image/fetch/$s_!QZ8G!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffaea8276-499a-4f6a-934a-f9e66b26784c_2242x1708.png 424w, https://substackcdn.com/image/fetch/$s_!QZ8G!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffaea8276-499a-4f6a-934a-f9e66b26784c_2242x1708.png 848w, https://substackcdn.com/image/fetch/$s_!QZ8G!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffaea8276-499a-4f6a-934a-f9e66b26784c_2242x1708.png 1272w, https://substackcdn.com/image/fetch/$s_!QZ8G!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffaea8276-499a-4f6a-934a-f9e66b26784c_2242x1708.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">The expect statement is failing, but not our test.</figcaption></figure></div><p>Why doesn&#8217;t our test fail? </p><p>Because <code>waitFor</code> returns a <code>Promise</code>. </p><p>The problem with our test is that we are not awaiting the returned promise to resolve before moving on. our test block doesn&#8217;t detect the error being thrown because in this case, <code>waitFor</code> is effectively swallowing the error thrown by our expect statement.</p><p>Let&#8217;s see what happens when we introduce <code>async</code> and <code>await</code>.</p><pre><code>it('reverses entered text and displays reversed text to user', <strong>async</strong> () =&gt; {
  // arrange
  render(&lt;App /&gt;);
  const input = screen.getByPlaceholderText('Enter text...');
  const reverseButton = screen.getByText('Reverse!');

  // act
  fireEvent.change(input, { target: { value: 'hello' } }); 
  fireEvent.click(reverseButton);

  // assert
  console.log("before waitFor");
  <strong>await</strong> waitFor(() =&gt; {
    console.log("before assertion");
    expect(screen.getByText('olleh')).toBeInTheDocument();
    console.log("after assertion");
  });
  console.log("after waitFor");
});</code></pre><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!JHPZ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98935a2a-d4b5-43bd-92aa-d2f33a8ad02f_2204x1602.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!JHPZ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98935a2a-d4b5-43bd-92aa-d2f33a8ad02f_2204x1602.png 424w, https://substackcdn.com/image/fetch/$s_!JHPZ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98935a2a-d4b5-43bd-92aa-d2f33a8ad02f_2204x1602.png 848w, https://substackcdn.com/image/fetch/$s_!JHPZ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98935a2a-d4b5-43bd-92aa-d2f33a8ad02f_2204x1602.png 1272w, https://substackcdn.com/image/fetch/$s_!JHPZ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98935a2a-d4b5-43bd-92aa-d2f33a8ad02f_2204x1602.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!JHPZ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98935a2a-d4b5-43bd-92aa-d2f33a8ad02f_2204x1602.png" width="1456" height="1058" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/98935a2a-d4b5-43bd-92aa-d2f33a8ad02f_2204x1602.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1058,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:357906,&quot;alt&quot;:&quot;The test finally fails!&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="The test finally fails!" title="The test finally fails!" srcset="https://substackcdn.com/image/fetch/$s_!JHPZ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98935a2a-d4b5-43bd-92aa-d2f33a8ad02f_2204x1602.png 424w, https://substackcdn.com/image/fetch/$s_!JHPZ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98935a2a-d4b5-43bd-92aa-d2f33a8ad02f_2204x1602.png 848w, https://substackcdn.com/image/fetch/$s_!JHPZ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98935a2a-d4b5-43bd-92aa-d2f33a8ad02f_2204x1602.png 1272w, https://substackcdn.com/image/fetch/$s_!JHPZ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98935a2a-d4b5-43bd-92aa-d2f33a8ad02f_2204x1602.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">The test finally fails!</figcaption></figure></div><p> We finally have a failing test! Notice that &#8220;before assertion&#8221; gets logged about 21 times, and then reports a failure.</p><p>This is how <code>waitFor</code> works. By default, it will run the callback once, then it repeats the passed callback every 50 milliseconds for 1000 milliseconds (1 second), or until the callback completes successfully, and resolves the promise. Once waitFor has timed out, it will reject the promise, and pass along the error that occurred. This unhandled error will then cause our test to fail.</p><p>Now that we have a valid test, let&#8217;s fix our code.</p><p>Let&#8217;s take a look at the <code>reverseString</code> function.</p><pre><code>function reverseString(theString: string): string {
  return theString.split('').join('');
}</code></pre><p>We forgot to reverse the string! Thankfully, that&#8217;s an easy fix.</p><pre><code>function reverseString(theString: string): string {
  return theString.split('').<strong>reverse()</strong>.join('');
}</code></pre><p>We can see that our test passes.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!t2uV!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0f2fec4b-633b-485c-8f29-31f0624077a0_2222x1718.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!t2uV!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0f2fec4b-633b-485c-8f29-31f0624077a0_2222x1718.png 424w, https://substackcdn.com/image/fetch/$s_!t2uV!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0f2fec4b-633b-485c-8f29-31f0624077a0_2222x1718.png 848w, https://substackcdn.com/image/fetch/$s_!t2uV!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0f2fec4b-633b-485c-8f29-31f0624077a0_2222x1718.png 1272w, https://substackcdn.com/image/fetch/$s_!t2uV!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0f2fec4b-633b-485c-8f29-31f0624077a0_2222x1718.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!t2uV!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0f2fec4b-633b-485c-8f29-31f0624077a0_2222x1718.png" width="1456" height="1126" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/0f2fec4b-633b-485c-8f29-31f0624077a0_2222x1718.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1126,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:337660,&quot;alt&quot;:&quot;Our test passes! For real this time!&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Our test passes! For real this time!" title="Our test passes! For real this time!" srcset="https://substackcdn.com/image/fetch/$s_!t2uV!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0f2fec4b-633b-485c-8f29-31f0624077a0_2222x1718.png 424w, https://substackcdn.com/image/fetch/$s_!t2uV!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0f2fec4b-633b-485c-8f29-31f0624077a0_2222x1718.png 848w, https://substackcdn.com/image/fetch/$s_!t2uV!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0f2fec4b-633b-485c-8f29-31f0624077a0_2222x1718.png 1272w, https://substackcdn.com/image/fetch/$s_!t2uV!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0f2fec4b-633b-485c-8f29-31f0624077a0_2222x1718.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Our test passes! For real this time!</figcaption></figure></div><p>And, our application is behaving as expected.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!rSTZ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F579b646a-25d2-41db-a94c-fa780d04d4ac_3024x1894.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!rSTZ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F579b646a-25d2-41db-a94c-fa780d04d4ac_3024x1894.png 424w, https://substackcdn.com/image/fetch/$s_!rSTZ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F579b646a-25d2-41db-a94c-fa780d04d4ac_3024x1894.png 848w, https://substackcdn.com/image/fetch/$s_!rSTZ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F579b646a-25d2-41db-a94c-fa780d04d4ac_3024x1894.png 1272w, https://substackcdn.com/image/fetch/$s_!rSTZ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F579b646a-25d2-41db-a94c-fa780d04d4ac_3024x1894.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!rSTZ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F579b646a-25d2-41db-a94c-fa780d04d4ac_3024x1894.png" width="1456" height="912" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/579b646a-25d2-41db-a94c-fa780d04d4ac_3024x1894.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:912,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:236783,&quot;alt&quot;:&quot;Our text reverser now works.&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Our text reverser now works." title="Our text reverser now works." srcset="https://substackcdn.com/image/fetch/$s_!rSTZ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F579b646a-25d2-41db-a94c-fa780d04d4ac_3024x1894.png 424w, https://substackcdn.com/image/fetch/$s_!rSTZ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F579b646a-25d2-41db-a94c-fa780d04d4ac_3024x1894.png 848w, https://substackcdn.com/image/fetch/$s_!rSTZ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F579b646a-25d2-41db-a94c-fa780d04d4ac_3024x1894.png 1272w, https://substackcdn.com/image/fetch/$s_!rSTZ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F579b646a-25d2-41db-a94c-fa780d04d4ac_3024x1894.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Our text reverser works now!</figcaption></figure></div><h2>Conclusion</h2><p>Automated testing is a critical aspect of software development. Good tests can provide confidence that the code we ship behaves as intended. They can help us ensure that it continues to do so by guarding against regressions.</p><p>However, it's important to recognize that our tests can inadvertently mislead if not crafted well. It&#8217;s possible to create flaky, unreliable tests if we don&#8217;t understand our tools well.</p><p>Through an exploration of asynchronous testing using Testing Library's <code>waitFor</code> function, we've uncovered a possible pitfall: the failure to await the returned Promise, leading to undetected errors and false positives in test results.</p><p>By ensuring proper utilization of <code>waitFor</code>&#8212;either through <code>async/await</code> or <code>.then</code> syntax&#8212;we can accurately capture asynchronous behavior and detect errors effectively. We can have true confidence in our tests and our code.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.biodigitaljazz.tech/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Biodigital Jazz! If you like what you see, please subscribe to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>We could also use <a href="https://testing-library.com/docs/dom-testing-library/api-async/#findby-queries">findByText</a>. However, in this example, <code>waitFor</code> more clearly illustrates the point. And it more closely matches the flaky test we encountered in our production application.</p></div></div>]]></content:encoded></item><item><title><![CDATA[[1] From Music Theory Professor to Data Analyst - Mastering the Art of Career Transitions]]></title><description><![CDATA[With guest, James DiNardo]]></description><link>https://www.biodigitaljazz.tech/p/podcast-1-from-music-theory-professor-to</link><guid isPermaLink="false">https://www.biodigitaljazz.tech/p/podcast-1-from-music-theory-professor-to</guid><dc:creator><![CDATA[Tim Reynolds]]></dc:creator><pubDate>Tue, 20 Jun 2023 07:06:00 GMT</pubDate><enclosure url="https://api.substack.com/feed/podcast/128136161/0e63697b2a40b10d1e265397986ba958.mp3" length="0" type="audio/mpeg"/><content:encoded><![CDATA[<p>In the inaugural episode of the Biodigital Jazz Podcast, I interview my friend and colleague, James DiNardo. James shares his journey of completing a Ph.D. in Music Theory, teaching at the college level, then reinventing himself and transitioning to a career in data analytics. </p><p>Along the way, James shares what he&#8217;s learned about embracing new challenges, cultivating a beginner&#8217;s mindset, and taking the calculated risks required to make a career transition.</p><p>James is currently a Data Analyst at <a href="https://www.ramseysolutions.com/">Ramsey Solutions</a>.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.biodigitaljazz.tech/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading (and listening to) Biodigital Jazz! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.biodigitaljazz.tech/p/podcast-1-from-music-theory-professor-to?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.biodigitaljazz.tech/p/podcast-1-from-music-theory-professor-to?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p>]]></content:encoded></item><item><title><![CDATA[How to Have Better One-on-Ones ]]></title><description><![CDATA[I regularly have one-on-one meetings. That is, regular check-ins with some of my peers, or my direct supervisor. But sometimes, they aren't as productive as I'd like. Here's a tip on how to fix that.]]></description><link>https://www.biodigitaljazz.tech/p/how-to-have-better-one-on-ones</link><guid isPermaLink="false">https://www.biodigitaljazz.tech/p/how-to-have-better-one-on-ones</guid><dc:creator><![CDATA[Tim Reynolds]]></dc:creator><pubDate>Tue, 13 Jun 2023 11:30:59 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc2d24eec-57b5-4ff5-92bb-bcab8294595e_800x799.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I regularly have one-on-one meetings. That is, regular check-ins with some of my peers, or my direct supervisor.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!1YDF!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc2d24eec-57b5-4ff5-92bb-bcab8294595e_800x799.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!1YDF!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc2d24eec-57b5-4ff5-92bb-bcab8294595e_800x799.png 424w, https://substackcdn.com/image/fetch/$s_!1YDF!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc2d24eec-57b5-4ff5-92bb-bcab8294595e_800x799.png 848w, https://substackcdn.com/image/fetch/$s_!1YDF!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc2d24eec-57b5-4ff5-92bb-bcab8294595e_800x799.png 1272w, https://substackcdn.com/image/fetch/$s_!1YDF!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc2d24eec-57b5-4ff5-92bb-bcab8294595e_800x799.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!1YDF!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc2d24eec-57b5-4ff5-92bb-bcab8294595e_800x799.png" width="396" height="395.505" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c2d24eec-57b5-4ff5-92bb-bcab8294595e_800x799.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:799,&quot;width&quot;:800,&quot;resizeWidth&quot;:396,&quot;bytes&quot;:847313,&quot;alt&quot;:&quot;Monkey employee in 1:1 with manager&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Monkey employee in 1:1 with manager" title="Monkey employee in 1:1 with manager" srcset="https://substackcdn.com/image/fetch/$s_!1YDF!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc2d24eec-57b5-4ff5-92bb-bcab8294595e_800x799.png 424w, https://substackcdn.com/image/fetch/$s_!1YDF!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc2d24eec-57b5-4ff5-92bb-bcab8294595e_800x799.png 848w, https://substackcdn.com/image/fetch/$s_!1YDF!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc2d24eec-57b5-4ff5-92bb-bcab8294595e_800x799.png 1272w, https://substackcdn.com/image/fetch/$s_!1YDF!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc2d24eec-57b5-4ff5-92bb-bcab8294595e_800x799.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Which one am I? &#129300;</figcaption></figure></div><p>We talk about work, what&#8217;s going on, how it&#8217;s going. We also talk about life. It&#8217;s an opportunity to build trust and get to know each other a bit outside the context of work.</p><p>One-on-ones are a great way to build trust, get help, and exercise accountability. But sometimes, getting through them can be a struggle.</p><p>I&#8217;ve been in one-on-ones that can meander. They can be awkward. They can be dominated by small talk. Or have no personal touch at all. Or they are dominated by one side, creating a monologue instead of a dialogue. And at the end of it, sometimes you can wonder what was accomplished.</p><p>How do you fix this?</p><p>The best place to start is simple&#8230;. make a plan. Have an agenda.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.biodigitaljazz.tech/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Biodigital Jazz! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p>In <a href="https://amzn.to/3IXoXbA">Trillion Dollar Coach</a>, the authors describe Bill Campbell&#8217;s approach to 1:1s, summarized as &#8220;5 Words on a Whiteboard.&#8221; If you happen to snag a copy of the book, you can read about it from pages 46-50.</p><p>The template is pretty straightforward. Each party prepares five topics to discuss. If you have a whiteboard available, each participant writes their five topics. Then, they can merge them into a structured agenda.</p><p>In the case of a manager-employee (or mentor-mentee as the case may be) meeting, the employee should list their topics <em>first</em>. There are a few benefits to this:</p><ul><li><p>This type of 1:1 should primarily be for the benefit of the employee. Their topics take precedence. Not a simple status report for the manager.</p></li><li><p>This allows the opportunity for the manager to gain some insight into what is on the employee&#8217;s mind. What are they thinking about? How do they prioritize? This can be seized upon as a coaching moment in itself.</p></li><li><p>Some managers can steamroll the interaction without giving the employee a chance to address topics they need help with or that otherwise need attention.</p></li><li><p>If the manager goes first, this can put the employee in the position to mindlessly agree with the priorities as set by the boss and robs them of the chance for them to apply some critical thinking, and share what they think should be prioritized.</p></li></ul><p>It doesn&#8217;t have to be five topics exactly. The point is to have some structure and put in some preparation.</p><p>Come in with just one topic. Even that would be an improvement.</p><p>Exercise just a little forethought and I think you&#8217;ll find the next 1:1 you&#8217;re in will go much more smoothly. </p><p>You&#8217;ll get something out of it. </p><p>And you might even enjoy it just a bit.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.biodigitaljazz.tech/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Biodigital Jazz! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[How to Figure Stuff Out]]></title><description><![CDATA[Problem-Solving for Software Engineers]]></description><link>https://www.biodigitaljazz.tech/p/how-to-figure-stuff-out</link><guid isPermaLink="false">https://www.biodigitaljazz.tech/p/how-to-figure-stuff-out</guid><dc:creator><![CDATA[Tim Reynolds]]></dc:creator><pubDate>Fri, 03 Mar 2023 12:55:08 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/496c699b-d274-42a7-a9aa-d3a1735b17c2_420x300.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>A few weeks ago I was looking through our team&#8217;s backlog. The top ticket was filled out something like this:</p><p><strong>Title:</strong></p><p>Update this really awesome API with a new field for a really cool feature.</p><p><strong>Description:</strong></p><p>Add the field &#8220;email&#8221; to <em>really-awesome-api-service</em>, so that we can expose it for editing to the user.</p><p><strong>Technical notes:</strong></p><ol><li><p>Add the new field to the Data Object</p></li><li><p>You might need to update the database</p></li><li><p>Update the controller to support CRUD operations on the new field</p></li><li><p>Write test cases</p></li></ol><p>I&#8217;ve seen much less detailed tickets. In fact, this one was pretty good in my experience.</p><p>So what&#8217;s the problem? What kept me from just doing the thing?</p><p>I didn&#8217;t know how to do it.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!rgBb!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02101be1-8bc4-4f16-85bb-d60c1810426b_2078x1200.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!rgBb!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02101be1-8bc4-4f16-85bb-d60c1810426b_2078x1200.png 424w, https://substackcdn.com/image/fetch/$s_!rgBb!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02101be1-8bc4-4f16-85bb-d60c1810426b_2078x1200.png 848w, https://substackcdn.com/image/fetch/$s_!rgBb!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02101be1-8bc4-4f16-85bb-d60c1810426b_2078x1200.png 1272w, https://substackcdn.com/image/fetch/$s_!rgBb!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02101be1-8bc4-4f16-85bb-d60c1810426b_2078x1200.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!rgBb!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02101be1-8bc4-4f16-85bb-d60c1810426b_2078x1200.png" width="728" height="420.5" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/02101be1-8bc4-4f16-85bb-d60c1810426b_2078x1200.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:false,&quot;imageSize&quot;:&quot;normal&quot;,&quot;height&quot;:841,&quot;width&quot;:1456,&quot;resizeWidth&quot;:728,&quot;bytes&quot;:162088,&quot;alt&quot;:&quot;Man at computer thinking.&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Man at computer thinking." title="Man at computer thinking." srcset="https://substackcdn.com/image/fetch/$s_!rgBb!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02101be1-8bc4-4f16-85bb-d60c1810426b_2078x1200.png 424w, https://substackcdn.com/image/fetch/$s_!rgBb!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02101be1-8bc4-4f16-85bb-d60c1810426b_2078x1200.png 848w, https://substackcdn.com/image/fetch/$s_!rgBb!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02101be1-8bc4-4f16-85bb-d60c1810426b_2078x1200.png 1272w, https://substackcdn.com/image/fetch/$s_!rgBb!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02101be1-8bc4-4f16-85bb-d60c1810426b_2078x1200.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Me at work&#8230;</figcaption></figure></div><p>I went to the GitHub link for the source code. I perused it for a bit and realized it was a Kotlin service.</p><p>I don&#8217;t know how to program in Kotlin.</p><p>I knew almost nothing about this application, including the tech stack it was built on.</p><p>Spring? Maven? Hibernate?</p><p>I have barely touched any of them.</p><p>Not only that, I had no idea what database needed to be updated. Or, as the ticket hinted at, if it even needed to be updated.</p><p>There&#8217;s a lot I didn&#8217;t know.</p><p>So, I wrung my hands, gave up, and cried in the corner, while rocking in the fetal position.</p><p>Just kidding&#8230;</p><p>As engineers, this is exactly what we&#8217;re paid to do. Encounter something we don&#8217;t understand or know. And figure it out.</p><p>So here&#8217;s how I figured it out.</p><p>First, I started with what I did know:</p><ul><li><p>I knew this was a REST API, with a database behind it for persistence. While I haven&#8217;t worked in this kind of tech stack before, I know the concepts from studying and working in similar applications.</p></li><li><p>The ticket mentioned a Data Object. I know that&#8217;s a pretty common pattern for ORMs (Object Relational Mappers). It would make sense that I would have to find and edit this part of the code.</p></li><li><p>I knew that Spring uses the MVC pattern for web APIs. I understand how that pattern works, so it gives me a frame of reference as I navigate the code.</p></li><li><p>I&#8217;ve worked in .NET, Ruby on Rails, and a handful of other frameworks implementing essentially the same thing. At the end of the day, it involves making migrations for the database to the new schema, updating the models and entities that talk to that database, then updating the controller to provide the methods to view and edit that information. There might be some nuance, and some middleware to take into account, but those are the bones of this kind of task.</p></li></ul><p>So I had a rough idea of the big picture subtasks, but what I didn&#8217;t know was&#8230;</p><ul><li><p>How do I make the migration to add the new field (changes to the underlying database schema)?</p></li><li><p>Are these migrations stored in scripts anywhere?</p></li><li><p>Is there a special command I need to run to do those scripts? or sequence of commands?</p></li><li><p>What database is this connected to?</p></li><li><p>Do I need to directly connect to this DB and make any changes there, or can it be done completely from the application code?</p></li><li><p>Are there any other tables or relationships that need to be accounted for? Any dependencies I could break in the process?</p></li><li><p>How do I even set up and run this project?</p></li></ul><p>So how did I begin to answer these questions?</p><p>First, I searched through the code for anything related to the data object. I found the relevant code, and lo and behold, it had some fields I recognized. It seemed simple enough to copy the code from one field and modify it to suit my needs.</p><p>Then, I searched for an example field name throughout the entire project. For our purposes, let&#8217;s say I used the field &#8220;FirstName&#8221; to base my work on. I found all references to &#8220;FirstName,&#8221; and this painted a picture for me of all of the bits of code I&#8217;d have to amend for my new use case.</p><p>Now, I had to figure out what database the app connected to. I knew from experience that this is usually defined in some kind of configuration file, and was able to find that.</p><p>Next, I looked through the project&#8217;s README to see if there were any instructions on setting up the project. There were, so I proceeded to get the app up and running on my machine.</p><p>Now, I had what I thought was all of the relevant code updated, and I had the project set up. However, I still couldn&#8217;t figure out how to migrate the data to the new schema. This is when I resorted to reaching out for help.</p><p>I looked through the project's commit history and found the person who most recently did work there. I shot a message to that person.</p><p>I couldn&#8217;t get any further, so I took a two-hour break and scrolled through Instagram until he could respond.</p><p>I&#8217;m just kidding again.</p><p>I didn&#8217;t want to let that block me, so I kept digging and trying to think of how I could get this information.</p><p>Then it hit me&#8230;</p><p>This seems like a pretty typical task that&#8217;s probably been done before&#8230; There&#8217;s probably an old pull request similar to the work I&#8217;m doing now. So I searched all of the closed PRs for the text &#8220;add field.&#8221; And sure enough, several results popped up.</p><p>I found a good example and it highlighted to me a few things I did right, and some things I had overlooked.</p><p>I still didn&#8217;t have everything I needed though. I still needed help. So I amended my questions to my coworker with the new information I had. I was able to ask more detailed, explicit questions, and he was able to give me much more direct, simple, and higher-quality answers with this new information.</p><p>We weren&#8217;t ready to activate on the work yet. So, I updated the ticket with a summary of what I had learned. That way, the next engineer to take on the work would start from a much better position.</p><p>As I reflected on my day, I realized something. I do this <em>all </em>the time. </p><p>There&#8217;s a pattern here.</p><p>The following is my best attempt to abstract what I did into a step-by-step process:</p><ol><li><p>Start with what you know.</p></li><li><p>Identify what you don&#8217;t know.</p></li><li><p>Craft the right questions to ask to learn what you don&#8217;t know.</p></li><li><p>Figure out an order that makes sense to ask those questions in. Some answers to questions are dependent on answers to previous questions. There may be an inherent order to work in.</p></li><li><p>Ask those questions via whatever methods are available&#8230;</p><ul><li><p>Read through the source code.</p></li><li><p>Read through the documentation.</p></li><li><p>Review language and tooling documentation.</p></li><li><p>Search Google.</p></li><li><p>Ask ChatGPT &#128540;.</p></li><li><p>Ask a human being.</p></li><li><p>Get direct help by pairing with a person.</p></li></ul></li><li><p>Repeat the process, refining the details until you have clear action steps to take that get you closer to solving your problem.</p></li><li><p>Solve problems one by one. As you solve, new unknowns will likely reveal themselves. Apply the same process to figure these new problems out.</p></li></ol><p>Fundamentally, this is the essence of what I have done as an engineer for my entire career. Repeating this process and variations of it as I learned more and encountered new, more challenging problems.</p><p>As you advance in your engineering career, the problems you tackle will be less well-defined, more ambiguous, and more challenging across several dimensions.</p><p>But the fundamental process of problem-solving remains the same. If you master that process and build those problem-solving muscles, you&#8217;ll unlock the ability to tackle more interesting, difficult problems.</p><p>And you&#8217;ll get to experience the rewards that come with solving them.</p><p>Have fun.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.biodigitaljazz.tech/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Biodigital Jazz! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[Product Discovery is Like Walking in the Woods, in Fog, at Night]]></title><description><![CDATA[On New Year&#8217;s day, four other men and I set off on a backpacking trip to hike a section of the Appalachian Trail.]]></description><link>https://www.biodigitaljazz.tech/p/product-discovery-is-like-walking</link><guid isPermaLink="false">https://www.biodigitaljazz.tech/p/product-discovery-is-like-walking</guid><dc:creator><![CDATA[Tim Reynolds]]></dc:creator><pubDate>Mon, 23 Jan 2023 01:21:45 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!JgEV!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff7c8d1c2-fcf2-43f5-9fc9-320b318cfaed_4000x3000.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!JgEV!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff7c8d1c2-fcf2-43f5-9fc9-320b318cfaed_4000x3000.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!JgEV!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff7c8d1c2-fcf2-43f5-9fc9-320b318cfaed_4000x3000.jpeg 424w, https://substackcdn.com/image/fetch/$s_!JgEV!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff7c8d1c2-fcf2-43f5-9fc9-320b318cfaed_4000x3000.jpeg 848w, https://substackcdn.com/image/fetch/$s_!JgEV!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff7c8d1c2-fcf2-43f5-9fc9-320b318cfaed_4000x3000.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!JgEV!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff7c8d1c2-fcf2-43f5-9fc9-320b318cfaed_4000x3000.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!JgEV!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff7c8d1c2-fcf2-43f5-9fc9-320b318cfaed_4000x3000.jpeg" width="1456" height="1092" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f7c8d1c2-fcf2-43f5-9fc9-320b318cfaed_4000x3000.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1092,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:2288610,&quot;alt&quot;:&quot;Dark forrest trail.&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Dark forrest trail." title="Dark forrest trail." srcset="https://substackcdn.com/image/fetch/$s_!JgEV!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff7c8d1c2-fcf2-43f5-9fc9-320b318cfaed_4000x3000.jpeg 424w, https://substackcdn.com/image/fetch/$s_!JgEV!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff7c8d1c2-fcf2-43f5-9fc9-320b318cfaed_4000x3000.jpeg 848w, https://substackcdn.com/image/fetch/$s_!JgEV!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff7c8d1c2-fcf2-43f5-9fc9-320b318cfaed_4000x3000.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!JgEV!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff7c8d1c2-fcf2-43f5-9fc9-320b318cfaed_4000x3000.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Photo by <a href="https://unsplash.com/@spencer_demera?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Spencer DeMera</a> on <a href="https://unsplash.com/photos/_AQM83YhL1w?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></figcaption></figure></div><p>On New Year&#8217;s day, four other men and I set off on a backpacking trip to hike a section of the Appalachian Trail. We started from Woody Gap, near Helen, Georgia, and eventually ended the trip by getting picked up on Highway 75, just past Blue Mountain Shelter.</p><p>We hiked about 32 miles over the course of three days.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!4ufk!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67e42b43-eb3e-4ecc-b20d-0728af94bcf1_2156x1446.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!4ufk!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67e42b43-eb3e-4ecc-b20d-0728af94bcf1_2156x1446.png 424w, https://substackcdn.com/image/fetch/$s_!4ufk!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67e42b43-eb3e-4ecc-b20d-0728af94bcf1_2156x1446.png 848w, https://substackcdn.com/image/fetch/$s_!4ufk!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67e42b43-eb3e-4ecc-b20d-0728af94bcf1_2156x1446.png 1272w, https://substackcdn.com/image/fetch/$s_!4ufk!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67e42b43-eb3e-4ecc-b20d-0728af94bcf1_2156x1446.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!4ufk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67e42b43-eb3e-4ecc-b20d-0728af94bcf1_2156x1446.png" width="1456" height="977" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/67e42b43-eb3e-4ecc-b20d-0728af94bcf1_2156x1446.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:977,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:5901393,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!4ufk!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67e42b43-eb3e-4ecc-b20d-0728af94bcf1_2156x1446.png 424w, https://substackcdn.com/image/fetch/$s_!4ufk!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67e42b43-eb3e-4ecc-b20d-0728af94bcf1_2156x1446.png 848w, https://substackcdn.com/image/fetch/$s_!4ufk!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67e42b43-eb3e-4ecc-b20d-0728af94bcf1_2156x1446.png 1272w, https://substackcdn.com/image/fetch/$s_!4ufk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67e42b43-eb3e-4ecc-b20d-0728af94bcf1_2156x1446.png 1456w" sizes="100vw"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Our AT hike route.</figcaption></figure></div><p>By the end of the trip, we were all hurting, and soaking wet. We were basically hiking in a cloud for the last two days. I can still feel the cold, floating water particles brushing against my skin.</p><p>And that was in the interludes between actual rain.</p><p>Towards the end of day two, it was getting dark fast. One of my hiking buddies and I were trailing behind the others, and we still had well over a mile to go by the time night had settled in. We ended up hiking in the dark for almost an hour.</p><p>Yep, it was only an hour. BUT, this was my first time doing any kind of night hiking. My headlamp was dim. And as though all that wasn&#8217;t bad enough, we were still in thick fog. So both the light from my lamp and my friend&#8217;s headlamp was being dispersed and reflected in all directions. We maybe had at best a couple of feet of visibility on the ground in front of us.</p><p>Cold, wet, and not exactly sure exactly how far the shelter was, we had been hiking almost 14 miles for the day, and my feet and legs were blistered and beat.</p><p>We were less seeing our way down the trail, and more <em>feeling</em> our way.</p><p>And at that moment, we weren&#8217;t exactly sure how long we&#8217;d be out there.</p><p>As I&#8217;ve been reflecting on this experience, I&#8217;ve realized something&#8230;</p><p>The way I felt stumbling and feeling my way through that trail for an hour, only seeing a foot or two in front of me, is the same way I&#8217;ve felt at work over the last few months.</p><p>Why?</p><p>We&#8217;ve been in a season of product discovery.</p><p>And it&#8217;s messy.</p><p>For much of my career, I&#8217;ve had more-or-less well defined problems AND solutions put in front of me to work on.</p><p>&#8220;Program X, so that we can do Y.&#8221;</p><p>Or&#8230;</p><p>&#8220;Help build this widget, so that we can make money.&#8221;</p><p>That&#8217;s a slightly tongue-in-cheek description. But still, I think a fairly accurate summary of most software engineering assignments.</p><p>This time, however, my team has been given a <em>customer problem</em>. No solution prescribed. We get to come up with that part.</p><p>And just like that hour in the dark on the trail, it&#8217;s been messy, very touch-and-go, a little anxiety-inducing.</p><p>And also, just like that experience on the trail, it&#8217;s pretty dang cool.</p><p>We&#8217;re in a problem space where we have extremely limited visibility. So we&#8217;re relying on a lot of qualitative feedback to get signals that we&#8217;re going in the right direction. We know where we need to go. It&#8217;s just really hard to see how to get there.</p><p>And as we&#8217;re going, we&#8217;re building more sophisticated tools and solutions to track and gather data, so that we can build more confidence as we go.</p><p>It&#8217;s kinda&#8217; like building a better headlamp while you&#8217;re walking down a dark path.</p><p>And thankfully, we haven&#8217;t had to build our own trail to get to our destination. Others have gone before us. We&#8217;ve been relying heavily on <a href="https://amzn.to/3kyk2EW">Teresa Torres&#8217; Continuous Discovery Habits</a> to give us tools and language to stay on course. It&#8217;s a definite must-read if you&#8217;re building digital products.</p><p>My friend and I kept going. One step in front of the other. And finally, we heard our friends calling to us. And we eventually saw light from the campsite in the distance.</p><p>We made it.</p><p>All we had to do was keep going.</p><p>And at work, through all of the uncertainty that&#8217;s come with working on this problem, we&#8217;ve identified and are beginning to deliver a solution that will take a step towards tackling it and providing value for our customers.</p><p>Now off to find the next solution.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.biodigitaljazz.tech/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Biodigital Jazz! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[Dealing with Burnout]]></title><description><![CDATA[The key to managing stress and staving off the onset of burnout is maintaining some fundamental habits. And reestablishing them when they get out of wack]]></description><link>https://www.biodigitaljazz.tech/p/dealing-with-burnout</link><guid isPermaLink="false">https://www.biodigitaljazz.tech/p/dealing-with-burnout</guid><dc:creator><![CDATA[Tim Reynolds]]></dc:creator><pubDate>Tue, 23 Aug 2022 11:30:40 GMT</pubDate><enclosure url="https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/358067c6-7521-43cb-9b9d-3d596f9d25b8_420x300.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!IjwS!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F272662af-8ce5-4395-b05c-b9f2191e1df1_1630x772.webp" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!IjwS!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F272662af-8ce5-4395-b05c-b9f2191e1df1_1630x772.webp 424w, https://substackcdn.com/image/fetch/$s_!IjwS!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F272662af-8ce5-4395-b05c-b9f2191e1df1_1630x772.webp 848w, https://substackcdn.com/image/fetch/$s_!IjwS!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F272662af-8ce5-4395-b05c-b9f2191e1df1_1630x772.webp 1272w, https://substackcdn.com/image/fetch/$s_!IjwS!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F272662af-8ce5-4395-b05c-b9f2191e1df1_1630x772.webp 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!IjwS!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F272662af-8ce5-4395-b05c-b9f2191e1df1_1630x772.webp" width="728" height="345" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/272662af-8ce5-4395-b05c-b9f2191e1df1_1630x772.webp&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:false,&quot;imageSize&quot;:&quot;normal&quot;,&quot;height&quot;:690,&quot;width&quot;:1456,&quot;resizeWidth&quot;:728,&quot;bytes&quot;:234102,&quot;alt&quot;:&quot;This is fine dog meme.&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/webp&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="This is fine dog meme." title="This is fine dog meme." srcset="https://substackcdn.com/image/fetch/$s_!IjwS!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F272662af-8ce5-4395-b05c-b9f2191e1df1_1630x772.webp 424w, https://substackcdn.com/image/fetch/$s_!IjwS!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F272662af-8ce5-4395-b05c-b9f2191e1df1_1630x772.webp 848w, https://substackcdn.com/image/fetch/$s_!IjwS!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F272662af-8ce5-4395-b05c-b9f2191e1df1_1630x772.webp 1272w, https://substackcdn.com/image/fetch/$s_!IjwS!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F272662af-8ce5-4395-b05c-b9f2191e1df1_1630x772.webp 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>In a group discussion at work a few days ago, one of my teammates asked the question, &#8220;how do you deal with burnout?&#8221;</p><p>I&#8217;ve been thinking about this question a lot lately. I feel like I&#8217;ve been approaching burnout myself.</p><p>It&#8217;s been a very busy summer. With a lot of change for all of us on the team. And a lot going on personally as well.</p><p>I think we all experience burnout in some shape or form that&#8217;s unique to us at one point or another.</p><p>Frankly, I haven&#8217;t been writing a lot lately because I&#8217;ve simply felt too overwhelmed to mess with it. So, I figure what better way to get back into writing than to address this very thing.</p><h2>Am I Burned Out?</h2><p>How do I know I&#8217;m getting burned out?</p><p>I begin to notice a few things just aren&#8217;t quite right. It usually looks like some combination of the following, in no particular order:</p><ul><li><p>I&#8217;m more irritable. Things that I might normally let go just irritate me more.</p></li><li><p>I feel tight, and tense constantly. I especially feel this in my back, shoulders, and hands.</p></li><li><p>My sleep quality is trash. Even when I can sleep, it seems shallow, less deep. I tend to wake up two or three times in the night.</p></li><li><p>I wake up thinking about upcoming meetings or conversations.</p></li><li><p>When I get home, I just feel thoroughly exhausted. I would rather just go to bed than do&#8230; anything.</p></li><li><p>Activities that I enjoy just seem like a chore. I have no intrinsic motivation.</p></li><li><p>I feel emotionally numb most of the time, with random outbursts of emotion. Crazy stuff like crying at a commercial with a puppy or something inane like that.</p></li><li><p>Instead of using leisure time working on productive things (e.g. this newsletter) I struggle to bring myself to do anything more than drink beer and watch Netflix. And no, that&#8217;s not bad once in a while. But there is a limit&#8230;</p></li><li><p>I struggle to focus and make decisions.</p></li><li><p>Loss of connection to the sense of meaning in my work or other pursuits.</p></li></ul><p>I&#8217;ve been experiencing all of these to some degree or another over the last few months.</p><p>Certainly, there has been a lot going on that is out of my control. But there are some things that <em>I am in control</em> of that I haven&#8217;t been perfectly consistent on or disciplined about.</p><h2>The Disciplines</h2><p>There are a few cornerstone habits, or disciplines, in my life that I know if I am inconsistent with, everything else is thrown off.</p><p>These disciplines are:</p><ul><li><p>Exercise</p></li><li><p>Eating well</p></li><li><p>Sleeping well</p></li><li><p>Spiritual connection</p></li></ul><p>I&#8217;m sure if you&#8217;ve read any other article on this topic, this list isn&#8217;t a surprise.</p><p>Just open up another tab, right now, and search &#8220;burnout.&#8221; I guarantee the top results will talk about sleep, exercise, diet, and probably something related to the spiritual, or social connection at a minimum.</p><p>But the fact is, when I&#8217;m feeling burned out and I do a little reflection, I don&#8217;t have to go too far back to notice that I haven&#8217;t been consistent with maintaining one of these disciplines. Or all of them.</p><p>So for me, the key to managing stress and staving off the onset of burnout is maintaining these habits. And reestablishing them when they get out of wack.</p><p>It comes down to fundamentals.</p><p><strong>Exercise</strong></p><p>Exercise releases a lot of feel-good chemicals.<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a></p><p>Many of us have been there. In the middle of a workout, it seems like torture. But afterward, we feel amazing!</p><p>I like to do this after work. When I&#8217;ve had a hard day, I have to get out of my mind and into my body.</p><p>There&#8217;s nothing like a hard workout to help me do that.</p><p>It helps me release all of the tension that has built up from a desk job. And that workout creates a boundary that forces me to separate work time from personal time.</p><p>Aside from that, it gives me the strength to do the activities I enjoy. And just being able to walk up the stairs without losing my breath gives me confidence.</p><p>The problem is that I might start the week off great. I work out for an hour Monday evening.</p><p>Then, by the time Tuesday comes around, or whatever the next day is in my training schedule, It seems impossible just to get my sneakers on.</p><p><strong>Eating Well</strong></p><p>When I eat like trash, I feel like trash.</p><p>When I&#8217;m stressed out, I tend to gravitate towards fried food, sweats, and more beer.</p><p>When I go to lunch and I have the choice between the salad or a chicken parmesan sub&#8230; I&#8217;m probably going for the sub. It just feels better&#8230; </p><p>&#8230; for about an hour.</p><p>Then I&#8217;m bloated and want to take a nap for the rest of the afternoon.</p><p>And forget working out when I get home.</p><p><strong>Sleeping Well</strong></p><p>This is the most challenging one for me.</p><p>It&#8217;s very difficult to maintain a consistent bedtime, and usually, that translates to sleeping later, which throws my whole morning routine off, and then I get to work already feeling behind and stressed.</p><p>This is probably the one discipline that If I could fix and be consistent with, it would change all the rest.</p><p><strong>Spiritual Connection</strong></p><p>For me, this looks like studying and praying every morning. And meditating (often through journaling). Keeping a daily connection with God. </p><p>I need the help.</p><p>Even if you&#8217;re not religious, you may recognize the value in some sort of practice that puts you in a position to think about your life. To reflect and evaluate.</p><p>All of these disciplines are interconnected.</p><p>If I&#8217;m sleeping well, I can get up in time to study, pray and journal.</p><p>When I&#8217;ve studied, prayed, and journaled, I&#8217;ve had space to think, process whatever is going on, and look at things from a bigger perspective. Even with some gratitude.</p><p>Once that&#8217;s in place, I&#8217;m much calmer throughout the day. More present. I&#8217;m thinking about my actions, my words. I&#8217;m responding instead of reacting. </p><p>Since I&#8217;ve shown up from that more calm, peaceful, present place, I have less to be anxious or worry about. So I sleep better.</p><p>That gives me the energy to exercise at the end of the day. When I exercise, I crave water and healthier food. It&#8217;s just that much easier to eat well. Because I&#8217;ve eaten well, my mood and emotions are better regulated. Which in turn helps how kind, present and sharp I can be throughout the day.</p><p>Which helps me sleep.</p><p>And on, and on&#8230;</p><p>These disciplines form a framework around which the other parts of my life hang. And when any or all of them falter, the whole thing gets out of wack.</p><h2>No Silver Bullet</h2><p>None of these disciplines is a silver bullet.</p><p>Going for a run will not take away the need for that hard conversation you keep putting off.</p><p>They don&#8217;t automatically take away the stressful environment you&#8217;re in, or the tasks that you have to keep up with.</p><p>But, again these practices form a foundation from which you can be well equipped to handle and cope with your everyday stressors. And perhaps even find creative solutions to your problems.</p><h2>What&#8217;s Stopping Us?</h2><p>So I just told you that if you&#8217;re at the edge of burning out, you should sleep more, exercise, eat better, and meditate.</p><p>Helpful.</p><p>I&#8217;m just as much telling myself this.</p><p>I know what to do.</p><p>We know that none of this is new. The habits needed to cope with stress and burnout seem to be well known.</p><p>So if we know these are the things that are good for us, why don&#8217;t we just do them?</p><p>There is something innate to human nature that <em>resists </em>anything beneficial for us. Anything that doesn&#8217;t result in instant gratification. Even when we know that it will be good for us in the long term.</p><p>In <em>The War of Art,</em><a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-2" href="#footnote-2" target="_self">2</a> Steven Pressfield talks at length about this. Mostly, within the context of creative work. But it applies all the same to any worthwhile endeavor. </p><p>He personifies it as <em>Resistance</em>. As though it were an entity. Except, this entity has no motive. It&#8217;s simply a force of nature. Not too unlike the <em>Law of Entropy.</em><a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-3" href="#footnote-3" target="_self">3</a></p><p>So recognizing that there is an innate pull within us to avoid what&#8217;s good for us, how can we counteract that pull? How do we establish the disciplines that are necessary to start coping with burnout?</p><p>I&#8217;ll address that in Part II of this series on dealing with burnout.</p><p>But for now&#8230;</p><p>I&#8217;m going to bed.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.biodigitaljazz.tech/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">To make sure you get the next installment, consider becoming a subscriber to BiodigitalJazz.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>https://www.webmd.com/depression/guide/exercise-depression </p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-2" href="#footnote-anchor-2" class="footnote-number" contenteditable="false" target="_self">2</a><div class="footnote-content"><p>https://amzn.to/3Cqopsmv</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-3" href="#footnote-anchor-3" class="footnote-number" contenteditable="false" target="_self">3</a><div class="footnote-content"><p>https://www.livescience.com/50941-second-law-thermodynamics.html </p><p></p></div></div>]]></content:encoded></item><item><title><![CDATA[The One Percent Rule]]></title><description><![CDATA[One of the most fun things about working in technology is constant change. Also, one of the most frustrating things about working in technology is constant change. How do you keep up without going crazy?]]></description><link>https://www.biodigitaljazz.tech/p/the-one-percent-rule</link><guid isPermaLink="false">https://www.biodigitaljazz.tech/p/the-one-percent-rule</guid><dc:creator><![CDATA[Tim Reynolds]]></dc:creator><pubDate>Tue, 17 May 2022 11:15:45 GMT</pubDate><enclosure url="https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/cb05da1e-fb5d-40e1-9c64-0c7b899a5def_2196x1404.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>One of the most exciting and fun things about working in technology is the fact that things never stay the same and there&#8217;s always something new to learn.</p><p>Also, one of the most overwhelming, stressful, and yes, even maddeningly frustrating things about working in technology is the fact that things never stay the same and there&#8217;s always something new to learn.</p><p><a href="https://amzn.to/3LhVs2P">Your cheese is constantly being moved.</a><a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a></p><p>So how do you manage the constant stream of change? The constant need to learn a new programming language? A new library? A new framework? A new design pattern? A new tool?</p><p>How do you keep up without going crazy?</p><p>How do you sustainably grow in your craft?</p><p>Previously, I&#8217;ve written about the <a href="https://www.biodigitaljazz.tech/p/how-to-get-a-great-return-on-time">fundamentals of the craft</a>, which can help form a foundation for growth. And, I&#8217;ve shared <a href="https://www.biodigitaljazz.tech/p/the-most-important-hour-for-growth">one of my favorite techniques to help manage the time needed to learn</a>.</p><p>So while I&#8217;m at it, here&#8217;s another thought:</p><blockquote><p>Just try to get one percent better today than you were yesterday.</p></blockquote><p>That&#8217;s it.</p><p>This idea is not very original. In fact, A lot has already been written about the &#8220;one-percent rule&#8221; all over the internet. I don&#8217;t want to repeat <em>all</em> of that, so here are a few of my favorite articles on the topic for further reading:</p><ul><li><p><a href="https://jamesclear.com/the-1-percent-rule">The 1 Percent Rule: Why a Few People Get Most of the Rewards </a></p></li><li><p><a href="https://jamesclear.com/continuous-improvement">Continuous Improvement: How It Works and How to Master It </a></p></li><li><p><a href="https://www.artofmanliness.com/character/behavior/get-1-better-every-day-the-kaizen-way-to-self-improvement">Get 1% Better Every Day: The Kaizen Way to Self-Improvement </a></p></li></ul><p>What I do want to do is share a few practical ideas for how to implement this rule as a technologist.</p><p>But quickly, why one percent?</p><p>First, it&#8217;s manageable. </p><p>Saying you need to learn C++, for example, is a good goal. However, it&#8217;s so broad and so overwhelming that it&#8217;s almost useless as a target.</p><p>But, saying you need to learn C++, then asking yourself, &#8220;what&#8217;s one tiny thing I can do to get the ball rolling on this today?&#8221; is useful. Maybe that one tiny thing is writing &#8220;hello world.&#8221; Or maybe that&#8217;s learning pointer arithmetic. It just depends on where you were yesterday.</p><p>Looking at where you were yesterday, and getting just a little bit better on any given topic feels a lot more approachable than tackling everything all at once.</p><p>Second, it&#8217;s powerful. One of the most impactful quotes I&#8217;ve seen on the topic comes from James Clear:</p><blockquote><p>If you get one percent better each day for one year, you'll end up thirty-seven times better by the time you&#8217;re done.<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-2" href="#footnote-2" target="_self">2</a></p></blockquote><p>Most of the impact and changes in your life don&#8217;t come from any singular, grand moment. They come from the tiny, incremental decisions and actions made day by day.</p><p>So with that, let&#8217;s consider an example of how this could look&#8230;</p><p>You&#8217;re a software engineer and your company is moving all of its infrastructure to the cloud. AWS (Amazon Web Services), for example. You&#8217;ve never worked in a cloud environment before. So everything is new.</p><p>Well, in this scenario, I might say to myself, &#8220;I&#8217;m going to get 1% percent better today by reading an article that provides an overview of all of the major AWS services.&#8221;</p><p>It&#8217;s day two now. Since I read that article yesterday, I now have kind of an idea of what AWS is all about in general. However, I&#8217;m still fuzzy on how my code and the work that I routinely do connects to it. But, I do know a guy in systems engineering, let&#8217;s call him &#8220;Bob,&#8221; that knows a lot about this stuff.</p><p>I say to myself, &#8220;Self, today I am going to get 1% better at my job by having a meeting with Bob and asking him how my team&#8217;s code utilizes whatever AWS products are relevant.&#8221;</p><p>It&#8217;s day three now. And now that I have a pretty good grasp on how our team&#8217;s code fits within our cloud infrastructure (thanks to that little chat with Bob yesterday), I wonder what else we could be doing with it? People keep talking about serverless computing, and I think we might be able to use this for our next project.</p><p>I start googling, and I come across AWS Lambda functions. So today, I decide I&#8217;m going to get 1% better at my job by researching Lambdas to determine if this feature  fits our use case.</p><p>It&#8217;s day four. After learning a little bit about Lambdas yesterday, I think it&#8217;s worth investing a little more time into it. So today, I&#8217;m going to get 1% better at serverless computing by going through a tutorial and setting up a Lambda myself.</p><p>I hope you can see the thread here&#8230;.</p><ul><li><p>Take inventory of where you are.</p></li><li><p>Identify the topics you need to learn about.</p></li><li><p>Keep a list of those topics. </p></li><li><p>Look up relevant learning resources; books, videos, courses, and people you work with. Have those handy.</p></li><li><p>Execute. Find a few minutes in your day to make progress. 10-15 minutes could be all you need! <a href="https://www.biodigitaljazz.tech/p/the-most-important-hour-for-growth">Doing this within the first hour is a great idea</a>!</p></li></ul><p>You could take this and reduce it to a template:</p><p>&#8220;I&#8217;m going to get 1% better today at <em>X</em> by doing/reading/watching <em>Y.</em>&#8221;</p><p>In the morning, fill that sentence in. Write it in a journal. And mark it off when you did it!</p><p>In a few months, you&#8217;ll look back at all the things you improved at and feel confident, knowing that <em>you. can. learn.</em> That you can improve. That the big, scary, uncertain things that looked impossible just a few weeks or a few months ago are now completely within your grasp.</p><p>All by consistently showing up and doing just a little. tiny. bit.</p><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p><a href="https://amzn.to/3LhVs2P">S. Johnson, </a><em><a href="https://amzn.to/3LhVs2P">Who moved my cheese? an amazing way to deal with change in your work and your life</a></em><a href="https://amzn.to/3LhVs2P">. New York: Putnam, 1998.</a></p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-2" href="#footnote-anchor-2" class="footnote-number" contenteditable="false" target="_self">2</a><div class="footnote-content"><p>J. Clear, &#8220;Continuous Improvement: How It Works and How to Master It,&#8221; <em>James Clear</em>. <a href="https://jamesclear.com/continuous-improvement">https://jamesclear.com/continuous-improvement</a> (accessed May 15, 2022).</p><p></p></div></div>]]></content:encoded></item><item><title><![CDATA[The Most Important Hour for Growth]]></title><description><![CDATA[I think that most of us would agree that growth in our field of endeavor is important. But it may not be so obvious as to how to go about it. Here's one approach that has worked for me.]]></description><link>https://www.biodigitaljazz.tech/p/the-most-important-hour-for-growth</link><guid isPermaLink="false">https://www.biodigitaljazz.tech/p/the-most-important-hour-for-growth</guid><dc:creator><![CDATA[Tim Reynolds]]></dc:creator><pubDate>Sun, 03 Apr 2022 22:00:51 GMT</pubDate><enclosure url="https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/4c0b23f3-bdaf-4773-9379-0df57aa62f5c_1920x1080.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In my last post, <a href="https://www.biodigitaljazz.tech/p/how-to-get-a-great-return-on-time">How to Get a Great Investment on Time Spent Learning</a>, I shared how important it is to practice the fundamentals of your craft. Specifically in the field of software engineering. This concept can apply much more broadly, far beyond just software.</p><p>I think that most of us would agree that growth in our field of endeavor is important. But it may not be so obvious as to how to go about it.</p><p>It takes dedicated time and focus. It&#8217;s helpful to have a system to make it easier. In this post, I want to share my number one technique for learning and growth.</p><p>Several years ago I was in Charlotte, North Carolina staying with friends for an event. The friend I stayed with was the director of the Charlotte office for an HVAC company. He shared that, years ago as a technician, he would often show up to work early and sit in his truck reading technical manuals before starting the next job. He credited this practice with a lot of his success and advancement in the company.</p><p>That story stuck with me. So I have incorporated some version of this practice into my professional life.</p><p>So how does this look for me? Well, first I&#8217;ll describe the <em>ideal</em> version of how this works, the one I strive for, then I&#8217;ll share the <em>actual</em> version of how it plays out.</p><p>In the ideal version, I show up to work an hour early. That&#8217;s every workday. Five days a week. And I use this hour for learning. That could be reading a book, working on a technical course, listening to lectures, reading articles, or working on a project meant to practice a skill.</p><p>In the <em>actual</em> version, I occasionally do everything just described. More often, I maybe get there thirty minutes or fifteen minutes before work. Sometimes I&#8217;ll just study at home for a bit before heading to work. Sometimes, I have no time at the start of the day, so I might end the day with a little learning time. And sometimes&#8230; not at all. </p><p>Admittedly, I&#8217;m inconsistent.</p><p>But, I do this more often than I don&#8217;t do it.</p><p>James Clear, the author of <a href="https://amzn.to/3DdN5mt">Atomic Habits</a>, observed that &#8220;You do not rise to the level of your goals. You fall to the level of your systems.&#8221;<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a></p><p>This practice is my attempt at <em>systematizing</em> learning and growth into a habit. Something I can fall back on and <em>just do</em>, without thinking too much.</p><p>There is so much to learn. Everything keeps changing. Especially in any technology-related field. Which is virtually all of them at this point. Keeping up is just table stakes.</p><p>I&#8217;ve found that this technique, even when practiced imperfectly, has helped me adapt to the ever-changing landscape of my field. I offer it as a suggestion and hope it&#8217;s helpful.</p><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>https://jamesclear.com/3-2-1/january-2-2020 </p></div></div>]]></content:encoded></item><item><title><![CDATA[How to Get a Great Return on Time Invested in Learning]]></title><description><![CDATA[Focus on the Fundamentals]]></description><link>https://www.biodigitaljazz.tech/p/how-to-get-a-great-return-on-time</link><guid isPermaLink="false">https://www.biodigitaljazz.tech/p/how-to-get-a-great-return-on-time</guid><dc:creator><![CDATA[Tim Reynolds]]></dc:creator><pubDate>Tue, 01 Mar 2022 16:05:36 GMT</pubDate><enclosure url="https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/43f6156d-3d41-4c84-afb3-d279cd5c7736_420x300.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>A couple of weeks ago, I was helping a junior software engineer with a project. It required updating some legacy Ruby on Rails code that was making an API request. The code we needed to get to was buried under several layers of abstraction. </p><p>So while the ask was pretty straightforward&#8230; actually doing it was a different matter.</p><p>He got to a point where he was spinning his wheels. So I jumped in to help out. I looked at it for a little while and I was able to figure out what was going on.</p><p>He described me as a "wizard.&#8221; I had just done the impossible. </p><p>At least, in his view.</p><p></p><p></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!2Prd!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F9eea9a19-71f2-4eff-9680-006124334c98_420x300.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!2Prd!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F9eea9a19-71f2-4eff-9680-006124334c98_420x300.jpeg 424w, https://substackcdn.com/image/fetch/$s_!2Prd!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F9eea9a19-71f2-4eff-9680-006124334c98_420x300.jpeg 848w, https://substackcdn.com/image/fetch/$s_!2Prd!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F9eea9a19-71f2-4eff-9680-006124334c98_420x300.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!2Prd!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F9eea9a19-71f2-4eff-9680-006124334c98_420x300.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!2Prd!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F9eea9a19-71f2-4eff-9680-006124334c98_420x300.jpeg" width="570" height="407.14285714285717" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/9eea9a19-71f2-4eff-9680-006124334c98_420x300.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:300,&quot;width&quot;:420,&quot;resizeWidth&quot;:570,&quot;bytes&quot;:55007,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!2Prd!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F9eea9a19-71f2-4eff-9680-006124334c98_420x300.jpeg 424w, https://substackcdn.com/image/fetch/$s_!2Prd!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F9eea9a19-71f2-4eff-9680-006124334c98_420x300.jpeg 848w, https://substackcdn.com/image/fetch/$s_!2Prd!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F9eea9a19-71f2-4eff-9680-006124334c98_420x300.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!2Prd!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F9eea9a19-71f2-4eff-9680-006124334c98_420x300.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">To be clear, NOT a wizard.</figcaption></figure></div><p>Of course, I didn&#8217;t feel like a wizard. I was just following instinct&#8230; following one piece of code to the next through the inheritance hierarchy. With that and a little help from Google for Ruby minutiae, I was able to trace through the program down to the relevant piece that needed updating.</p><p>This experience did get me thinking though&#8230; <em>why was I</em> <em>able</em> to go into an unfamiliar codebase, in a language and framework that I am by-no-means an expert on, and, in a relatively short amount of time, figure out what was going on?</p><p>I can trace back my thought process back to the Computer Science 2 course I took in the Spring of 2012. Object-Oriented Programming in Java.</p><p>In that class, I learned many of the <em>fundamentals</em> of OOP. Abstraction, encapsulation, inheritance, polymorphism. I learned how to apply those concepts with interfaces, abstract classes, generics, and more techniques.</p><p>All these years later, I&#8217;m still applying those lessons in completely different languages and environments.</p><blockquote><p>When I was young, I had to learn the fundamentals of basketball. You can have all the physical ability in the world, but you still have to know the fundamentals.<br><br>- Michael Jordan</p></blockquote><p>Over the years of my career, I&#8217;ve seen those concepts play out across several different languages. And I&#8217;ve seen them expressed in several different design patterns, frameworks, and software architectures. So with that experience, I have further refined my understanding of these fundamental principles.</p><p>I&#8217;ve seen good examples.</p><p>I&#8217;ve seen a lot of not-so-good examples.</p><p>I&#8217;ve learned from all.</p><p>My observation at this point in my career is that I have gotten far more mileage out of learning and practicing the fundamentals of my craft than I have ever gotten out of focusing on <em>the new shiny</em> <em>thing</em>. Or even deeply focusing on a particular language or technology.</p><p>Now don&#8217;t get me wrong, there are seasons when you do need to keep up with the latest and greatest. Things do change. You need to know what&#8217;s possible.</p><p>And if you&#8217;re career is in a specific area&#8230; AWS engineering, just as an example, It&#8217;s necessary to know all the ins and outs of that particular technology. To dive deep.</p><p>My point is that in any craft or field of endeavor, there are a common set of principles that everything else is built on. The fundamentals.</p><p>Not taking the time to learn these fundamentals will hold you back.</p><p>Taking the time to learn, practice, and master the fundamentals will unlock an ability to adapt to new and unfamiliar situations. You&#8217;ll start to see how they apply across a wide variety of contexts.</p><p>You&#8217;ll see patterns emerge where there was once chaos.</p><p>Then, all of a sudden, things will make sense.</p><p>What constitutes the fundamentals for your field or specialty may vary. Here&#8217;s my attempt at listing what <em>I think</em> are a few good topics to start with as a software engineer:</p><ul><li><p>Data Structures and Algorithms</p><ul><li><p>The basics are not as scary as you might think. Realize, an <em>array is a data structure</em>. Algorithms are often just the techniques by which we can Create, Read, Update and Delete (CRUD) the data within those structures. Almost everything else is built on top of this.</p></li></ul></li><li><p>Object-Oriented Programming</p><ul><li><p>Can you describe the difference between an object and a class?</p><ul><li><p>I&#8217;ve conducted dozens of interviews, and a good number of candidates struggle with this.</p></li></ul></li><li><p>The Four Pillars of OOP: Abstraction, Encapsulation, Inheritance, Polymorphism.</p></li><li><p>The difference between Composition and Inheritance.</p></li></ul></li><li><p>Web Programming</p><ul><li><p>It&#8217;s helpful to understand some basics of how the internet actually works.</p><ul><li><p>Computer Networking</p></li><li><p>HTTP/HTTPS</p></li></ul></li><li><p>JavaScript/HTML/CSS</p></li><li><p>Server-Side Programming</p><ul><li><p>How is data exchanged between client and server?</p></li><li><p>HTTP methods</p></li><li><p>CRUD</p></li><li><p>APIs, REST</p></li></ul></li></ul></li><li><p>Databases</p><ul><li><p>Can you create a few tables, relate them, and use SQL to query from them or modify them?</p></li></ul></li></ul><p>If you need resources to help you get started, here are a few I recommend:</p><ul><li><p><a href="https://amzn.to/3hpHZsY">Cracking the Coding Interview</a></p><ul><li><p>While this book is mainly about interviewing, I find a lot of value in its overview of so many topics from computer science and software engineering. If you don&#8217;t know where to start, start here.</p></li></ul></li><li><p><a href="https://frontendmasters.com/">Frontend Masters</a></p><ul><li><p>Pay for a month and spend some time on the beginner learning track.</p></li></ul></li><li><p><a href="https://www.udacity.com/course/networking-for-web-developers--ud256">Networking for Web Developers</a></p><ul><li><p>Just spending a couple of weeks on this free course will help you have better conversations with systems and network engineers.</p></li></ul></li></ul><p>You might disagree with some items I&#8217;ve listed. Or, you may think I failed to list some critical items. I&#8217;m fine with that! Please feel free to add items in the comments.</p><p>Mastering the fundamentals is <em>far</em> from wasted time.</p><p>So if you&#8217;re in a season where you&#8217;re wondering, how can I grow? What&#8217;s holding me back from reaching the next level? Consider going back to basics.</p><p>Revisit the fundamentals.</p><p>It will pay off BIG TIME.</p><p></p><p></p>]]></content:encoded></item><item><title><![CDATA[Technical Feasibility]]></title><description><![CDATA[... what do I actually do here?]]></description><link>https://www.biodigitaljazz.tech/p/technical-feasibility</link><guid isPermaLink="false">https://www.biodigitaljazz.tech/p/technical-feasibility</guid><dc:creator><![CDATA[Tim Reynolds]]></dc:creator><pubDate>Sun, 23 Jan 2022 23:13:44 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!R7An!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe373beb-6244-4ef9-8b14-4b6c74ef1d6b_728x409.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!R7An!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe373beb-6244-4ef9-8b14-4b6c74ef1d6b_728x409.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!R7An!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe373beb-6244-4ef9-8b14-4b6c74ef1d6b_728x409.jpeg 424w, https://substackcdn.com/image/fetch/$s_!R7An!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe373beb-6244-4ef9-8b14-4b6c74ef1d6b_728x409.jpeg 848w, https://substackcdn.com/image/fetch/$s_!R7An!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe373beb-6244-4ef9-8b14-4b6c74ef1d6b_728x409.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!R7An!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe373beb-6244-4ef9-8b14-4b6c74ef1d6b_728x409.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!R7An!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe373beb-6244-4ef9-8b14-4b6c74ef1d6b_728x409.jpeg" width="728" height="409" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/be373beb-6244-4ef9-8b14-4b6c74ef1d6b_728x409.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:409,&quot;width&quot;:728,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:219865,&quot;alt&quot;:&quot;What would you say you actually do here? - Office Space.&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="What would you say you actually do here? - Office Space." title="What would you say you actually do here? - Office Space." srcset="https://substackcdn.com/image/fetch/$s_!R7An!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe373beb-6244-4ef9-8b14-4b6c74ef1d6b_728x409.jpeg 424w, https://substackcdn.com/image/fetch/$s_!R7An!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe373beb-6244-4ef9-8b14-4b6c74ef1d6b_728x409.jpeg 848w, https://substackcdn.com/image/fetch/$s_!R7An!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe373beb-6244-4ef9-8b14-4b6c74ef1d6b_728x409.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!R7An!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe373beb-6244-4ef9-8b14-4b6c74ef1d6b_728x409.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><p>Since becoming a tech lead, I&#8217;ve been trying to figure out how to do my job. What <em>do</em> I do here?</p><p>This blog is a product of that effort. To codify and share the results of that learning process.</p><p>So with that, I want to discuss the central theme that I have come to orient my work towards as a tech lead. That theme is <em>feasibility</em>.</p><h3>Why Feasibility?</h3><p>Why do I orient towards feasibility?</p><p>I feel it&#8217;s a natural outgrowth of the organizational design of my company. We borrow a lot of ideas from Marty Cagan and Silicon Valley Product Group. So at the lowest level in the product organization of my company, we are organized as cross-functional product squads.</p><p>The squad I work on is composed of a product manager, product designer, myself (tech lead), software developers, and a test engineer. The product manager, designer, and tech lead, together form a product trio.<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a> In the product trio model, the whole team is responsible for a successful product outcome, while each discipline approaches the outcome from their respective domain. The perspective of their discipline.</p><p>The product manager is primarily concerned with <em>value</em> and <em>viability</em>, whether or not the product meets the needs of the business and customer.</p><p>The designer is primarily concerned with <em>usability</em>. Can the intended user figure out how to use the product?</p><p>The tech lead is primarily concerned with <em>feasibility</em>. Can the solution be built?</p><h3>What is Feasibility?</h3><p>So what do we mean when we talk about technical feasibility?</p><p>Oxford defines feasibility as &#8220;the quality of being possible and likely to be achieved.&#8221;</p><p>Seems straightforward. From that definition, it seems as though I could answer the question to most projects I&#8217;m involved in with a yes or no answer pretty quickly, just based on my gut.</p><p>However, there&#8217;s a little more to it than that. Much is implied in this definition. What makes something <em>possible</em>? How do I know what&#8217;s possible and what&#8217;s not? What are the constraints that make something <em>likely to be achieved</em>? What are the hidden constraints that haven&#8217;t been considered?</p><p>Marty Cagan puts it this way, feasibility is about whether engineering can &#8220;&#8230;build what we need with the <em>time</em>, <em>skills</em> and <em>technology</em> we have [emphasis added].&#8221;<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-2" href="#footnote-2" target="_self">2</a></p><p>Time. </p><p>Skills. </p><p>Technology. </p><p>Those are the elements that I focus on.</p><p>I&#8217;ll attempt to address each of these elements in turn. In reality, though, they are entangled together and must be approached holistically. When you choose to optimize for one element, you may be doing so at the expense of another.</p><h4>Time</h4><p>Judging from experience, I think a pretty common misconception is that feasibility is the same as an estimation of when the project will be done. Often a stakeholder might ask what the feasibility of a given feature or project is. But what they are really asking is &#8220;Hey, how long will this thing take?&#8221;</p><p>Feasibility and timeline estimation are not the same. Feasibility may incorporate some element of estimation, especially as a factor when comparing options and deciding a direction. However, they are two very different disciplines.</p><p>At my current company, we operate according to the Kanban methodology.<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-3" href="#footnote-3" target="_self">3</a> As my friend and Kanban Coach, <a href="https://tristanhood.substack.com/">Tristan Hood</a> has put it, &#8220;Kanban seeks to remove the idea of &#8216;committing to estimated deadlines&#8217; so estimates become less important for setting a deadline and more important for driving collaboration and building just the right amount of thing in the right amount of time.&#8221;</p><p>So while the timeframe isn&#8217;t without importance, it is secondary to providing value. If the thing you&#8217;re working on is indeed the next right thing, It should be focused on until completion.</p><p>There are times when you have some work that has a fixed delivery date. In this case, the goal of the feasibility analysis is to come up with a plan to hit a target.<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-4" href="#footnote-4" target="_self">4</a> However, it&#8217;s more useful to design the work in such a matter that it promotes iteratively discovering and delivering products that provide value, rather than defaulting to fixed-date project commitments.</p><p>So for feasibility analysis, my main concern with the time element is determining what the <em>relative size</em> of our implementation options are. Option A might take longer than option B, but it accounts for X, Y, and Z concerns. Option C might be faster than all the other options. However, option C comes with such and such trade-offs to consider. Understanding this informs our decision as a team about which avenue of implementation to venture down.</p><p>As we further decompose the work, we may be able to perform some projections. The projections aren&#8217;t meant to imply fixed-date commitments, but to inform decision-making along the way.</p><p>There&#8217;s a lot that can be written on estimation. And has been! I plan to distill what I&#8217;ve learned about software estimation into a future post.</p><h4>Skills</h4><p>Skill is just the ability to do something. There are several dimensions to consider when determining if your team has the skills to practically execute a project.</p><p>Probably the first obvious dimension is <em>technical skill</em>. Does your team have any experience with the tech stack of the project? If the project calls for building an API in Java, and the team members have been working in the .NET stack for the past five years, you&#8217;ll have a learning curve that must be factored in.</p><p>And I say <em>the team</em> on purpose. To use the previous example, it may be that one of the team members did tons of Java API development at their last job. But if the other team members haven&#8217;t, <em>that</em> team member is going to be spending a lot of time training and communicating rather than coding.</p><p>Aside from specific technology, there is the craft side of software engineering. Think algorithms, design patterns, data modeling, architecture, requirements analysis. All of the skills that transcend languages and frameworks.</p><p>The greater the difference is between the team&#8217;s technical expertise and the expertise demanded by the project, the more this becomes a limiting factor.</p><p>A closely related dimension to technical skill is <em>experience</em>. Do you have a team of junior developers? A team of more seasoned veterans? Or a mixture? The more robust that the solution for the project is required to be across any given set of quality characteristics<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-5" href="#footnote-5" target="_self">5</a>, the more need there is for seasoned engineers to be involved in the design and guide implementation.</p><p>A third dimension is <em>domain knowledge</em>. How familiar is the team with the business side of what they are attempting to implement? Do they understand the user&#8217;s pain? If you&#8217;re tasked with implementing an accounting system, it helps to know the jargon that accountants use. The members of the team have to be able to take the concepts from the domain, abstract them into a model, and then translate that model into instructions that a computer can understand. The more understanding and context that the team has of the <em>application</em> of the system they&#8217;re building, the more accurate their implementation will be.</p><p>Another dimension to consider too is the team&#8217;s experience <em>together</em>. Has the team worked together long enough that they have had time to gel, to get to the point where each member could almost finish each other&#8217;s sentences? How&#8217;s the sense of <em>trust</em> on the team? The practice of building <em>durable</em> teams has gained popularity in recent years because there are so many advantages of having a team that has a shared history and experience.</p><p>There does come a point where the team and the project just aren&#8217;t compatible due to a mismatch between the skill-set of the team and the project&#8217;s requirements. In this case, you might:</p><ul><li><p>Scrap the project. Possibly reevaluate later.</p></li><li><p>Request work or assistance from another team that is capable.</p></li><li><p>Reevaluate and see if there&#8217;s another solution to the problem you&#8217;re addressing that <em>is</em> practical for the team.</p></li></ul><h4>Technology</h4><p>When it comes to handling the Technology aspect of feasibility, I view it as answering a series of questions&#8230;</p><p>Within our existing technology stack, do we have something already that can solve this problem?</p><p>If we do have something that kinda&#8217; fits the problem, but not quite, what is involved in modifying or extending that system to meet the problem? How difficult would this be?</p><p>Do we need to build something entirely new?</p><p>Can we buy a solution?</p><p>If we can buy something that meets a portion of the need, can we build the other portion to make up the difference?</p><p>Whether we build or buy, how does that integrate with the existing system?</p><p>Is working on that integration going to be harder than just modifying the existing system(s)?</p><p>That&#8217;s just a handful of examples I can think of. Answering these questions takes at least a couple of skills. You have to be able to apply some principles of software design and architecture. And you have to take an investigative approach.</p><p>Applying software design and architecture involves being able to map a customer or business problem to a possible software solution. And then use knowledge of various methods of software construction to work out a possible design for that solution. Or better yet, several alternative design options.</p><p>This is informed by a few things. An understanding of your current system. An understanding of the technology ecosystem that you work in; for example, what similar projects are available in your company to draw examples from? What services or APIs are available? It&#8217;s informed by experience; what have you built in the past? And Informed by education; what techniques and design patterns have you formally studied? What&#8217;s the latest innovation you&#8217;ve read about on TechCrunch or some other outlet?</p><p>I say &#8220;investigative approach&#8221; because I often feel like a criminal investigator from a TV show. I&#8217;m always gathering bits of information here and there. Especially with legacy systems; they&#8217;re almost always poorly documented. So you have the evidence of a design, the code is there. But the story of how it got there, how it works, and how you have to work with it to do the thing that you want to do with it&#8230; all of that may be a complete mystery. One that you have to solve.</p><p>I might be compiling notes from Google searches about the latest technology. I might be scouring through source code, maybe even downloading and running an application with a debugger. I might be walking up to someone&#8217;s desk and asking them questions. The point is I&#8217;m constantly compiling data from disparate sources and attempting to synthesize that into information that can help myself and my team understand what&#8217;s possible technically.</p><h4>How do I &#8220;do Feasibility?&#8221;</h4><p>So we know a bit about what feasibility is&#8230; how do we go about determining whether a project is feasible or not?</p><p>At the beginning of the project, I will direct my activities towards drafting a feasibility analysis report. This gives me a document where I can record answers to questions like the ones in the previous sections, and share the outcome of my research with the team and any stakeholders.</p><p>I treat it as a living document. It will continuously be updated and amended throughout the project as more is learned and decisions are made and changed.</p><p>The document isn&#8217;t just built by myself, of course. I&#8217;ll go over it with fellow engineers, my product manager, designer, stakeholders&#8230; anyone with information or vested interest. Their input helps further refine the document. It&#8217;s very much a collaborative effort.</p><p>I have yet to find a generic template that works for me. I&#8217;m open to suggestions, so if you have one, feel free to leave a comment! I&#8217;ve been developing different versions of a template as I&#8217;ve been doing this kind of work more formally.</p><p>What ends up in the feasibility report is usually some variation of the following</p><ol><li><p>An overview of the <em>options</em>.</p></li><li><p>Potential <em>trade-offs</em> between the options. Pros/Cons.</p></li><li><p>A <em>recommendation</em> of which option.</p></li><li><p>Some additional <em>context</em> and background.</p></li></ol><p>I&#8217;ll also put links to supporting documents as well. These might be architectural diagrams, architectural decisions records, conversations logs; anything that might be relevant.</p><p>I consider myself to be done with the first draft once the document answers enough questions about the implementation of a solution to a problem so that the development team has a solid basis of information upon which to begin implementation.</p><p>Now aside from feasibility analysis, there are other important aspects to my role as well. I view the tech lead role as a mixture of project management, software architecture, technical advocacy, and being a player/coach. Yes, even still coding. I plan to write more posts that are specific to those functions in the future.</p><p>So that&#8217;s a snapshot of where I&#8217;m at in this journey. I hope for anyone in a similar position that sharing this sparks some ideas and maybe even helps you to move from clarity to ambiguity, wherever you are on your path.</p><p></p><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>Torres, Teresa, &#8220;Core Concept: The Product Trio,&#8221; <em>Product Talk</em>, May 05, 2021. <a href="https://www.producttalk.org/2021/05/product-trio/">https://www.producttalk.org/2021/05/product-trio/</a> (accessed Dec.&nbsp;27, 2021).</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-2" href="#footnote-anchor-2" class="footnote-number" contenteditable="false" target="_self">2</a><div class="footnote-content"><p>M. Cagan, &#8220;The Four Big Risks,&#8221; <em>Silicon Valley Product Group</em>, Dec.&nbsp;04, 2017. <a href="https://svpg.com/four-big-risks/">https://svpg.com/four-big-risks/</a> (accessed Jan.&nbsp;16, 2022).</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-3" href="#footnote-anchor-3" class="footnote-number" contenteditable="false" target="_self">3</a><div class="footnote-content"><p>&#8220;The Kanban Method: The Ultimate Beginner&#8217;s Guide! | Nave,&#8221; Nave Blog - Expert tips and guidelines for Kanban teams, Mar.&nbsp;02, 2018. https://getnave.com/blog/what-is-the-kanban-method/ (accessed Jan.&nbsp;17, 2022).</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-4" href="#footnote-anchor-4" class="footnote-number" contenteditable="false" target="_self">4</a><div class="footnote-content"><p>S. McConnell, Software estimation: demystifying the black art. Redmond, Wash: Microsoft Press, 2006 ch.&nbsp;1, pp.&nbsp;5.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-5" href="#footnote-anchor-5" class="footnote-number" contenteditable="false" target="_self">5</a><div class="footnote-content"><p>&#8220;ISO 25010.&#8221; [https://iso25000.com/index.php/en/iso-25000-standards/iso-25010](https://iso25000.com/index.php/en/iso-25000-standards/iso-25010) (accessed Jan. 19, 2022).</p><p></p></div></div>]]></content:encoded></item><item><title><![CDATA[On Software Design Sessions...]]></title><description><![CDATA[How to improve shared context and software craftsmanship]]></description><link>https://www.biodigitaljazz.tech/p/on-software-design-sessions</link><guid isPermaLink="false">https://www.biodigitaljazz.tech/p/on-software-design-sessions</guid><dc:creator><![CDATA[Tim Reynolds]]></dc:creator><pubDate>Sun, 12 Dec 2021 22:56:48 GMT</pubDate><content:encoded><![CDATA[<p>Periodically, our squad engages in what we call &#8220;Nitro Days.&#8221; These are days where we book a conference room and work together, away from our desks. The purpose of these days is to encourage a singular focus on a shared problem, free of the normal distractions of other meetings and drop-ins. If you&#8217;ve ever played the Need for Speed games and hit the NOS, think of that. It helps us get an extra boost on our work.</p><p>In one of these sessions a few months back, we were working out how to build an API authentication flow. I had the thought, &#8220;this would be a great use-case for a <a href="https://www.lucidchart.com/pages/uml-sequence-diagram">UML sequence diagram</a>.&#8221; I shared that with the team, so we got to diagramming the whole process out. We went further, diagramming a flowchart for the module logic.</p><p>So what were the results? Within thirty minutes after the discussion, we had a working solution coded and code-reviewed. And just as valuable, <em>every</em> engineer on the squad understood the problem; they understood the solution. Even though it was <em>one</em> person on the team that directly coded.</p><p>What I realized later was that we stumbled into conducting a <em>software design session</em>. With this post, I want to advocate the benefit of a pause before coding, just to take a little time to work out solutions with your team.</p><p>To begin, I want to contrast this method of working with what in my experience is often the default. The default pattern usually goes something like this:</p><ol><li><p>The developer is assigned a ticket</p></li><li><p>Developer reads ticket.</p></li><li><p>The developer immediately starts coding in isolation.</p></li><li><p>If code reviews are required (and they should be), the developer submits a pr</p></li><li><p>The developer gets feedback and may refactor the solution if needed.</p></li></ol><p>Do you see the problem with this? It&#8217;s not until the code review <em>after </em>code is worked on, that peer review and solution discussion occurs. If more of this can be front-loaded <em>before </em>fingers have touched keys. context is much more effectively shared, multiple voices speak into solutions, coding itself goes faster, and code review is more friction-less since the reviewer is working from the same context.</p><p>Since that nitro day, we&#8217;ve practiced this in various forms and formats. Here are a few benefits that I&#8217;ve observed over time doing this:</p><ol><li><p>Shared context.</p></li><li><p>Teaching and learning opportunities for craftsmanship. </p></li><li><p>Improved software craftsmanship across the team.</p></li><li><p>Highlights assumptions and potential risks.</p></li><li><p>Gives the team a jump-start on documentation.</p></li><li><p>It&#8217;s fun.</p></li></ol><p>Let&#8217;s examine each of these a bit...</p><p><strong>1. Shared Context</strong></p><p>I&#8217;ve already spoken on this up to this point. To me, the biggest advantage of this practice is that it is natural. A big problem that can easily occur is siloing of information. How often is it that <em>one </em>engineer on the team understands a particular system or process, they go on vacation, leave, or are otherwise unavailable? As soon as that happens, the rest of the team is left scrambling to figure out how the hell the damn thing works when they inevitably must work on said system. Engaging in design sessions regularly can help interrupt that siloing effect.</p><p><strong>2. Opportunity for Teaching and Learning</strong></p><p>In the first session, I had just learned about sequence diagrams from a course I had been taking. This provided me with an outlet and opportunity to share that knowledge with the team. This makes that training way more valuable, because it&#8217;s not just myself that is benefiting from it, it&#8217;s the rest of the team.</p><p>In a more recent meeting, we learned about the Factory Pattern and applied that to a problem solution. Not just one person. The whole team.</p><p>In these sessions, it&#8217;s often that someone has a unique take or perspective on the problem and how to solve it. This provides a natural opportunity for them to share this perspective and perhaps teach a new software engineering technique. This is so much more powerful because it is in the context of a problem we are working on, rather than a dry textbook example.</p><p><strong>3. Improved Software Craftsmanship</strong></p><p>This is similar to the last point but restated from a different angle. Because a natural opportunity is presented to teach and share, the level of craftsmanship rises not just with the individual developers on the team, but with everyone. Everyone starts speaking in the same language. Junior developers and more senior developers are speaking in terms of design patterns and behavior modeling techniques.</p><p><strong>4. Highlights Assumptions and Potential Risks</strong></p><p>Often, a problem may seem simple on the surface. For example, a requirement may be that your code must send an email based on some user action. People send emails all the time, this shouldn&#8217;t be difficult.</p><p>With a design session, questions can start being asked... Who designs and develops the email template? What system is it that sends the email? Are there any external dependencies? What are the various options available?</p><p>Then with the answers to these questions, your team can graphically map out on paper what the dependencies are and where they introduce risk to the project. Unknown assumptions are brought to light through this process.</p><p><strong>5. Jump-start on documentation</strong></p><p>After that initial white-boarding session, we took it a bit further and formalized our sequence diagram in Lucidchart. This gave us a design artifact that we could store with the code and use to document and discuss the solution later.</p><p>Documentation is often an afterthought when writing software. When diagramming and communicating about solutions before building, the team is already primed into a documentation-oriented mindset. And it is much easier to go back to the already existing designs after the project, edit and archive them than it is to have a completely separate body of documentation work.</p><p>Now, if a UML expert were to come by and examine our charts, they&#8217;d probably find all sorts of problems. Being perfect at UML wasn&#8217;t the point. The point was to grapple with the problem outside of our heads in a shared space so that the team could engage in the same mental model with a shared context.</p><p><strong>6. It&#8217;s Fun</strong></p><p>Finally, It&#8217;s just fun. I think of software design discussions as riffing sessions.</p><p>In the same way that jazz musicians would come together and instantaneously create music, developers are coming together, improvising designs and discussing ideas on a whiteboard. Like a set of skilled musicians, we are drawing from our own shared set of language and experience to make something new in real-time. The software and the documentation then become the recording of a great jam session.</p><p><strong>What&#8217;s Next...</strong></p><p>One problem I&#8217;m still wrestling with solving: How can we work this way as a squad without the need for a meeting? Meetings aren&#8217;t entirely evil, but they can be inefficient. My ideal vision is that instead of having to book a meeting, this method becomes the normal way we work. Whenever we start working on a problem, instead of immediately coding, we spin around, start marking up a whiteboard and start a discussion.</p>]]></content:encoded></item><item><title><![CDATA[How to Influence Attitudes on your Team for Better Results]]></title><description><![CDATA[Over the past few months, a situation developed on my team.]]></description><link>https://www.biodigitaljazz.tech/p/how-to-influence-attitudes-on-your</link><guid isPermaLink="false">https://www.biodigitaljazz.tech/p/how-to-influence-attitudes-on-your</guid><dc:creator><![CDATA[Tim Reynolds]]></dc:creator><pubDate>Sun, 14 Nov 2021 22:23:25 GMT</pubDate><content:encoded><![CDATA[<p>Over the past few months, a situation developed on my team. Work that was prioritized was being avoided in favor of more appealing work. There was a growing lack of results. There was constant complaining. And morale felt low. I knew as the tech lead on the team I had to figure out what was going on and how to address the problem. This is how I approached it&#8230;</p><p>I spent some time meditating on this and a few threads came together. Over the past year, we have been integrating with a larger business unit. With that integration came the inheritance of some legacy codebases. This code was largely written in Ruby on Rails. My squad had a negative attitude towards Ruby on Rails. We would rather build in virtually any other language or platform.</p><p>I have to admit, Ruby on Rails is not my favorite tool to work with. For most of the time since I started at my current company, I have avoided using or writing in it to the best of my ability. I would work on other projects or write mostly front-end code. I came from a background working in .NET shops, using C#, as well as JavaScript, and even had some experience writing Java. I had gotten to the point where I could figure out how most programs worked by just looking at them for a while, with minimal need for a dedicated study of the language. This was not the case when I started working with Ruby on Rails. Much of the programs are layers of &#8220;magic.&#8221; You&nbsp;<em>just have to know</em>&nbsp;to get it. For someone coming into a project with little background in the platform, this is frustrating. And working with the Rails platform felt like going back in time compared to my previous work with ASP MVC and the comparatively luxurious development environment that came with it.</p><p>As I thought through this, I realized something. This situation was&nbsp;<em>my</em>&nbsp;fault. I took a note from Jocko Willink<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a> and decided to embrace extreme ownership. For over two years, I had allowed my negative attitude towards this tool to take hold and voiced it throughout many of my exchanges. I didn&#8217;t properly respect and appreciate the influence that my voice had; especially with more junior developers. And now that I was in the role of tech lead on my squad, this was even more important. I felt a responsibility to do what I could to turn the ship.</p><p>So how did I do this? I knew I had to have a heart-to-heart conversation with my developers. So I called a short meeting together with them. I started by walking them through my history of thinking which I shared above. I then admitted that while my opinions on the technology haven&#8217;t changed, my attitude towards it had affected our ability to work effectively. I said that I was sorry for allowing my attitude to affect the team and said that I was committed to improving it. I then appealed to them to join me in that effort. I reminded them, and myself, that the tool wasn&#8217;t as important as the mission and the work that was in front of us. That we can improve everything that has been handed to us if we only embraced ownership of it.</p><p>The team needed time to process the conversation, but overall it seemed to be well received. Within a couple of weeks, one of them even improved our workflow with our Rails repos by introducing dev containers. This stabilized our environment and eliminated a lot of headaches we were experiencing. We&#8217;ve also continued to add documentation to the project and practiced the boy-scout rule, making improvements as touched it. I&#8217;m very proud of my team for the progress we&#8217;ve made. Overall, the vibe is much much more positive. Work is more fun.</p><p>In hindsight one thing I could have done better is establish psychological safety at the beginning of the conversation. I launched into the talk immediately without simply establishing that no one was leaving and no one was getting fired. These two assumptions are the first places people naturally go when called into a meeting like this. The safety needed to have a difficult conversation well can be threatened without those kinds of fears allayed from the outset.</p><p>Looking back, I can see a progression of steps that allowed us to correct our attitudes and start getting the results we wanted. These are: </p><ol><li><p>Recognized there is a problem. </p></li><li><p>Meditate on the root cause. Be curious. Are there any common themes? </p></li><li><p>Recognize and admit your part in creating the problem. This is especially important as the leader. </p></li><li><p>Call the team together to address the issue directly. </p></li><li><p>Invite your team to join you in fixing the problem. </p></li><li><p>Follow up. Check-in with the team, and individually. Treat it as a continual discussion. </p></li><li><p>Recognize and celebrate progress.</p></li></ol><p>A couple of great resources that influenced how I approached this situation are the book&nbsp;<a href="https://www.amazon.com/Crucial-Conversations-Tools-Talking-Stakes/dp/1260474186/ref=sr_1_4?crid=3O5A7JT3Y8WHT&amp;dchild=1&amp;keywords=crucial+conversations+tools+for+talking+when+stakes+are+high&amp;qid=1635096647&amp;s=books&amp;sprefix=crucial%2Cstripbooks%2C173&amp;sr=1-4">Crucial Conversations</a>&nbsp;and&nbsp;<a href="https://www.youtube.com/watch?v=WhZzu2sqUUw">Brendan Wovchko&#8217;s framework</a>&nbsp;on handling difficult conversations.</p><h3></h3><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>J. Willink and L. Babin,&nbsp;<em>Extreme Ownership: How U.S. navy seals lead and win</em>. Macmillan, 2018.</p></div></div>]]></content:encoded></item><item><title><![CDATA[Leadership lessons in the technology field.]]></title><description><![CDATA[Welcome to Biodigital Jazz by me, Tim Reynolds.]]></description><link>https://www.biodigitaljazz.tech/p/coming-soon</link><guid isPermaLink="false">https://www.biodigitaljazz.tech/p/coming-soon</guid><dc:creator><![CDATA[Tim Reynolds]]></dc:creator><pubDate>Wed, 25 Aug 2021 03:02:44 GMT</pubDate><content:encoded><![CDATA[<p>Welcome to Biodigital Jazz by me, Tim Reynolds. I&#39;m a Senior Software Engineer in the Nashville metro area.\n\nMy newsletter is an open professional journal, allowing me to process and share thoughts on topics related to my experience as an engineer.</p><p>Sign up now so you don&#8217;t miss the first issue.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.biodigitaljazz.tech/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.biodigitaljazz.tech/subscribe?"><span>Subscribe now</span></a></p><p>In the meantime, <a href="https://www.biodigitaljazz.tech/p/coming-soon?utm_source=substack&utm_medium=email&utm_content=share&action=share">tell your friends</a>!</p>]]></content:encoded></item></channel></rss>